Skip to content
Snippets Groups Projects
Commit 26192e5c authored by Knuiman, Bart's avatar Knuiman, Bart
Browse files

big wip

parent becf3934
No related branches found
No related tags found
No related merge requests found
...@@ -2,16 +2,58 @@ using Mapbox.Vector.Tile; ...@@ -2,16 +2,58 @@ using Mapbox.Vector.Tile;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEditor;
using UnityEngine; using UnityEngine;
using UnityEngine.Networking; using UnityEngine.Networking;
using static Wander.Easing;
namespace Wander namespace Wander
{ {
// Always multiple of 3. Each 3 form a triangle. // Always multiple of 3. Each 3 form a triangle.
public struct TriangulatedPolygon public class TriangulatedPolygon
{ {
public List<Vector2> vertices; public List<Vector2> vertices;
public List<Vector2> mins;
public List<Vector2> maxs;
public List<float> denoms;
public void OptimizeForIsPointInTriangle()
{
if ( vertices == null ) return; // Non poly layers have this.
mins = new List<Vector2>( vertices.Count / 3 );
maxs = new List<Vector2>( vertices.Count / 3 );
denoms = new List<float>( vertices.Count / 3 );
for ( int i = 0; i < vertices.Count; i += 3 )
{
float minx = float.MaxValue;
float miny = float.MaxValue;
if (vertices[i+0].x < minx) minx = vertices[i].x;
if (vertices[i+0].y < miny) miny = vertices[i].y;
if (vertices[i+1].x < minx) minx = vertices[i+1].x;
if (vertices[i+1].y < miny) miny = vertices[i+1].y;
if (vertices[i+2].x < minx) minx = vertices[i+2].x;
if (vertices[i+2].y < miny) miny = vertices[i+2].y;
mins.Add( new Vector2( minx, miny ) );
float maxx = float.MinValue;
float maxy = float.MinValue;
if (vertices[i+0].x > maxx) maxx = vertices[i].x;
if (vertices[i+0].y > maxy) maxy = vertices[i].y;
if (vertices[i+1].x > maxx) maxx = vertices[i+1].x;
if (vertices[i+1].y > maxy) maxy = vertices[i+1].y;
if (vertices[i+2].x > maxx) maxx = vertices[i+2].x;
if (vertices[i+2].y > maxy) maxy = vertices[i+2].y;
maxs.Add( new Vector2( maxx, maxy ) );
// float denominator = ((vertex2.y - vertex3.y) * (vertex1.x - vertex3.x) + (vertex3.x - vertex2.x) * (vertex1.y - vertex3.y));
float denominator = ((vertices[i+1].y - vertices[i+2].y) * (vertices[i].x - vertices[i+2].x) + (vertices[i+2].x - vertices[i+1].x) * (vertices[i].y - vertices[i+2].y));
denoms.Add( 1.0f / denominator );
}
}
} }
public class VectorTile public class VectorTile
...@@ -83,8 +125,11 @@ namespace Wander ...@@ -83,8 +125,11 @@ namespace Wander
var polygons = new List<TriangulatedPolygon>(); var polygons = new List<TriangulatedPolygon>();
for (int j = 0; j< features.Count; j++) for (int j = 0; j< features.Count; j++)
{ {
polygons.Add( new TriangulatedPolygon() ); // Add empty to ensure list(layer) of lists(features) match.
if (features[j].GeometryType != Tile.GeomType.Polygon) if (features[j].GeometryType != Tile.GeomType.Polygon)
{
continue; continue;
}
vertices.Clear(); vertices.Clear();
holeIndices.Clear(); holeIndices.Clear();
var rings = features[j].Geometry; var rings = features[j].Geometry;
...@@ -112,7 +157,7 @@ namespace Wander ...@@ -112,7 +157,7 @@ namespace Wander
double y = vertices[indices[k]*2+1]; double y = vertices[indices[k]*2+1];
poly.vertices.Add( new Vector2( (float)x, (float)y ) ); poly.vertices.Add( new Vector2( (float)x, (float)y ) );
} }
polygons.Add( poly ); polygons[polygons.Count-1] = poly;
Debug.Assert( poly.vertices.Count % 3 == 0 ); Debug.Assert( poly.vertices.Count % 3 == 0 );
} }
catch (Exception) catch (Exception)
...@@ -126,20 +171,32 @@ namespace Wander ...@@ -126,20 +171,32 @@ namespace Wander
return numFailedPolys; return numFailedPolys;
} }
public void OptimizeForPointIsInsideTriangle()
{
for (int i = 0;i < polygonLayers.Count;i++)
for (int j = 0;j < polygonLayers[i].Count;j++)
polygonLayers[i][j].OptimizeForIsPointInTriangle();
}
// Calls callback(x, y, channel) for each raster position (256 channels) where each value represents a single channel. // Calls callback(x, y, channel) for each raster position (256 channels) where each value represents a single channel.
// If no polygon was hit, 255 is called. // If no polygon was hit, 255 is called.
// If polygon was hit, but no feature was matched, 254 is called. // If polygon was hit, but no feature was matched, 254 is called.
public void RenderToTextureSingle( int width, int height, string attributeKeyMatch, List<List<string>> layerNamesList, Func<int, int, byte, bool> callback ) // Returns a list of failed to match pixels. This can be due to geometry not exactly matching or a layer not being found.
public List<Vector3Int> RenderToTextureSingle(
int width, int height,
List<string> matchingAttribKeys,
List<List<string>> layerNamesList,
Func<int, int, byte, bool> callback )
{ {
Debug.Assert( triangulated, "First call Triangulate." ); Debug.Assert( triangulated, "First call Triangulate." );
Debug.Assert( layerNamesList.Count < 254, "254 and 255 are reserved for no hit or no match." ); Debug.Assert( layerNamesList.Count < 254, "254 and 255 are reserved for no hit or no match." );
bool cancel = false;
// First match layers to layer names. // First match layers to layer names.
bool cancel = false;
List<Vector3Int> failedPixels = new List<Vector3Int>();
for (int l = 0;l < layers.Count && !cancel;l++) for (int l = 0;l < layers.Count && !cancel;l++)
{ {
var layer = layers[l]; var layer = layers[l];
for (int f = 0;f < layer.VectorTileFeatures.Count && !cancel;f++) for (int f = 0;f < layer.VectorTileFeatures.Count && !cancel;f++)
{ {
var feature = layer.VectorTileFeatures[f]; var feature = layer.VectorTileFeatures[f];
...@@ -155,15 +212,35 @@ namespace Wander ...@@ -155,15 +212,35 @@ namespace Wander
bool matchingLayerFound = false; bool matchingLayerFound = false;
for (int a = 0;a < feature.Attributes.Count && !matchingLayerFound;a++) for (int a = 0;a < feature.Attributes.Count && !matchingLayerFound;a++)
{ {
if (feature.Attributes[a].Key != attributeKeyMatch) for (int m = 0;m < matchingAttribKeys.Count && !matchingLayerFound;m++)
continue; {
if (feature.Attributes[a].Key != matchingAttribKeys[m])
string function = feature.Attributes[a].Value as string; continue;
string function = feature.Attributes[a].Value as string;
for (int layerIdx = 0;layerIdx < layerNamesList.Count && !matchingLayerFound;layerIdx++)
{
for (int layerNameIdx = 0;layerNameIdx < layerNamesList[layerIdx].Count;layerNameIdx++)
{
if (function.Contains( layerNamesList[layerIdx][layerNameIdx] ))
{
feature.SelectedLayerIdx = layerIdx;
matchingLayerFound = true;
break;
}
}
}
}
}
// try Layer.name
if (!matchingLayerFound)
{
for (int layerIdx = 0;layerIdx < layerNamesList.Count && !matchingLayerFound;layerIdx++) for (int layerIdx = 0;layerIdx < layerNamesList.Count && !matchingLayerFound;layerIdx++)
{ {
for (int layerNameIdx = 0;layerNameIdx < layerNamesList[layerIdx].Count;layerNameIdx++) for (int layerNameIdx = 0;layerNameIdx < layerNamesList[layerIdx].Count;layerNameIdx++)
{ {
if (function.Contains( layerNamesList[layerIdx][layerNameIdx] )) if (layer.Name.Contains( layerNamesList[layerIdx][layerNameIdx] ))
{ {
feature.SelectedLayerIdx = layerIdx; feature.SelectedLayerIdx = layerIdx;
matchingLayerFound = true; matchingLayerFound = true;
...@@ -175,44 +252,88 @@ namespace Wander ...@@ -175,44 +252,88 @@ namespace Wander
} }
} }
Debug.Assert( width == height, "Must be square images." );
// For each layer, for each pixel, now check triangle intersections. // For each layer, for each pixel, now check triangle intersections.
for (int l = 0;l < layers.Count && !cancel;l++) for (int l = 0;l < layers.Count && !cancel;l++)
{ {
var layer = layers[l]; var layer = layers[l];
float fx = (float)layer.Extent / width;
TriangulatedPolygon cachedPoly = default;
int cachedVtxIdx = -1;
int cachedTriIdx = -1;
byte cachedPixel = 0;
for (int y = 0;y < height && !cancel;y++) for (int y = 0;y < height && !cancel;y++)
{ {
for (int x = 0;x < width && !cancel;x++) for (int x = 0;x < width && !cancel;x++)
{ {
Vector2 p = new Vector2(x, y); Vector2 p = new Vector2(fx*x+0.5f*fx, fx*y+0.5f*fx);
bool hit = false;
for (int f = 0;f < layer.VectorTileFeatures.Count && !cancel;f++) // First try cache, quite often adjacent pixels will hit the same triangle.
if (cachedVtxIdx!=-1)
{
var vertices = cachedPoly.vertices;
var denoms = cachedPoly.denoms;
var mins = cachedPoly.mins;
var maxs = cachedPoly.maxs;
if (!(p.x < mins[cachedTriIdx].x || p.x > maxs[cachedTriIdx].x) &&
!(p.y < mins[cachedTriIdx].y || p.y > maxs[cachedTriIdx].y))
{
hit = GeomUtil.PointIsInsideTriangle2( p, vertices[cachedVtxIdx], vertices[cachedVtxIdx+1], vertices[cachedVtxIdx+2], denoms[cachedTriIdx] );
if (hit)
{
cancel = callback( x, y, cachedPixel ); // If SelectedLayerIdx did not match, it was set to 254.
continue; // Pass from cache, continue to next pixel.
}
}
}
// Must check all triangles, no cache or was no hit with cache.
for (int f = 0;f < layer.VectorTileFeatures.Count;f++)
{ {
var feature = layer.VectorTileFeatures[f]; var feature = layer.VectorTileFeatures[f];
if (feature.GeometryType != Tile.GeomType.Polygon) if (feature.GeometryType != Tile.GeomType.Polygon)
continue; continue;
var triangles = polygonLayers[l][f].vertices; var polygons = polygonLayers[l][f];
bool hit = false; if (polygons.vertices.Count == 0)
for (int i = 0;i < triangles.Count && !cancel;i += 3) continue;
cachedVtxIdx = -1;
cachedPoly = polygonLayers[l][f];
var mins = cachedPoly.mins;
var maxs = cachedPoly.maxs;
var denoms = cachedPoly.denoms;
var vertices = cachedPoly.vertices;
for (int vIdx = 0, triIdx = 0; vIdx < vertices.Count; vIdx += 3, triIdx++)
{ {
hit = GeomUtil.PointIsInsideTriangle( p, triangles[i], triangles[i+1], triangles[i+2] ); if ( p.x < mins[triIdx].x || p.x > maxs[triIdx].x ) continue;
if ( p.y < mins[triIdx].y || p.y > maxs[triIdx].y ) continue;
hit = GeomUtil.PointIsInsideTriangle2( p, vertices[vIdx], vertices[vIdx+1], vertices[vIdx+2], denoms[triIdx] );
if (hit) if (hit)
{ {
cancel = callback(x, y, (byte)feature.SelectedLayerIdx); // If SelectedLayerIdx did not match, it was set to 254. cachedTriIdx = triIdx;
cachedVtxIdx = vIdx;
cachedPixel = (byte)feature.SelectedLayerIdx;
cancel = callback( x, y, cachedPixel );
break; break;
} }
} }
if (!hit) if (hit) break;
{ }
callback( x, y, 255 ); // no hit
} if ( !hit )
{
failedPixels.Add( new Vector3Int( x, y, 255 ) );
} }
} }
} }
} }
return failedPixels;
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment