private void Create() { if (_subdiv != null) { return; } Envelope siteEnv = DelaunayTriangulationBuilder.Envelope(_siteCoords); IList <Segment> segments = new List <Segment>(); if (_constraintLines != null) { siteEnv.ExpandToInclude(_constraintLines.EnvelopeInternal); CreateVertices(_constraintLines); segments = CreateConstraintSegments(_constraintLines); } IEnumerable <Vertex> sites = CreateSiteVertices(_siteCoords); ConformingDelaunayTriangulator cdt = new ConformingDelaunayTriangulator(sites, _tolerance); cdt.SetConstraints(segments, new List <Vertex>(_constraintVertexMap.Values)); cdt.FormInitialDelaunay(); cdt.EnforceConstraints(); _subdiv = cdt.Subdivision; }
private void Create() { if (_subdiv != null) { return; } Envelope siteEnv = DelaunayTriangulationBuilder.Envelope(_siteCoords); _diagramEnv = siteEnv; // add a buffer around the final envelope double expandBy = Math.Max(_diagramEnv.Width, _diagramEnv.Height); _diagramEnv.ExpandBy(expandBy); if (_clipEnv != null) { _diagramEnv.ExpandToInclude(_clipEnv); } var vertices = DelaunayTriangulationBuilder.ToVertices(_siteCoords); _subdiv = new QuadEdgeSubdivision(siteEnv, _tolerance); IncrementalDelaunayTriangulator triangulator = new IncrementalDelaunayTriangulator(_subdiv); triangulator.InsertSites(vertices); }
// ================================================================== /// <summary> /// Computes the Delaunay triangulation of the initial sites. /// </summary> public void FormInitialDelaunay() { ComputeBoundingBox(); _subdiv = new QuadEdgeSubdivision(_computeAreaEnv, _tolerance); _subdiv.SetLocator(new LastFoundQuadEdgeLocator(_subdiv)); _incDel = new IncrementalDelaunayTriangulator(_subdiv); InsertSites(_initialVertices); }
private void Create() { if (_subdiv != null) { return; } var siteEnv = Envelope(_siteCoords); var vertices = ToVertices(_siteCoords); _subdiv = new QuadEdgeSubdivision(siteEnv, _tolerance); IncrementalDelaunayTriangulator triangulator = new IncrementalDelaunayTriangulator(_subdiv); triangulator.InsertSites(vertices); }
public void TestVoronoiDiagramBuilder() { const string wkt = @"POLYGON ((561758.3399999999 4815264.26, 561758.2199999997 4815264.24, 561758.0899999999 4815264.25, 561757.9699999997 4815264.279999999, 561757.8499999996 4815264.34, 561757.7599999999 4815264.42, 561757.6799999997 4815264.52, 561757.6299999999 4815264.640000001, 561757.5999999996 4815264.76, 561757.5999999996 4815264.890000001, 561757.6299999999 4815265.02, 561757.6799999997 4815265.130000001, 561757.7599999999 4815265.230000001, 561757.8600000005 4815265.310000001, 561758.6100000005 4815265.724000001, 561759.3600000005 4815266.138000001, 561760.1100000005 4815266.552000001, 561760.8600000005 4815266.966000001, 561761.6100000005 4815267.380000001, 561761.75 4815267.41, 561761.9000000004 4815267.4, 561762.04 4815267.359999999, 561762.1699999999 4815267.289999999, 561762.2699999996 4815267.1899999995, 561762.3600000005 4815267.07, 561762.4100000003 4815266.930000001, 561762.4299999997 4815266.789999999, 561762.4199999999 4815266.65, 561762.3799999999 4815266.51, 561762.2999999998 4815266.380000001, 561761.5319999999 4815265.966000001, 561760.764 4815265.552000001, 561759.9959999999 4815265.138000001, 561759.228 4815264.724000001, 561758.4600000001 4815264.310000001, 561758.3399999999 4815264.26))"; var reader = new WKTReader(); var geom = reader.Read(wkt); Assert.IsTrue(geom.IsValid); Assert.IsTrue(geom.IsSimple); //var dtb = new DelaunayTriangulationBuilder(); //dtb.SetSites(geom); QuadEdgeSubdivision qes = null; //Assert.DoesNotThrow( () => qes = dtb.GetSubdivision()); //Assert.IsNotNull(qes); //foreach (var t in qes.GetVoronoiCellPolygons(GeometryFactory.Default)) // Console.WriteLine(t.AsText()); //Console.WriteLine(); GeometryCollection diag = null; //Assert.DoesNotThrow(() => diag = qes.GetVoronoiDiagram(GeometryFactory.Default)); //Assert.IsNotNull(diag); var vdb = new VoronoiDiagramBuilder(); vdb.SetSites(geom); qes = null; Assert.DoesNotThrow(() => qes = vdb.GetSubdivision()); Assert.IsNotNull(qes); foreach (var t in qes.GetVoronoiCellPolygons(GeometryFactory.Default)) { Console.WriteLine(t.AsText()); } Console.WriteLine(); diag = null; Assert.DoesNotThrow(() => diag = vdb.GetDiagram(GeometryFactory.Default)); Assert.IsNotNull(diag); }
private static void RunVoronoi(string sitesWKT, string expectedWKT) { WKTReader reader = new WKTReader(); IGeometry sites = reader.Read(sitesWKT); DelaunayTriangulationBuilder builder = new DelaunayTriangulationBuilder(); builder.SetSites(sites); QuadEdgeSubdivision subdiv = builder.GetSubdivision(); IGeometry result = subdiv.GetVoronoiDiagram(GeometryFactory.Default); Assert.IsNotNull(result); IGeometry expectedEdges = reader.Read(expectedWKT); result.Normalize(); expectedEdges.Normalize(); Assert.IsTrue(expectedEdges.EqualsExact(result, ComparisonTolerance)); }
/// <summary> /// Creates a new triangulator using the given <see cref="QuadEdgeSubdivision"/>. /// The triangulator uses the tolerance of the supplied subdivision. /// </summary> /// <param name="subdiv">a subdivision in which to build the TIN</param> public IncrementalDelaunayTriangulator(QuadEdgeSubdivision subdiv) { _subdiv = subdiv; _isUsingTolerance = subdiv.Tolerance > 0.0; }
private static IList <QuadEdgeTriangle> ExtractTriangles(QuadEdgeSubdivision subdiv) { var qeTris = QuadEdgeTriangle.CreateOn(subdiv); return(qeTris); }
public LastFoundQuadEdgeLocator(QuadEdgeSubdivision subdiv) { _subdiv = subdiv; Init(); }
} // 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