Hello.
Sorry for the long answer.
Creation of example takes time.
using System;
using System.Collections.Generic;
using UnityEngine;
public class GenerateRoadsExample:MonoBehaviour
{
public OnlineMapsRange zoomRange = new OnlineMapsRange(19, 20);
private OnlineMaps map;
private OnlineMapsTileSetControl control;
private OnlineMapsVector2i topLeft;
private OnlineMapsVector2i bottomRight;
private float lastRequestTime;
private float requestRate = 0.1f;
private string requestData;
private OnlineMapsOSMAPIQuery osmRequest;
private Mesh roadsMesh;
private Dictionary<string, OnlineMapsOSMNode> nodes;
private List<OnlineMapsOSMWay> ways;
private void DrawRoad(OnlineMapsOSMWay way, List<OnlineMapsOSMNode> usedNodes, List<Vector3> vertices, List<Vector3> normals, List<Vector2> uv, List<int> triangles, float width, double tlx, double tly, double brx, double bry, float bestElevationYScale)
{
way.GetNodes(nodes, usedNodes);
List<Vector3> points = GetLocalPoints(usedNodes);
if (points.Count < 2) return;
float w2 = width * 2;
Vector3 prevS1 = Vector3.zero;
Vector3 prevS2 = Vector3.zero;
for (int i = 0; i < points.Count; i++)
{
float px = points[i].x;
float pz = points[i].z;
Vector3 s1 = Vector3.zero;
Vector3 s2 = Vector3.zero;
if (i == 0 || i == points.Count - 1)
{
float p1x, p1z, p2x, p2z;
if (i == 0)
{
p1x = px;
p1z = pz;
Vector3 np = points[i + 1];
p2x = np.x;
p2z = np.z;
}
else
{
Vector3 pp = points[i - 1];
p1x = pp.x;
p1z = pp.z;
p2x = px;
p2z = pz;
}
float a = OnlineMapsUtils.Angle2DRad(p1x, p1z, p2x, p2z, 90);
float offX = Mathf.Cos(a) * width;
float offZ = Mathf.Sin(a) * width;
float s1x = px + offX;
float s1z = pz + offZ;
float s2x = px - offX;
float s2z = pz - offZ;
float s1y = control.GetElevationValue(s1x, s1z, bestElevationYScale, tlx, tly, brx, bry);
float s2y = control.GetElevationValue(s2x, s2z, bestElevationYScale, tlx, tly, brx, bry);
s1 = new Vector3(s1x, s1y, s1z);
s2 = new Vector3(s2x, s2y, s2z);
}
else
{
Vector3 pp = points[i - 1];
Vector3 np = points[i + 1];
float p1x = pp.x;
float p1z = pp.z;
float p2x = np.x;
float p2z = np.z;
float a1 = OnlineMapsUtils.Angle2DRad(p1x, p1z, px, pz, 90);
float a2 = OnlineMapsUtils.Angle2DRad(px, pz, p2x, p2z, 90);
float off1x = Mathf.Cos(a1) * width;
float off1z = Mathf.Sin(a1) * width;
float off2x = Mathf.Cos(a2) * width;
float off2z = Mathf.Sin(a2) * width;
float p21x = px + off1x;
float p21z = pz + off1z;
float p22x = px - off1x;
float p22z = pz - off1z;
float p31x = px + off2x;
float p31z = pz + off2z;
float p32x = px - off2x;
float p32z = pz - off2z;
float is1x, is1z, is2x, is2z;
int state1 = OnlineMapsUtils.GetIntersectionPointOfTwoLines(p1x + off1x, p1z + off1z, p21x, p21z, p31x, p31z, p2x + off2x, p2z + off2z, out is1x, out is1z);
int state2 = OnlineMapsUtils.GetIntersectionPointOfTwoLines(p1x - off1x, p1z - off1z, p22x, p22z, p32x, p32z, p2x - off2x, p2z - off2z, out is2x, out is2z);
if (state1 == 1 && state2 == 1)
{
float o1x = is1x - px;
float o1z = is1z - pz;
float o2x = is2x - px;
float o2z = is2z - pz;
float m1 = Mathf.Sqrt(o1x * o1x + o1z * o1z);
float m2 = Mathf.Sqrt(o2x * o2x + o2z * o2z);
if (m1 > w2)
{
is1x = o1x / m1 * w2 + px;
is1z = o1z / m1 * w2 + pz;
}
if (m2 > w2)
{
is2x = o2x / m2 * w2 + px;
is2z = o2z / m2 * w2 + pz;
}
s1 = new Vector3(is1x, control.GetElevationValue(is1x, is1z, bestElevationYScale, tlx, tly, brx, bry), is1z);
s2 = new Vector3(is2x, control.GetElevationValue(is2x, is2z, bestElevationYScale, tlx, tly, brx, bry), is2z);
}
else
{
float po1x = p1x + off1x;
float po1z = p1z + off1z;
float po2x = p2x - off1x;
float po2z = p2z - off1z;
s1 = new Vector3(po1x, control.GetElevationValue(po1x, po1z, bestElevationYScale, tlx, tly, brx, bry), po1z);
s2 = new Vector3(po2x, control.GetElevationValue(po2x, po2z, bestElevationYScale, tlx, tly, brx, bry), po2z);
}
}
if (i > 0)
{
int ti = vertices.Count;
vertices.Add(prevS1);
vertices.Add(s1);
vertices.Add(s2);
vertices.Add(prevS2);
normals.Add(Vector3.up);
normals.Add(Vector3.up);
normals.Add(Vector3.up);
normals.Add(Vector3.up);
uv.Add(new Vector2(0, 0));
uv.Add(new Vector2(0, 1));
uv.Add(new Vector2(1, 1));
uv.Add(new Vector2(1, 0));
triangles.Add(ti);
triangles.Add(ti + 1);
triangles.Add(ti + 2);
triangles.Add(ti);
triangles.Add(ti + 2);
triangles.Add(ti + 3);
}
prevS1 = s1;
prevS2 = s2;
}
}
protected List<Vector3> GetLocalPoints(List<OnlineMapsOSMNode> nodes)
{
double tlx, tly;
map.GetTopLeftPosition(out tlx, out tly);
double sx, sy;
map.projection.CoordinatesToTile(tlx, tly, map.buffer.apiZoom, out sx, out sy);
List<Vector3> localPoints = new List<Vector3>(nodes.Count);
float sw = OnlineMapsUtils.tileSize * map.tilesetSize.x / map.tilesetWidth;
float sh = OnlineMapsUtils.tileSize * map.tilesetSize.y / map.tilesetHeight;
for (int i = 0; i < nodes.Count; i++)
{
double px, py;
map.projection.CoordinatesToTile(nodes[i].lon, nodes[i].lat, map.buffer.apiZoom, out px, out py);
localPoints.Add(new Vector3((float)(-(px - sx) * sw), 0, (float)((py - sy) * sh)));
}
return localPoints;
}
private void OnRoadRequestComplete(string response)
{
osmRequest = null;
List<OnlineMapsOSMRelation> relations;
OnlineMapsOSMAPIQuery.ParseOSMResponse(response, out nodes, out ways, out relations);
}
private void PrepareRequest()
{
double tlx, tly, brx, bry;
map.projection.TileToCoordinates(topLeft.x, topLeft.y, map.zoom, out tlx, out tly);
map.projection.TileToCoordinates(bottomRight.x, bottomRight.y, map.zoom, out brx, out bry);
requestData = String.Format("node({0},{1},{2},{3});way(bn)['highway'];(._;>;);out;", bry, tlx, tly, brx);
}
private void SendRequest()
{
if (osmRequest != null || string.IsNullOrEmpty(requestData)) return;
osmRequest = OnlineMapsOSMAPIQuery.Find(requestData);
osmRequest.OnComplete += OnRoadRequestComplete;
lastRequestTime = Time.time;
requestData = null;
}
private void Start()
{
map = OnlineMaps.instance;
control = OnlineMapsTileSetControl.instance;
GameObject roadsGO = new GameObject("Roads");
MeshFilter meshFilter = roadsGO.AddComponent<MeshFilter>();
MeshRenderer meshRenderer = roadsGO.AddComponent<MeshRenderer>();
meshRenderer.material = new Material(Shader.Find("Transparent/Diffuse"));
roadsMesh = meshFilter.sharedMesh = new Mesh();
roadsMesh.name = "Roads";
roadsMesh.MarkDynamic();
}
private void Update()
{
if (!zoomRange.InRange(map.zoom))
{
roadsMesh.Clear();
return;
}
double tlx, tly, brx, bry;
map.GetTopLeftPosition(out tlx, out tly);
map.GetBottomRightPosition(out brx, out bry);
map.projection.CoordinatesToTile(tlx, tly, map.zoom, out tlx, out tly);
map.projection.CoordinatesToTile(brx, bry, map.zoom, out brx, out bry);
OnlineMapsVector2i newTopLeft = new OnlineMapsVector2i((int) Math.Round(tlx - 2), (int) Math.Round(tly - 2));
OnlineMapsVector2i newBottomRight = new OnlineMapsVector2i((int) Math.Round(brx + 2), (int) Math.Round(bry + 2));
if (newTopLeft != topLeft || newBottomRight != bottomRight)
{
topLeft = newTopLeft;
bottomRight = newBottomRight;
PrepareRequest();
}
if (lastRequestTime + requestRate < Time.time) SendRequest();
UpdateRoadsMesh();
}
private void UpdateRoadsMesh()
{
roadsMesh.Clear();
if (ways == null || ways.Count == 0) return;
float width = 12f * (1 << map.zoom) / (1 << 19);
double tlx, tly, brx, bry;
map.GetTopLeftPosition(out tlx, out tly);
map.GetBottomRightPosition(out brx, out bry);
if (brx < tlx) brx += 360;
float bestElevationYScale = control.GetBestElevationYScale(tlx, tly, brx, bry);
List<OnlineMapsOSMNode> usedNodes = new List<OnlineMapsOSMNode>(30);
List<Vector3> vertices = new List<Vector3>(128);
List<Vector3> normals = new List<Vector3>(128);
List<Vector2> uv = new List<Vector2>(128);
List<int> triangles = new List<int>(128);
foreach (OnlineMapsOSMWay way in ways) DrawRoad(way, usedNodes, vertices, normals, uv, triangles, width, tlx, tly, brx, bry, bestElevationYScale);
roadsMesh.vertices = vertices.ToArray();
roadsMesh.normals = normals.ToArray();
roadsMesh.uv = uv.ToArray();
roadsMesh.SetTriangles(triangles.ToArray(), 0);
}
}