/// <summary> /// TO BE REMOVED!!! Processing geometries is out of scope. /// Clip geometries extending beyond the tile border. /// </summary> /// <param name="geoms">Raw tile geometries of the feature</param> /// <param name="geomType">Geometry type of the feature</param> /// <param name="extent">Extent of the layer </param> /// <param name="bufferSize">Units (in internal tile coordinates) to go beyond the tile border. Pass '0' to clip exactly at the tile border</param> /// <param name="scale">Factor for scaling the geometries</param> /// <returns></returns> public static List <List <Point2d <long> > > ClipGeometries( List <List <Point2d <long> > > geoms , GeomType geomType , long extent , uint bufferSize , float scale ) { List <List <Point2d <long> > > retVal = new List <List <Point2d <long> > >(); //points: simply remove them if one part of the coordinate pair is out of bounds: // <0 || >extent if (geomType == GeomType.POINT) { foreach (var geomPart in geoms) { List <Point2d <long> > outGeom = new List <Point2d <long> >(); foreach (var geom in geomPart) { if ( geom.X < (0L - bufferSize) || geom.Y < (0L - bufferSize) || geom.X > (extent + bufferSize) || geom.Y > (extent + bufferSize) ) { continue; } outGeom.Add(geom); } if (outGeom.Count > 0) { retVal.Add(outGeom); } } return(retVal); } //use clipper for lines and polygons bool closed = true; if (geomType == GeomType.LINESTRING) { closed = false; } Polygons subjects = new Polygons(); Polygons clip = new Polygons(1); Polygons solution = new Polygons(); clip.Add(new Polygon(4)); clip[0].Add(new InternalClipper.IntPoint(0L - bufferSize, 0L - bufferSize)); clip[0].Add(new InternalClipper.IntPoint(extent + bufferSize, 0L - bufferSize)); clip[0].Add(new InternalClipper.IntPoint(extent + bufferSize, extent + bufferSize)); clip[0].Add(new InternalClipper.IntPoint(0L - bufferSize, extent + bufferSize)); foreach (var geompart in geoms) { Polygon part = new Polygon(); foreach (var geom in geompart) { part.Add(new InternalClipper.IntPoint(geom.X, geom.Y)); } subjects.Add(part); } InternalClipper.Clipper c = new InternalClipper.Clipper(); c.AddPaths(subjects, InternalClipper.PolyType.ptSubject, closed); c.AddPaths(clip, InternalClipper.PolyType.ptClip, true); bool succeeded = false; if (geomType == GeomType.LINESTRING) { InternalClipper.PolyTree lineSolution = new InternalClipper.PolyTree(); succeeded = c.Execute( InternalClipper.ClipType.ctIntersection , lineSolution , InternalClipper.PolyFillType.pftNonZero , InternalClipper.PolyFillType.pftNonZero ); if (succeeded) { solution = InternalClipper.Clipper.PolyTreeToPaths(lineSolution); } } else { succeeded = c.Execute( InternalClipper.ClipType.ctIntersection , solution , InternalClipper.PolyFillType.pftNonZero , InternalClipper.PolyFillType.pftNonZero ); } if (succeeded) { retVal = new List <List <Point2d <long> > >(); foreach (var part in solution) { List <Point2d <long> > geompart = new List <Point2d <long> >(); // HACK: // 1. clipper may or may not reverse order of vertices of LineStrings // 2. clipper semms to drop the first vertex of a Polygon // * We don't care about 1. // * Added a check for 2 and insert a copy of last vertex as first foreach (var geom in part) { geompart.Add(new Point2d <long>() { X = geom.X, Y = geom.Y }); } if (geomType == GeomType.POLYGON) { if (!geompart[0].Equals(geompart[geompart.Count - 1])) { geompart.Insert(0, geompart[geompart.Count - 1]); } } retVal.Add(geompart); } return(retVal); } else { //if clipper was not successfull return original geometries return(geoms); } }
private static List <List <Point2d> > clipGeometries( List <List <Point2d> > geoms , GeomType geomType , long extent , uint bufferSize ) { List <List <Point2d> > retVal = new List <List <Point2d> >(); //points: simply remove them if one part of the coordinate pair is out of bounds: // <0 || >extent if (geomType == GeomType.POINT) { foreach (var geomPart in geoms) { List <Point2d> outGeom = new List <Point2d>(); foreach (var geom in geomPart) { if ( geom.X < (0L - bufferSize) || geom.Y < (0L - bufferSize) || geom.X > (extent + bufferSize) || geom.Y > (extent + bufferSize) ) { continue; } outGeom.Add(geom); } if (outGeom.Count > 0) { retVal.Add(outGeom); } } return(retVal); } //use clipper for lines and polygons bool closed = true; if (geomType == GeomType.LINESTRING) { closed = false; } Polygons subjects = new Polygons(); Polygons clip = new Polygons(1); Polygons solution = new Polygons(); clip.Add(new Polygon(4)); clip[0].Add(new InternalClipper.IntPoint(0L - bufferSize, 0L - bufferSize)); clip[0].Add(new InternalClipper.IntPoint(extent + bufferSize, 0L - bufferSize)); clip[0].Add(new InternalClipper.IntPoint(extent + bufferSize, extent + bufferSize)); clip[0].Add(new InternalClipper.IntPoint(0L - bufferSize, extent + bufferSize)); foreach (var geompart in geoms) { Polygon part = new Polygon(); foreach (var geom in geompart) { part.Add(new InternalClipper.IntPoint(geom.X, geom.Y)); } subjects.Add(part); } InternalClipper.Clipper c = new InternalClipper.Clipper(); c.AddPaths(subjects, InternalClipper.PolyType.ptSubject, closed); c.AddPaths(clip, InternalClipper.PolyType.ptClip, true); bool succeeded = false; if (geomType == GeomType.LINESTRING) { InternalClipper.PolyTree lineSolution = new InternalClipper.PolyTree(); succeeded = c.Execute( InternalClipper.ClipType.ctIntersection , lineSolution , InternalClipper.PolyFillType.pftNonZero , InternalClipper.PolyFillType.pftNonZero ); if (succeeded) { solution = InternalClipper.Clipper.PolyTreeToPaths(lineSolution); } } else { succeeded = c.Execute( InternalClipper.ClipType.ctIntersection , solution , InternalClipper.PolyFillType.pftNonZero , InternalClipper.PolyFillType.pftNonZero ); } if (succeeded) { retVal = new List <List <Point2d> >(); foreach (var part in solution) { List <Point2d> geompart = new List <Point2d>(); foreach (var geom in part) { geompart.Add(new Point2d() { X = geom.X, Y = geom.Y }); } retVal.Add(geompart); } return(retVal); } else { //if clipper was not successfull return original geometries return(geoms); } }
public override void Run(VectorFeatureUnity feature, MeshData md, UnityTile tile = null) { if (feature.Points.Count < 1) { return; } InternalClipper.PolyTree solution = new InternalClipper.PolyTree(); InternalClipper.ClipperOffset co = new InternalClipper.ClipperOffset(); foreach (var roadSegment in feature.Points) { co.AddPath(roadSegment.Select(i => new InternalClipper.IntPoint(i.x, i.z)).ToList(), InternalClipper.JoinType.jtSquare, InternalClipper.EndType.etOpenButt); } co.Execute(ref solution, Width / 2); var x = solution; var polygon = new Polygon(); Vertex prev = null; Vertex current = null; Vertex first = null; foreach (var poly in solution.m_AllPolys) { prev = null; current = null; first = null; foreach (var item in poly.Contour) { prev = current; current = new Vertex(item.X, item.Y, 0); if (first == null) { first = current; } polygon.Add(current); if (prev != null) { polygon.Add(new Segment(current, prev)); } } polygon.Add(new Segment(first, current)); } var mesh = polygon.Triangulate(); var data = new List <int>(); foreach (var tri in mesh.Triangles) { data.Add(tri.GetVertexID(0)); data.Add(tri.GetVertexID(2)); data.Add(tri.GetVertexID(1)); } foreach (var edge in mesh.Edges) { if (edge.Label == 0) { continue; } md.Edges.Add(edge.P0); md.Edges.Add(edge.P1); } md.Vertices.Clear(); using (var sequenceEnum = mesh.Vertices.GetEnumerator()) { while (sequenceEnum.MoveNext()) { md.Vertices.Add(new Vector3((float)sequenceEnum.Current.x, 0, (float)sequenceEnum.Current.y)); } } md.Triangles.Add(data); //foreach (var roadSegment in feature.Points) //{ // var count = roadSegment.Count; // for (int i = 1; i < count*2; i++) // { // md.Edges.Add(md.Vertices.Count + i); // md.Edges.Add(md.Vertices.Count + i - 1); // } // md.Edges.Add(md.Vertices.Count); // md.Edges.Add(md.Vertices.Count + (count*2) - 1); // var newVerticeList = new Vector3[count * 2]; // var uvList = new Vector2[count * 2]; // Vector3 norm; // var lastUv = 0f; // var p1 = Mapbox.Unity.Constants.Math.Vector3Zero; // var p2 = Mapbox.Unity.Constants.Math.Vector3Zero; // var p3 = Mapbox.Unity.Constants.Math.Vector3Zero; // for (int i = 1; i < count; i++) // { // p1 = roadSegment[i - 1]; // p2 = roadSegment[i]; // p3 = p2; // if (i + 1 < roadSegment.Count) // p3 = roadSegment[i + 1]; // if (i == 1) // { // norm = GetNormal(p1, p1, p2) * Width; //road width // newVerticeList[0] = (p1 + norm); // newVerticeList[count * 2 - 1] = (p1 - norm); // uvList[0] = new Vector2(0, 0); // uvList[count * 2 - 1] = new Vector2(1, 0); // } // var dist = Vector3.Distance(p1, p2); // lastUv += dist; // norm = GetNormal(p1, p2, p3) * Width; // newVerticeList[i] = (p2 + norm); // newVerticeList[2 * count - 1 - i] = (p2 - norm); // uvList[i] = new Vector2(0, lastUv); // uvList[2 * count - 1 - i] = new Vector2(1, lastUv); // } // //if (_mergeStartEnd) // //{ // // //brnkhy -2 because first and last items are same // // p1 = segment[count - 2]; // // p2 = segment[0]; // // p3 = segment[1]; // // norm = GetNormal(p1, p2, p3) * Width; // // newVerticeList[count - 1] = p2 + norm; // // newVerticeList[0] = p2 + norm; // // newVerticeList[count] = p2 - norm; // // newVerticeList[2 * count - 1] = p2 - norm; // //} // var pcount = md.Vertices.Count; // md.Vertices.AddRange(newVerticeList); // md.UV[0].AddRange(uvList); // var lineTri = new List<int>(); // var n = count; // for (int i = 0; i < n - 1; i++) // { // lineTri.Add(pcount + i); // lineTri.Add(pcount + i + 1); // lineTri.Add(pcount + 2 * n - 1 - i); // lineTri.Add(pcount + i + 1); // lineTri.Add(pcount + 2 * n - i - 2); // lineTri.Add(pcount + 2 * n - i - 1); // } // if (md.Triangles.Count < 1) // md.Triangles.Add(new List<int>()); // md.Triangles[0].AddRange(lineTri); //} }