public void TestInvertedItalicNTSConforming() { var atb = new AffineTransformationBuilder( new Coordinate(0, 0), new Coordinate(50, 0), new Coordinate(0, 100), new Coordinate(0, 0), new Coordinate(50, 0), new Coordinate(20, 100)); var geom = _wktReader.Read(NTS); //Apply italic effect geom = atb.GetTransformation().Transform(geom); Console.WriteLine(geom.AsText()); IGeometry constraint = ((IPolygon)geom).GetInteriorRingN(0); constraint = geom.Factory.CreatePolygon((ILinearRing)constraint, null); constraint = ((IPolygon)constraint.Buffer(-1)).Shell; var coordinates = constraint.Coordinates; coordinates[coordinates.Length - 1].X -= 1e-7; coordinates[coordinates.Length - 1].Y -= 1e-7; constraint = geom.Factory.CreateLineString(coordinates); Console.WriteLine(constraint.AsText()); //Setup var dtb = new ConformingDelaunayTriangulationBuilder { Constraints = constraint }; dtb.SetSites(geom); var result = dtb.GetEdges(geom.Factory); Console.WriteLine(result.AsText()); }
public void TestInvertedNTSConforming() { IGeometry geom = _wktReader.Read(NTS); Console.WriteLine(geom.AsText()); IGeometry constraint = ((IPolygon)geom).GetInteriorRingN(0); constraint = geom.Factory.CreatePolygon((ILinearRing)constraint, null); constraint = ((IPolygon)constraint.Buffer(-1)).Shell; Coordinate[] coordinates = constraint.Coordinates; coordinates[coordinates.Length - 1].X -= 1e-7; coordinates[coordinates.Length - 1].Y -= 1e-7; constraint = geom.Factory.CreateLineString(coordinates); Console.WriteLine(constraint.AsText()); //Setup ConformingDelaunayTriangulationBuilder dtb = new ConformingDelaunayTriangulationBuilder { Constraints = constraint }; dtb.SetSites(geom); IMultiLineString result = dtb.GetEdges(geom.Factory); Console.WriteLine(result.AsText()); }
/// <summary> /// Calculte concave hull for grid cells /// </summary> /// <param name="gridCells"></param> /// <param name="alphaValue"></param> /// <param name="useCenterPoint">Used when concave hull is calculated. Grid corner coordinates used when false</param> /// <returns></returns> public static IGeometry ConcaveHull(this List <WebGridCellSpeciesObservationCount> gridCells, double alphaValue, bool useCenterPoint) { if (gridCells == null || gridCells.Count < 3) { return(null); } IPoint[] points; if (useCenterPoint) { //Create a geometry with all grid cell points, this is much faster than using the gridcells because it's less coordinates, the generated geometry will also look better points = (from c in gridCells select c.OrginalCentreCoordinate.ToPoint()).ToArray(); } else { points = new IPoint[gridCells.Count * 4]; for (var i = 0; i < gridCells.Count; i++) { var gridCell = gridCells[i]; var boundingBox = gridCell.OrginalBoundingBox; if (boundingBox == null) { continue; } var startIndex = i * 4; points[startIndex] = new Point(new Coordinate(boundingBox.Min.X, boundingBox.Min.Y)); points[startIndex + 1] = new Point(new Coordinate(boundingBox.Min.X, boundingBox.Max.Y)); points[startIndex + 2] = new Point(new Coordinate(boundingBox.Max.X, boundingBox.Max.Y)); points[startIndex + 3] = new Point(new Coordinate(boundingBox.Max.X, boundingBox.Min.Y)); } } //Triangulate all points var triangulationBuilder = new ConformingDelaunayTriangulationBuilder(); triangulationBuilder.SetSites(new MultiPoint(points)); var geometryFactory = new GeometryFactory(); var triangles = triangulationBuilder.GetTriangles(geometryFactory); IGeometry alphaGeometry = null; for (var i = 0; i < triangles.Count; i++) { var triangle = triangles[i]; var radius = triangle.Radius() / 1000; //Div radius by 1000 to (commonly) keep alpha values in a range of 1 - 1000 if (radius < alphaValue) { alphaGeometry = alphaGeometry == null ? triangle : alphaGeometry.Union(triangle); } } return(alphaGeometry); }
public static Geometry conformingDelaunayTriangles(Geometry sites, Geometry constraints) { ConformingDelaunayTriangulationBuilder builder = new ConformingDelaunayTriangulationBuilder(); builder.SetSites(sites); builder.Constraints = constraints; builder.Tolerance = TRIANGULATION_TOLERANCE; var geomFact = sites != null ? sites.Factory : constraints.Factory; Geometry tris = builder.GetTriangles(geomFact); return(tris); }
private static Geometry ConformingDelaunayTrianglesWithTolerance(Geometry sites, Geometry constraints, double tol) { var builder = new ConformingDelaunayTriangulationBuilder(); builder.SetSites(sites); builder.Constraints = constraints; builder.Tolerance = tol; var geomFact = sites != null ? sites.Factory : constraints.Factory; Geometry tris = builder.GetTriangles(geomFact); return(tris); }
public void Test2() { var geom = _wktReader.Read("POLYGON ((0 0, 0 10, 4 10, 4 8, 6 8, 6 10, 10 10, 10 0, 0 0))"); var dtb = new ConformingDelaunayTriangulationBuilder(); dtb.SetSites(geom); var resultEdges = dtb.GetEdges(geom.Factory); Console.WriteLine(resultEdges.AsText()); var resultTriangles = dtb.GetTriangles(geom.Factory); Console.WriteLine(resultTriangles.AsText()); }
public static IGeometry ConformingDelaunayEdgesWithTolerance(IGeometry sites, IGeometry constraints, double tol) { ConformingDelaunayTriangulationBuilder builder = new ConformingDelaunayTriangulationBuilder(); builder.SetSites(sites); builder.Constraints = constraints; builder.Tolerance = tol; IGeometryFactory geomFact = sites != null ? sites.Factory : constraints.Factory; IGeometry tris = builder.GetEdges(geomFact); return(tris); }
private static void RunDelaunay(string sitesWKT, string constraintsWKT, bool computeTriangles, string expectedWKT) { var reader = new WKTReader(); var sites = reader.Read(sitesWKT); var constraints = reader.Read(constraintsWKT); var builder = new ConformingDelaunayTriangulationBuilder(); builder.SetSites(sites); builder.Constraints = constraints; var geomFact = GeometryFactory.Default; Geometry result = computeTriangles ? builder.GetTriangles(geomFact) : builder.GetEdges(geomFact); Assert.IsNotNull(result); var expectedEdges = reader.Read(expectedWKT); result.Normalize(); expectedEdges.Normalize(); Assert.IsTrue(expectedEdges.EqualsExact(result, ComparisonTolerance)); }
} // End Function GetConcaveHull public Geometry ComputeConcaveHull() { ConformingDelaunayTriangulationBuilder cdtb = new ConformingDelaunayTriangulationBuilder(); cdtb.SetSites(this.geometries); QuadEdgeSubdivision qes = cdtb.GetSubdivision(); IList <QuadEdge> quadEdges = qes.GetEdges(); IList <QuadEdgeTriangle> qeTriangles = QuadEdgeTriangle.CreateOn(qes); IEnumerable <Vertex> qeVertices = qes.GetVertices(false); int iV = 0; foreach (Vertex v in qeVertices) { this.coordinates[v.Coordinate] = iV; this.vertices[iV] = new Vertex(iV, v.Coordinate); iV++; } List <QuadEdge> qeFrameBorder = new List <QuadEdge>(); List <QuadEdge> qeFrame = new List <QuadEdge>(); List <QuadEdge> qeBorder = new List <QuadEdge>(); // here each one more foreach (QuadEdge qe in quadEdges) { if (qes.IsFrameBorderEdge(qe)) { qeFrameBorder.Add(qe); } if (qes.IsFrameEdge(qe)) { qeFrame.Add(qe); } } // Next qe // border for (int j = 0; j < qeFrameBorder.Count; j++) { QuadEdge q = qeFrameBorder[j]; if (!qeFrame.Contains(q)) { qeBorder.Add(q); } } // Next j // deletion of exterior edges foreach (QuadEdge qe in qeFrame) { qes.Delete(qe); } Dictionary <QuadEdge, double> qeDistances = new Dictionary <QuadEdge, double>(); foreach (QuadEdge qe in quadEdges) { qeDistances.Add(qe, qe.ToLineSegment().Length); } DoubleComparator dc = new DoubleComparator(qeDistances); // This doesn't work with dictionary - missing duplicates ... List <KeyValuePair <QuadEdge, double> > qeSorted = new List <KeyValuePair <QuadEdge, double> >(); foreach (KeyValuePair <QuadEdge, double> thisDistance in qeDistances) { qeSorted.Add(thisDistance); } qeSorted.Sort(dc); // edges creation int i = 0; foreach (KeyValuePair <QuadEdge, double> kvp in qeSorted) { LineSegment s = kvp.Key.ToLineSegment(); s.Normalize(); int idS = this.coordinates[s.P0]; int idD = this.coordinates[s.P1]; Vertex oV = this.vertices[idS]; Vertex eV = this.vertices[idD]; Edge edge; if (qeBorder.Contains(kvp.Key)) { oV.IsBorder = true; eV.IsBorder = true; edge = new Edge(i, s, oV, eV, true); if (s.Length < this.threshold) { this.shortLengths[i] = edge; } else { this.lengths[i] = edge; } } else { edge = new Edge(i, s, oV, eV, false); } this.edges[i] = edge; this.segments[s] = i; i++; } // Next qe // hm of linesegment and hm of edges // with id as key // hm of triangles using hm of ls and connection with hm of edges i = 0; foreach (QuadEdgeTriangle qet in qeTriangles) { LineSegment sA = qet.GetEdge(0).ToLineSegment(); LineSegment sB = qet.GetEdge(1).ToLineSegment(); LineSegment sC = qet.GetEdge(2).ToLineSegment(); sA.Normalize(); sB.Normalize(); sC.Normalize(); Edge edgeA = this.edges[this.segments[sA]]; Edge edgeB = this.edges[this.segments[sB]]; Edge edgeC = this.edges[this.segments[sC]]; Triangle triangle = new Triangle(i, qet.IsBorder() ? true : false); triangle.AddEdge(edgeA); triangle.AddEdge(edgeB); triangle.AddEdge(edgeC); edgeA.AddTriangle(triangle); edgeB.AddTriangle(triangle); edgeC.AddTriangle(triangle); this.triangles[i] = triangle; i++; } // Next qet // add triangle neighbourood foreach (Edge edge in this.edges.Values) { if (edge.Triangles.Count != 1) { Triangle tA = edge.Triangles[0]; Triangle tB = edge.Triangles[1]; tA.AddNeighbour(tB); tB.AddNeighbour(tA); } } // concave hull algorithm int index = 0; while (index != -1) { index = -1; Edge e = null; // find the max length (smallest id so first entry) int si = this.lengths.Count; if (si != 0) { KeyValuePair <int, Edge> entry = this.lengths.First(); int ind = entry.Key; if (entry.Value.Geometry.Length > this.threshold) { index = ind; e = entry.Value; } } // End if (si != 0) if (index != -1) { Triangle triangle = e.Triangles[0]; List <Triangle> neighbours = triangle.Neighbours; // irregular triangle test if (neighbours.Count == 1) { this.shortLengths[e.Id] = e; this.lengths.Remove(e.Id); } else { Edge e0 = triangle.Edges[0]; Edge e1 = triangle.Edges[1]; // test if all the vertices are on the border if (e0.OV.IsBorder && e0.EV.IsBorder && e1.OV.IsBorder && e1.EV.IsBorder) { this.shortLengths[e.Id] = e; this.lengths.Remove(e.Id); } else { // management of triangles Triangle tA = neighbours[0]; Triangle tB = neighbours[1]; tA.Border = true; // FIXME not necessarily useful tB.Border = true; // FIXME not necessarily useful this.triangles.Remove(triangle.Id); tA.RemoveNeighbour(triangle); tB.RemoveNeighbour(triangle); // new edges List <Edge> ee = triangle.Edges; Edge eA = ee[0]; Edge eB = ee[1]; Edge eC = ee[2]; if (eA.Border) { this.edges.Remove(eA.Id); eB.Border = true; eB.OV.IsBorder = true; eB.EV.IsBorder = true; eC.Border = true; eC.OV.IsBorder = true; eC.EV.IsBorder = true; // clean the relationships with the triangle eB.RemoveTriangle(triangle); eC.RemoveTriangle(triangle); if (eB.Geometry.Length < this.threshold) { this.shortLengths[eB.Id] = eB; } else { this.lengths[eB.Id] = eB; } if (eC.Geometry.Length < this.threshold) { this.shortLengths[eC.Id] = eC; } else { this.lengths[eC.Id] = eC; } this.lengths.Remove(eA.Id); } // End if (eA.Border) else if (eB.Border) { this.edges.Remove(eB.Id); eA.Border = true; eA.OV.IsBorder = true; eA.EV.IsBorder = true; eC.Border = true; eC.OV.IsBorder = true; eC.EV.IsBorder = true; // clean the relationships with the triangle eA.RemoveTriangle(triangle); eC.RemoveTriangle(triangle); if (eA.Geometry.Length < this.threshold) { this.shortLengths[eA.Id] = eA; } else { this.lengths[eA.Id] = eA; } if (eC.Geometry.Length < this.threshold) { this.shortLengths[eC.Id] = eC; } else { this.lengths[eC.Id] = eC; } this.lengths.Remove(eB.Id); } // End else if (eB.Border) else { this.edges.Remove(eC.Id); eA.Border = true; eA.OV.IsBorder = true; eA.EV.IsBorder = true; eB.Border = true; eB.OV.IsBorder = true; eB.EV.IsBorder = true; // clean the relationships with the triangle eA.RemoveTriangle(triangle); eB.RemoveTriangle(triangle); if (eA.Geometry.Length < this.threshold) { this.shortLengths[eA.Id] = eA; } else { this.lengths[eA.Id] = eA; } if (eB.Geometry.Length < this.threshold) { this.shortLengths[eB.Id] = eB; } else { this.lengths[eB.Id] = eB; } this.lengths.Remove(eC.Id); } // End Else of if (e0.OV.Border && e0.EV.Border && e1.OV.Border && e1.EV.Border) } // End Else of if } // End Else of if (neighbours.Count == 1) } // End if (index != -1) } // Whend // concave hull creation List <LineString> edges = new List <LineString>(); foreach (Edge e in this.lengths.Values) { LineString l = e.Geometry.ToGeometry(this.geomFactory); edges.Add(l); } foreach (Edge e in this.shortLengths.Values) { LineString l = e.Geometry.ToGeometry(this.geomFactory); edges.Add(l); } // merge Operation.Linemerge.LineMerger lineMerger = new Operation.Linemerge.LineMerger(); lineMerger.Add(edges); LineString merge = null; using (IEnumerator <Geometry> en = lineMerger.GetMergedLineStrings().GetEnumerator()) { en.MoveNext(); merge = (LineString)en.Current; } if (merge.IsRing) { LinearRing lr = new LinearRing(merge.CoordinateSequence, this.geomFactory); Polygon concaveHull = new Polygon(lr, null, this.geomFactory); return(concaveHull); } return(merge); } // End Function ComputeConcaveHull