Functioning renderer
This commit is contained in:
@@ -242,7 +242,7 @@ MonoBehaviour:
|
|||||||
m_Script: {fileID: 11500000, guid: 0c03158bf19bc8c4ab178ebaee653914, type: 3}
|
m_Script: {fileID: 11500000, guid: 0c03158bf19bc8c4ab178ebaee653914, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier: Assembly-CSharp::Map
|
m_EditorClassIdentifier: Assembly-CSharp::Map
|
||||||
overpassUrl: https://mapz.hozuvkod.dev/api/interpreter
|
overpassUrl: https://mapz.honzuvkod.dev/api/interpreter
|
||||||
queryRadiusMeters: 200
|
queryRadiusMeters: 200
|
||||||
latitude: 50.772789001464844
|
latitude: 50.772789001464844
|
||||||
longitude: 15.076871871948242
|
longitude: 15.076871871948242
|
||||||
@@ -262,7 +262,7 @@ Transform:
|
|||||||
m_GameObject: {fileID: 1274200469}
|
m_GameObject: {fileID: 1274200469}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
m_LocalPosition: {x: 314.27454, y: 0, z: 616.551}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children: []
|
m_Children: []
|
||||||
@@ -293,7 +293,7 @@ MeshRenderer:
|
|||||||
m_RenderingLayerMask: 1
|
m_RenderingLayerMask: 1
|
||||||
m_RendererPriority: 0
|
m_RendererPriority: 0
|
||||||
m_Materials:
|
m_Materials:
|
||||||
- {fileID: 0}
|
- {fileID: 2100000, guid: 283cf727b4c3ac64c94d59598e221b10, type: 2}
|
||||||
m_StaticBatchInfo:
|
m_StaticBatchInfo:
|
||||||
firstSubMesh: 0
|
firstSubMesh: 0
|
||||||
subMeshCount: 0
|
subMeshCount: 0
|
||||||
|
|||||||
@@ -1,26 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
using UnityEngine.UIElements;
|
|
||||||
|
|
||||||
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
|
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
|
||||||
public class Map : MonoBehaviour, IMapDataCollector
|
public class MapRenderer : MonoBehaviour
|
||||||
{
|
{
|
||||||
[Header("Overpass settings")]
|
[Header("Overpass settings")]
|
||||||
public string overpassUrl = "https://mapz.honzuvkod.dev/api/interpreter";
|
public string overpassUrl = "https://mapz.honzuvkod.dev/api/interpreter";
|
||||||
public float queryRadiusMeters = 200f; // radius around lat/lon to query
|
public float queryRadiusMeters = 200f; // radius around lat/lon to query
|
||||||
|
|
||||||
[Header("Location (lat, lon)")]
|
[Header("Location (lat, lon)")]
|
||||||
public double latitude = 50.7727878f; // example Prague
|
public double latitude; // example Prague
|
||||||
public double longitude = 15.0768714f;
|
public double longitude;
|
||||||
|
|
||||||
[Header("Building settings")]
|
[Header("Building settings")]
|
||||||
public Material buildingMaterial;
|
public Material buildingMaterial;
|
||||||
@@ -34,21 +30,78 @@ public class Map : MonoBehaviour, IMapDataCollector
|
|||||||
[Header("Misc")]
|
[Header("Misc")]
|
||||||
public float metersPerUnit = 1f; // scale: 1 unit = 1 meter
|
public float metersPerUnit = 1f; // scale: 1 unit = 1 meter
|
||||||
public bool autoStart = true;
|
public bool autoStart = true;
|
||||||
class Way
|
|
||||||
{
|
|
||||||
public long id;
|
|
||||||
public List<long> nodeRefs = new List<long>();
|
|
||||||
public Dictionary<string, string> tags = new Dictionary<string, string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly HttpClient client = new HttpClient();
|
// Internal storage
|
||||||
|
|
||||||
List<Way> parsedWays = new List<Way>();
|
|
||||||
Dictionary<long, Vector2> nodes = new Dictionary<long, Vector2>(); // id -> latlon
|
Dictionary<long, Vector2> nodes = new Dictionary<long, Vector2>(); // id -> latlon
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
CallApi();
|
if (autoStart)
|
||||||
|
StartCoroutine(GenerateForLocation(latitude, longitude));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public entry for other scripts
|
||||||
|
public void StartGenerating(double lat, double lon)
|
||||||
|
{
|
||||||
|
latitude = lat; longitude = lon;
|
||||||
|
StartCoroutine(GenerateForLocation(lat, lon));
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator GenerateForLocation(double lat, double lon)
|
||||||
|
{
|
||||||
|
ClearChildren();
|
||||||
|
|
||||||
|
// compute bbox from radius
|
||||||
|
float degPerMeter = 1f / 111000f; // approximate
|
||||||
|
double delta = queryRadiusMeters * degPerMeter;
|
||||||
|
double south = lat - delta;
|
||||||
|
double north = lat + delta;
|
||||||
|
double west = lon - delta;
|
||||||
|
double east = lon + delta;
|
||||||
|
|
||||||
|
string q = $"[out:xml][timeout:25];(way[\"building\"]({south.ToString().Replace(",",".")},{west.ToString().Replace(",", ".")},{north.ToString().Replace(",", ".")},{east.ToString().Replace(",", ".")});way[\"highway\"]({south.ToString().Replace(",", ".")},{west.ToString().Replace(",", ".")},{north.ToString().Replace(",", ".")},{east.ToString().Replace(",", ".")}););(._;>;);out body;";
|
||||||
|
|
||||||
|
WWWForm form = new WWWForm();
|
||||||
|
form.AddField("data", q);
|
||||||
|
|
||||||
|
using (UnityWebRequest www = UnityWebRequest.Post(overpassUrl, form))
|
||||||
|
{
|
||||||
|
www.downloadHandler = new DownloadHandlerBuffer();
|
||||||
|
yield return www.SendWebRequest();
|
||||||
|
|
||||||
|
if (www.result != UnityWebRequest.Result.Success)
|
||||||
|
{
|
||||||
|
Debug.LogError("Overpass request failed: " + www.error);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string xml = www.downloadHandler.text;
|
||||||
|
ParseOverpassXml(xml);
|
||||||
|
|
||||||
|
// create separate GameObjects for buildings and roads
|
||||||
|
GameObject buildingsRoot = new GameObject("Buildings");
|
||||||
|
buildingsRoot.transform.parent = this.transform;
|
||||||
|
|
||||||
|
GameObject roadsRoot = new GameObject("Roads");
|
||||||
|
roadsRoot.transform.parent = this.transform;
|
||||||
|
|
||||||
|
// iterate parsed ways
|
||||||
|
foreach (var w in parsedWays)
|
||||||
|
{
|
||||||
|
if (w.tags.ContainsKey("building"))
|
||||||
|
{
|
||||||
|
GameObject b = BuildBuildingMesh(w);
|
||||||
|
b.transform.parent = buildingsRoot.transform;
|
||||||
|
}
|
||||||
|
else if (w.tags.ContainsKey("highway"))
|
||||||
|
{
|
||||||
|
GameObject r = BuildRoadMesh(w);
|
||||||
|
r.transform.parent = roadsRoot.transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log("Map generation complete: " + parsedWays.Count + " ways, " + nodes.Count + " nodes.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearChildren()
|
void ClearChildren()
|
||||||
@@ -61,64 +114,16 @@ public class Map : MonoBehaviour, IMapDataCollector
|
|||||||
DestroyImmediate(g);
|
DestroyImmediate(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> CallOverpassApi(FormUrlEncodedContent query)
|
#region Overpass XML parsing
|
||||||
|
class Way
|
||||||
{
|
{
|
||||||
Debug.Log("Calling Overpass API...");
|
public long id;
|
||||||
|
public List<long> nodeRefs = new List<long>();
|
||||||
|
public Dictionary<string, string> tags = new Dictionary<string, string>();
|
||||||
var response = await client.PostAsync(overpassUrl, query);
|
|
||||||
Debug.Log("Received response from Overpass API.");
|
|
||||||
return await response.Content.ReadAsStringAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FormUrlEncodedContent QueryBuilder(double[] GPS)
|
List<Way> parsedWays = new List<Way>();
|
||||||
{
|
|
||||||
Debug.Log("Building Overpass API query...");
|
|
||||||
string query = @$"
|
|
||||||
[out:xml]
|
|
||||||
[timeout:90];
|
|
||||||
(
|
|
||||||
way(around:{queryRadiusMeters}, {GPS[0].ToString().Replace(",", ".")}, {GPS[1].ToString().Replace(",", ".")});
|
|
||||||
);
|
|
||||||
out geom;";
|
|
||||||
Dictionary<string, string> values = new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{"data", query}
|
|
||||||
};
|
|
||||||
Debug.Log("Overpass API query built.");
|
|
||||||
|
|
||||||
return new FormUrlEncodedContent(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void CallApi()
|
|
||||||
{
|
|
||||||
Debug.Log("Testing Overpass API...");
|
|
||||||
double[] GPS = new double[] {latitude, longitude};
|
|
||||||
string result = await CallOverpassApi(QueryBuilder(GPS));
|
|
||||||
Debug.Log("Overpass API response received:");
|
|
||||||
ParseOverpassXml(result);
|
|
||||||
|
|
||||||
GameObject buildingsRoot = new GameObject("Buildings");
|
|
||||||
buildingsRoot.transform.parent = this.transform;
|
|
||||||
GameObject roadsRoot = new GameObject("Roads");
|
|
||||||
roadsRoot.transform.parent = this.transform;
|
|
||||||
foreach (var w in parsedWays)
|
|
||||||
{
|
|
||||||
if (w.tags.ContainsKey("building"))
|
|
||||||
{
|
|
||||||
//Debug.Log("Building");
|
|
||||||
GameObject b = BuildBuildingMesh(w);
|
|
||||||
b.transform.parent = buildingsRoot.transform;
|
|
||||||
}
|
|
||||||
else if (w.tags.ContainsKey("highway"))
|
|
||||||
{
|
|
||||||
//Debug.Log("Highway");
|
|
||||||
GameObject r = BuildRoadMesh(w);
|
|
||||||
r.transform.parent = roadsRoot.transform;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
void ParseOverpassXml(string xmlText)
|
void ParseOverpassXml(string xmlText)
|
||||||
{
|
{
|
||||||
nodes.Clear();
|
nodes.Clear();
|
||||||
@@ -161,6 +166,8 @@ public class Map : MonoBehaviour, IMapDataCollector
|
|||||||
parsedWays.Add(w);
|
parsedWays.Add(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Utilities: latlon to local meters
|
#region Utilities: latlon to local meters
|
||||||
// Convert latitude/longitude to local XY meters relative to center point
|
// Convert latitude/longitude to local XY meters relative to center point
|
||||||
Vector3 LatLonToLocal(double lat, double lon)
|
Vector3 LatLonToLocal(double lat, double lon)
|
||||||
@@ -499,4 +506,3 @@ public class Map : MonoBehaviour, IMapDataCollector
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user