public GraphData(string name, List<Point> inputPoints, List<Segment> segments) { if (String.IsNullOrEmpty(name) || inputPoints == null || segments == null) throw new ArgumentNullException(); Name = name; //InputPoints = new List<Point>(); //InputSegments = new List<Segment>(); VoronoiSolution = new BoostVoronoi(); //Populate the input foreach (var point in inputPoints) { //InputPoints.Add(point); VoronoiSolution.AddPoint(point.X, point.Y); } foreach (var segment in segments) { //InputSegments.Add(segment); VoronoiSolution.AddSegment(segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y); } //Construct VoronoiSolution.Construct(); //Populate the output //OutputVertices = VoronoiSolution.Vertices; //OutputEdges = VoronoiSolution.Edges; //OutputCells = VoronoiSolution.Cells; }
static void Main(string[] args) { //Define a set of segments and pass them to the voronoi wrapper List<Segment> input = new List<Segment>(); input.Add(new Segment(0, 0, 0, 10)); input.Add(new Segment(0, 10, 10, 10)); input.Add(new Segment(10, 10, 10, 0)); input.Add(new Segment(10, 0, 0, 0)); //Instanciate the voronoi wrapper BoostVoronoi bv = new BoostVoronoi(); //Add a point bv.AddPoint(5, 5); //Add the segments foreach (var s in input) bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); //Build the C# Voronoi bv.Construct(); //Get the voronoi output List<Cell> cells = bv.Cells; List<Edge> edges = bv.Edges; List<Vertex> vertices = bv.Vertices; foreach (var cell in cells) { Console.Out.WriteLine(String.Format("Cell Identifier {0}. Is open = {1}", cell.Index, cell.IsOpen)); foreach (var edgeIndex in cell.EdgesIndex) { Edge edge = edges[edgeIndex]; Console.Out.WriteLine( String.Format(" Edge Index: {0}. Start vertex index: {1}, End vertex index: {2}", edgeIndex, edge.Start, edge.End)); //If the vertex index equals -1, it means the edge is infinite. It is impossible to print the coordinates. if (edge.IsLinear) { Vertex start = vertices[edge.Start]; Vertex end = vertices[edge.End]; Console.Out.WriteLine( String.Format(" From:{0}, To: {1}", start.ToString(), end.ToString())); } } } Console.In.ReadLine(); }
static void ConstructAndMeasure(ref List<Point> inputPoints, ref List<Segment> inputSegments) { Console.WriteLine(String.Format("Testing with {0} points and {1} segments", inputPoints.Count, inputSegments.Count)); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); BoostVoronoi bv = new BoostVoronoi(); foreach (var point in inputPoints) bv.AddPoint(point.X, point.Y); foreach (var segment in inputSegments) bv.AddSegment(segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y); bv.Construct(); // Stop timing. stopwatch.Stop(); Console.WriteLine("Time elapsed: {0:hh\\:mm\\:ss\\:ff}", stopwatch.Elapsed); }
public void TestSegmentTwin() { List<Point> inputPoint = new List<Point>() { new Point(5, 5) }; List<Segment> inputSegment = new List<Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 10, 10, 0)); inputSegment.Add(new Segment(10, 0, 0, 0)); //Build the CLR voronoi VoronoiWrapper vw = new VoronoiWrapper(); foreach (var p in inputPoint) vw.AddPoint(p.X, p.Y); foreach (var s in inputSegment) vw.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); vw.ConstructVoronoi(); List<Tuple<int, int, bool, bool, List<int>, bool, short>> clrCells = vw.GetCells(); //Build the C# Voronoi BoostVoronoi bv = new BoostVoronoi(); foreach (var p in inputPoint) bv.AddPoint(p.X, p.Y); foreach (var s in inputSegment) bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); bv.Construct(); List<Edge> sharpEdges = bv.Edges; //Test twin reciprocity for (int i = 0; i < sharpEdges.Count; i++) { Assert.AreEqual(i, sharpEdges[sharpEdges[i].Twin].Twin); } }
public void TestSegmentDicretization() { List<Point> inputPoint = new List<Point>() { new Point(5, 5) }; List<Segment> inputSegment = new List<Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the CLR voronoi VoronoiWrapper vw = new VoronoiWrapper(); foreach (var p in inputPoint) vw.AddPoint(p.X, p.Y); foreach (var s in inputSegment) vw.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); vw.ConstructVoronoi(); List<Tuple<int, int, bool, bool, List<int>, bool, short>> clrCells = vw.GetCells(); //Build the C# Voronoi BoostVoronoi bv = new BoostVoronoi(); foreach (var p in inputPoint) bv.AddPoint(p.X, p.Y); foreach (var s in inputSegment) bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); bv.Construct(); List<Vertex> vertices = bv.Vertices; List<Edge> sharpEdges = bv.Edges; List<Cell> sharpCells = bv.Cells; int testEdgeIndex = 2; for (int i = 0; i < sharpEdges.Count; i++) { if (sharpCells[sharpEdges[sharpEdges[i].Twin].Cell].SourceCategory == CellSourceCatory.SinglePoint && sharpCells[sharpEdges[i].Cell].Site == 1) testEdgeIndex = i; } Edge testEdge = sharpEdges[testEdgeIndex]; Vertex startVertex = vertices[testEdge.Start]; Vertex endVertex = vertices[testEdge.End]; List<Vertex> dvertices = bv.SampleCurvedEdge(testEdge, Distance.ComputeDistanceBetweenPoints(startVertex, endVertex) / 2); int lastDicretizedVertexIndex = dvertices.Count - 1; //Make sure that the end points are consistents Assert.AreEqual(dvertices[0].X, startVertex.X); Assert.AreEqual(dvertices[0].Y, startVertex.Y); Assert.AreEqual(dvertices[lastDicretizedVertexIndex].X, endVertex.X); Assert.AreEqual(dvertices[lastDicretizedVertexIndex].Y, endVertex.Y); Assert.AreEqual(dvertices[2].X, 2.5); Assert.AreEqual(dvertices[2].Y, 5); }
public void TestPrimaryEdges() { List<Point> inputPoint = new List<Point>() { new Point(5, 5) }; List<Segment> inputSegment = new List<Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the CLR voronoi VoronoiWrapper vw = new VoronoiWrapper(); foreach (var p in inputPoint) vw.AddPoint(p.X, p.Y); foreach (var s in inputSegment) vw.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); vw.ConstructVoronoi(); List<Tuple<int, int, bool, bool, List<int>, bool, short>> clrCells = vw.GetCells(); //Build the C# Voronoi BoostVoronoi bv = new BoostVoronoi(); foreach (var p in inputPoint) bv.AddPoint(p.X, p.Y); foreach (var s in inputSegment) bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); bv.Construct(); List<Vertex> vertices = bv.Vertices; List<Edge> sharpEdges = bv.Edges; int countPrimary = 0; int countSecondary = 0; int countFinite = 0; for (int i = 0; i < sharpEdges.Count; i++) { if (sharpEdges[i].IsPrimary) countPrimary++; if (sharpEdges[i].IsFinite) countFinite++; if (!sharpEdges[i].IsPrimary && sharpEdges[i].IsFinite) countSecondary++; } //8 finites from the center of the square corner + 8 edges arount the center point. Assert.AreEqual(countFinite, 16); //Check the number of secondary edge. Because this input is a square with a point in the center, the expected count is 0. Assert.AreEqual(countSecondary, 0); Assert.AreEqual(countPrimary, countFinite - countSecondary); }
public void TestGetCellVertices() { List<Point> inputPoint = new List<Point>() { new Point(5, 5) }; List<Segment> inputSegment = new List<Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the C# Voronoi BoostVoronoi bv = new BoostVoronoi(); foreach (var p in inputPoint) bv.AddPoint(p.X, p.Y); foreach (var s in inputSegment) bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); bv.Construct(); List<Vertex> vertices = bv.Vertices; List<Edge> sharpEdges = bv.Edges; List<Cell> cells = bv.Cells; for (int i = 0; i < cells.Count; i++) { if(!cells[i].IsOpen) { List<int> vertexIndexes = cells[i].GetVertices(ref sharpEdges); Assert.AreEqual(vertexIndexes.Count, 5); Assert.AreEqual(vertexIndexes[0], vertexIndexes[vertexIndexes.Count - 1]); } } }
public void TestFindInputSegmentSiteException() { List<Point> inputPoint = new List<Point>() { new Point(5, 5) }; List<Segment> inputSegment = new List<Segment>(); inputSegment.Add(new Segment(0, 0, 0, 10)); inputSegment.Add(new Segment(0, 0, 10, 0)); inputSegment.Add(new Segment(0, 10, 10, 10)); inputSegment.Add(new Segment(10, 0, 10, 10)); //Build the C# Voronoi BoostVoronoi bv = new BoostVoronoi(); foreach (var p in inputPoint) bv.AddPoint(p.X, p.Y); foreach (var s in inputSegment) bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); bv.Construct(); List<Vertex> vertices = bv.Vertices; List<Edge> sharpEdges = bv.Edges; List<Cell> cells = bv.Cells; for (int i = 0; i < cells.Count; i++) { if (cells[i].SourceCategory != CellSourceCatory.InitialSegment && cells[i].SourceCategory != CellSourceCatory.ReverseSegment) { bv.RetrieveInputSegment(cells[i]); } } }
// Execute: Execute the function given the array of the parameters public void Execute(IArray paramvalues, ITrackCancel trackcancel, IGPEnvironmentManager envMgr, IGPMessages message) { IFeatureClass outputFeatureClass = null; try { // get the input feature class IGPMultiValue inputFeatureClasses_Parameter = (IGPMultiValue)m_GPUtilities.UnpackGPValue(paramvalues.get_Element(0)); layer[] input_featureClasses = new layer[inputFeatureClasses_Parameter.Count]; for (int i = 0; i < inputFeatureClasses_Parameter.Count; i++) { IGPValue inputFeatureClass_Parameter = inputFeatureClasses_Parameter.get_Value(i); IFeatureClass inputFeatureClass; IQueryFilter inputQF; m_GPUtilities.DecodeFeatureLayer(inputFeatureClass_Parameter, out inputFeatureClass, out inputQF); input_featureClasses[i] = new layer() { featureclass = inputFeatureClass, qFilter = inputQF}; } if (input_featureClasses.Length == 0 || input_featureClasses.Any(w=> w.featureclass == null)) { message.AddError(2, "Could not open one or more input dataset."); return; } //IFields additionalFields = new FieldsClass(); //additionalFields.AddField(FEATURE_SOURCE_FIELD_NAME, esriFieldType.esriFieldTypeString); //additionalFields.AddField(FEATURE_ID_FIELD_NAME, esriFieldType.esriFieldTypeInteger); //additionalFields.AddField( // input_featureClasses[0].featureclass.Fields.get_Field( // input_featureClasses[0].featureclass.Fields.FindField( // input_featureClasses[0].featureclass.ShapeFieldName))); // create the output feature class IGPValue outputFeatureClass_Parameter = m_GPUtilities.UnpackGPValue(paramvalues.get_Element(1)); outputFeatureClass = GPHelperFunctions.CreateFeatureClass(outputFeatureClass_Parameter, envMgr); if (outputFeatureClass == null) { message.AddError(2, "Could not create output dataset."); return; } IGPString curveTypeParameter = (IGPString)m_GPUtilities.UnpackGPValue(paramvalues.get_Element(2)); ArcConstructionMethods method; if (!Enum.TryParse<ArcConstructionMethods>(curveTypeParameter.Value, true, out method)) { message.AddError(2, string.Format("The value {0} is not expected. Expected values are: {1}.", curveTypeParameter.Value, string.Join(",", Enum.GetNames(typeof(ArcConstructionMethods))))); return; } IStepProgressor stepPro = (IStepProgressor)trackcancel; GPHelperFunctions.dropSpatialIndex(outputFeatureClass); BoostVoronoi bv = new BoostVoronoi(100); double minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; List<site_key> point_sites = new List<site_key>(); List<site_key> segment_sites = new List<site_key>(); for (short i = 0; i < input_featureClasses.Length; i++) { layer l = input_featureClasses[i]; int featcount = l.featureclass.FeatureCount(l.qFilter); stepPro.MinRange = 0; stepPro.MaxRange = featcount; stepPro.StepValue = (1); stepPro.Message = "Reading features"; stepPro.Position = 0; stepPro.Show(); IFeatureCursor cursor = null; IFeature row = null; try { cursor = l.featureclass.Search(l.qFilter, false); while ((row = cursor.NextFeature()) != null) { stepPro.Step(); IPoint point = row.Shape as IPoint; if (point != null) { double X = point.X; double Y = point.Y; minX = Math.Min(minX, X); maxX = Math.Max(maxX, X); minY = Math.Min(minY, Y); maxY = Math.Max(maxY, Y); bv.AddPoint(point.X, point.Y); point_sites.Add(new site_key(i, row.OID)); } IMultipoint multipoint = row.Shape as IMultipoint; if (multipoint != null) { IPointCollection pointCollection = (IPointCollection)multipoint; IEnumVertex vertices = pointCollection.EnumVertices; IPoint vertex = null; int part, index; vertices.Next(out vertex, out part, out index); minX = Math.Min(minX, multipoint.Envelope.XMin); maxX = Math.Max(maxX, multipoint.Envelope.XMax); minY = Math.Min(minY, multipoint.Envelope.YMin); maxY = Math.Max(maxY, multipoint.Envelope.YMax); while (vertex != null) { bv.AddPoint(vertex.X, vertex.Y); point_sites.Add(new site_key(i, row.OID)); vertices.Next(out vertex, out part, out index); } } IPolyline polyline = row.Shape as IPolyline; if (polyline != null) { double fromX = polyline.FromPoint.X; double fromY = polyline.FromPoint.Y; double toX = polyline.ToPoint.X; double toY = polyline.ToPoint.Y; if (toX < fromX) { minX = Math.Min(minX, toX); maxX = Math.Max(maxX, fromX); } else { minX = Math.Min(minX, fromX); maxX = Math.Max(maxX, toX); } if (toY < fromY) { minY = Math.Min(minY, toY); maxY = Math.Max(maxY, fromY); } else { minY = Math.Min(minY, fromY); maxY = Math.Max(maxY, toY); } bv.AddSegment( polyline.FromPoint.X, polyline.FromPoint.Y, polyline.ToPoint.X, polyline.ToPoint.Y ); segment_sites.Add(new site_key(i, row.OID)); } Marshal.ReleaseComObject(row); } } finally { if (row != null) Marshal.ReleaseComObject(row); if (cursor != null) Marshal.ReleaseComObject(cursor); stepPro.Hide(); } } message.AddMessage(String.Format("{0}, {1} -> {2}, {3}", minX, minY, maxX, maxY)); int width = Math.Max((int)((maxX - minX) * 0.1), 1); int height = Math.Max((int)((maxY - minY) * 0.1), 1); maxX = maxX + width; minX = minX - width; maxY = maxY + height; minY = minY - height; message.AddMessage(String.Format("{0}, {1} -> {2}, {3}", minX, minY, maxX, maxY)); bv.AddSegment(minX, minY, maxX, minY); segment_sites.Add(new site_key(-1, -1)); bv.AddSegment(maxX, minY, maxX, maxY); segment_sites.Add(new site_key(-1, -1)); bv.AddSegment(maxX, maxY, minX, maxY); segment_sites.Add(new site_key(-1, -1)); bv.AddSegment(minX, maxY, minX, minY); segment_sites.Add(new site_key(-1, -1)); stepPro.Message = "Solve Voronoi"; stepPro.MaxRange = 0; stepPro.MaxRange = 0; stepPro.Show(); bv.Construct(); stepPro.Hide(); int featureSourceIndx = outputFeatureClass.Fields.FindField(FEATURE_SOURCE_FIELD_NAME); int featureIDIndx = outputFeatureClass.Fields.FindField(FEATURE_ID_FIELD_NAME); IFeatureCursor inserts = null; IFeatureBuffer buffer = null; try { object missing = Type.Missing; ISpatialReference spatialReference = ((IGeoDataset)outputFeatureClass).SpatialReference; inserts = outputFeatureClass.Insert(false); buffer = outputFeatureClass.CreateFeatureBuffer(); List<Cell> cells = bv.Cells; message.AddMessage(string.Format("{0} cells calculated", cells.Count)); List<Edge> edges = bv.Edges; message.AddMessage(string.Format("{0} edges calculated", edges.Count)); List<Vertex> vertices = bv.Vertices; message.AddMessage(string.Format("{0} vertexes calculated", vertices.Count)); stepPro.Message = "Write cells"; stepPro.MaxRange = 0; stepPro.MaxRange = cells.Count; stepPro.Show(); for (int cellIndex = 0; cellIndex < cells.Count; cellIndex++) { try { if(cellIndex % 5000 == 0) message.AddMessage(String.Format("{0}. {1} cells processed.", DateTime.Now, cellIndex)); Cell cell = cells[cellIndex]; int currentSite = cell.Site; IGeometryCollection geometryCollection = new GeometryBagClass() { SpatialReference = spatialReference }; //ignores any sliver cells if (cell.IsOpen || cell.EdgesIndex.Count < 3) continue; ISegmentCollection segmentCollection = createSegments(cell, bv, method, spatialReference); if (((IArea)segmentCollection).Area <= 0) { message.AddMessage("A invalid geometry has been detected, try reversing the orientation."); ISegmentCollection reversed_segmentCollection = new PolygonClass() { SpatialReference = spatialReference }; for (int i = segmentCollection.SegmentCount - 1; i >= 0; i--) { ISegment segment = (ISegment)segmentCollection.get_Segment(i); segment.ReverseOrientation(); reversed_segmentCollection.AddSegment(segment); } segmentCollection = reversed_segmentCollection; } ((IPolygon)segmentCollection).SpatialReference = spatialReference; if (((IArea)segmentCollection).Area <= 0) { message.AddWarning("An empty shell has been created"); for (int i = 0; i < segmentCollection.SegmentCount; i++) { ISegment segment = (ISegment)segmentCollection.get_Segment(i); message.AddMessage(String.Format("From {0}, {1} To {2},{3}", segment.FromPoint.X, segment.FromPoint.Y, segment.ToPoint.X, segment.ToPoint.Y)); } } //set attributes site_key sk = (currentSite >= point_sites.Count) ? segment_sites[currentSite - point_sites.Count] : point_sites[currentSite]; if (!sk.isEmpty) { buffer.set_Value(featureSourceIndx, input_featureClasses[sk.featureClassIndex].featureclass.AliasName); buffer.set_Value(featureIDIndx, sk.objectID); } else { buffer.set_Value(featureSourceIndx, DBNull.Value); buffer.set_Value(featureIDIndx, DBNull.Value); } IPolygon voronoiPolygon = (IPolygon)segmentCollection; buffer.Shape = (IPolygon)voronoiPolygon; inserts.InsertFeature(buffer); } catch (Exception e) { message.AddWarning("Failed to create a cell"); } } } finally { if (buffer != null) Marshal.ReleaseComObject(buffer); if (inserts != null) Marshal.ReleaseComObject(inserts); } GPHelperFunctions.createSpatialIndex(outputFeatureClass); } catch (Exception exx) { message.AddError(2, exx.Message); message.AddMessage(exx.ToString()); } finally { if (outputFeatureClass != null) Marshal.ReleaseComObject(outputFeatureClass); ((IProgressor)trackcancel).Hide(); } }