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; }
public void TestCellsCount() { 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)); input.Add(new Segment(0, 0, 5, 5)); input.Add(new Segment(5, 5, 10, 10)); //Build the CLR voronoi VoronoiWrapper vw = new VoronoiWrapper(); foreach (var s in input) 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 s in input) bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); bv.Construct(); List<Cell> sharpCells = bv.Cells; //Test that the outputs have the same length Assert.AreEqual(clrCells.Count, sharpCells.Count); }
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 TestVerticesSequence() { 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)); input.Add(new Segment(0, 0, 5, 5)); input.Add(new Segment(5, 5, 10, 10)); //Build the CLR voronoi VoronoiWrapper vw = new VoronoiWrapper(); foreach (var s in input) vw.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); vw.ConstructVoronoi(); List<Tuple<double, double>> clrVertices = vw.GetVertices(); //Build the C# Voronoi BoostVoronoi bv = new BoostVoronoi(); foreach (var s in input) bv.AddSegment(s.Start.X, s.Start.Y, s.End.X, s.End.Y); bv.Construct(); List<Vertex> sharpVertices = bv.Vertices; //Test that the outputs have the same length Assert.AreEqual(clrVertices.Count, sharpVertices.Count); for (int i = 0; i < sharpVertices.Count; i++) { Assert.AreEqual(clrVertices[i].Item1, sharpVertices[i].X); Assert.AreEqual(clrVertices[i].Item2, sharpVertices[i].Y); } }
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]); } } }
private ISegmentCollection createSegments(Cell cell,BoostVoronoi bv,ArcConstructionMethods method,ISpatialReference spatialReference) { List<Cell> cells = bv.Cells; List<Edge> edges = bv.Edges; List<Vertex> vertices = bv.Vertices; IPoint previousEndPoint = null; ISegmentCollection segmentCollection = new PolygonClass() { SpatialReference = spatialReference }; // As per boost documentation, edges are returned in counter clockwise (CCW) rotation. // voronoi_edge_type* next() Returns the pointer to the CCW next edge within the corresponding Voronoi cell. Edges not necessarily share a common vertex (e.g. infinite edges). for (int i = cell.EdgesIndex.Count - 1; i >= 0; i--) { Edge edge = edges[cell.EdgesIndex[i]]; //If the vertex index equals -1, it means the edge is infinite. It is impossible to print the coordinates. if (!edge.IsFinite && edge.End < 0) { // this is the ending portion of a pair of infinite edges, file the previous edge with Start >= 0 Edge previous = null; for (int k = i + 1; k < cell.EdgesIndex.Count; k++) { previous = edges[cell.EdgesIndex[k]]; if (previous.End >= 0) break; previous = null; } if (previous == null) { for (int k = 0; k < i; k++) { previous = edges[cell.EdgesIndex[k]]; if (previous.End >= 0) break; previous = null; } } if (previous == null) throw new Exception("No outbound infinite edge could be found"); //Add a straight line segment Vertex start = vertices[previous.End]; IPoint FromPoint = new PointClass() { X = start.X, Y = start.Y, SpatialReference = spatialReference }; Vertex end = vertices[edge.Start]; IPoint ToPoint = new PointClass() { X = end.X, Y = end.Y, SpatialReference = spatialReference }; segmentCollection.AddSegment(new LineClass() { FromPoint = FromPoint, ToPoint = ToPoint, SpatialReference = spatialReference }); previousEndPoint = ToPoint; } else if (edge.IsFinite) { Vertex start = vertices[edge.End]; IPoint FromPoint = new PointClass() { X = start.X, Y = start.Y, SpatialReference = spatialReference }; if (previousEndPoint != null) { if ((Math.Abs(previousEndPoint.X - FromPoint.X) > 0.05 || Math.Abs(previousEndPoint.X - FromPoint.X) > 0.05)) throw new Exception("Significant change between last end point and current start point"); else FromPoint = previousEndPoint; } Vertex end = vertices[edge.Start]; IPoint ToPoint = new PointClass() { X = end.X, Y = end.Y, SpatialReference = spatialReference }; if (method == ArcConstructionMethods.Straight || edge.IsLinear) { segmentCollection.AddSegment(new LineClass() { FromPoint = FromPoint, ToPoint = ToPoint, SpatialReference = spatialReference }); previousEndPoint = ToPoint; } else { // We need three points, use start, end, mid-point between focus and directrix Cell twinCell = cells[edges[edge.Twin].Cell]; VPoint pointSite; VSegment lineSite; if (cell.ContainsPoint && twinCell.ContainsSegment) { pointSite = bv.RetrieveInputPoint(cell); lineSite = bv.RetrieveInputSegment(twinCell); } else if (cell.ContainsSegment && twinCell.ContainsPoint) { pointSite = bv.RetrieveInputPoint(twinCell); lineSite = bv.RetrieveInputSegment(cell); } else { throw new Exception("Invalid edge, curves should only be present between a point and a line"); } double scaleFactor = Convert.ToDouble(bv.ScaleFactor); IPoint aoPointSite = new Point() { X = Convert.ToDouble(pointSite.X) / scaleFactor, Y = Convert.ToDouble(pointSite.Y) / scaleFactor, SpatialReference = spatialReference }; ISegment aoLineSite = new LineClass() { FromPoint = new PointClass() { X = Convert.ToDouble(lineSite.Start.X) / scaleFactor, Y = Convert.ToDouble(lineSite.Start.Y) / scaleFactor, SpatialReference = spatialReference }, ToPoint = new PointClass() { X = Convert.ToDouble(lineSite.End.X) / scaleFactor, Y = Convert.ToDouble(lineSite.End.Y) / scaleFactor, SpatialReference = spatialReference }, SpatialReference = spatialReference }; if (method == ArcConstructionMethods.Approximate) { List<Vertex> sampledVerticed = null; try { sampledVerticed = bv.SampleCurvedEdge(edge, aoLineSite.Length / 10); } catch (FocusOnDirectixException e) { //Log any exception here is required sampledVerticed = new List<Vertex>() { start, end }; } catch (UnsolvableVertexException e) { sampledVerticed = new List<Vertex>() { start, end }; } sampledVerticed.Reverse(); List<IPoint> discretizedEdge = sampledVerticed.Select( p => new Point() { X = p.X, Y = p.Y } ).ToList<IPoint>(); IPoint prev = discretizedEdge[0]; foreach (IPoint v in discretizedEdge.Skip(1)) { segmentCollection.AddSegment(new LineClass() { FromPoint = new Point() { X = prev.X, Y = prev.Y, SpatialReference = spatialReference }, ToPoint = new Point() { X = v.X, Y = v.Y, SpatialReference = spatialReference }, SpatialReference = spatialReference }); prev = v; } previousEndPoint = discretizedEdge.Last(); } else if (method == ArcConstructionMethods.Circular) { IPoint nearPoint = ((IProximityOperator)aoLineSite).ReturnNearestPoint(aoPointSite, esriSegmentExtension.esriNoExtension); IPoint midpoint = new PointClass() { X = (nearPoint.X + aoPointSite.X) / 2, Y = (nearPoint.Y + aoPointSite.Y) / 2, SpatialReference = spatialReference }; IConstructCircularArc constArc = new CircularArcClass() { SpatialReference = spatialReference }; constArc.ConstructThreePoints(FromPoint, midpoint, ToPoint, false); ICircularArc arc = (ICircularArc)constArc; if (!arc.IsMinor) { constArc = new CircularArcClass() { SpatialReference = spatialReference }; constArc.ConstructEndPointsRadius(FromPoint, ToPoint, !arc.IsCounterClockwise, arc.Radius, true); arc = (ICircularArc)constArc; } segmentCollection.AddSegment((ISegment)arc); previousEndPoint = arc.ToPoint; } else if (method == ArcConstructionMethods.Ellipse) { IPoint nearPoint = ((IProximityOperator)aoLineSite).ReturnNearestPoint(aoPointSite, esriSegmentExtension.esriExtendTangents); nearPoint.SpatialReference = spatialReference; ILine lineToFocus = new LineClass() { FromPoint = nearPoint, ToPoint = aoPointSite, SpatialReference = spatialReference }; ILine semiMajor = new LineClass() { SpatialReference = spatialReference }; lineToFocus.QueryTangent(esriSegmentExtension.esriExtendTangentAtTo, 1, true, 100 * lineToFocus.Length, semiMajor); IPoint center = new PointClass() { X = (semiMajor.FromPoint.X + semiMajor.ToPoint.X) / 2, Y = (semiMajor.FromPoint.Y + semiMajor.ToPoint.Y) / 2, SpatialReference = spatialReference }; double minor_length = Math.Sqrt( Math.Pow(distance(semiMajor.FromPoint, ToPoint) + distance(semiMajor.ToPoint, ToPoint), 2) - Math.Pow(semiMajor.Length, 2)); IEllipticArc arc = new EllipticArcClass() { SpatialReference = spatialReference }; double rotation = lineToFocus.Angle; double from = GetAngle(center, FromPoint); arc.PutCoords(false, center, FromPoint, ToPoint, rotation, minor_length / semiMajor.Length, esriArcOrientation.esriArcMinor); segmentCollection.AddSegment((ISegment)arc); previousEndPoint = arc.ToPoint; } } } } return segmentCollection; }
// 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(); } }