Functioning renderer

This commit is contained in:
2025-11-15 17:38:49 +01:00
parent 1c103a1496
commit 0cb7d4b64d
2 changed files with 83 additions and 77 deletions

View File

@@ -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

View File

@@ -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
} }