private static void AddVerticalBorder(BoostVoronoi voronoi, RTree <Edge> wallsTree, IReadOnlyList <int> border, int x, int maxY) { var index = 0; if (!border.Any()) { voronoi.AddSegment(x, 0, x, maxY); wallsTree.Insert(new Edge { Start = new Point2D(x, 0), End = new Point2D(x, maxY) }, new RTree <Edge> .Envelope(x, 0, x, maxY)); return; } var firstY = border[index++]; if (firstY != 0) { var y2 = index >= border.Count ? maxY : border[index++]; voronoi.AddSegment(x, firstY, x, y2); wallsTree.Insert(new Edge { Start = new Point2D(x, firstY), End = new Point2D(x, y2) }, new RTree <Edge> .Envelope(x, firstY, x, y2)); } while (index < border.Count) { var y1 = border[index++]; var y2 = index >= border.Count ? maxY : border[index++]; voronoi.AddSegment(x, y1, x, y2); wallsTree.Insert(new Edge { Start = new Point2D(x, y1), End = new Point2D(x, y2) }, new RTree <Edge> .Envelope(x, y1, x, y2)); } }
private static void AddHorizontalBorder(BoostVoronoi voronoi, RTree <Edge> wallsTree, IReadOnlyList <int> border, int y, int maxX) { var index = 0; if (!border.Any()) { voronoi.AddSegment(0, y, maxX, y); wallsTree.Insert(new Edge { Start = new Point2D(0, y), End = new Point2D(maxX, y) }, new RTree <Edge> .Envelope(0, y, maxX, y)); return; } var firstX = border[index++]; if (firstX != 0) { var x2 = index >= border.Count ? maxX : border[index++]; voronoi.AddSegment(firstX, y, x2, y); wallsTree.Insert(new Edge { Start = new Point2D(firstX, y), End = new Point2D(x2, y) }, new RTree <Edge> .Envelope(firstX, y, x2, y)); } while (index < border.Count) { var x1 = border[index++]; var x2 = index >= border.Count ? maxX : border[index++]; voronoi.AddSegment(x1, y, x2, y); wallsTree.Insert(new Edge { Start = new Point2D(x1, y), End = new Point2D(x2, y) }, new RTree <Edge> .Envelope(x1, y, x2, y)); } }
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(); using (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(String.Format("Vertices: {0}, Edges: {1}, Cells: {2}", bv.CountVertices, bv.CountEdges, bv.CountCells)); Console.WriteLine("Time elapsed: {0:hh\\:mm\\:ss\\:ff}.", stopwatch.Elapsed); //bv.Clear(); } inputPoints.Clear(); inputSegments.Clear(); }
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 TestInvalidCellIndexException() { 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 using (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(); bv.GetCell(bv.CountCells); } }
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 C# Voronoi using (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(); int countPrimary = 0; int countSecondary = 0; int countFinite = 0; for (long i = 0; i < bv.CountEdges; i++) { Edge edge = bv.GetEdge(i); if (edge.IsPrimary) { countPrimary++; } if (edge.IsFinite) { countFinite++; } if (!edge.IsPrimary && edge.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); } }
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 using (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 for (long i = 0; i < bv.CountCells; i++) { Cell cell = bv.GetCell(i); Console.Out.WriteLine(String.Format("Cell Identifier {0}. Is open = {1}", cell.Index, cell.IsOpen)); foreach (var edgeIndex in cell.EdgesIndex) { Edge edge = bv.GetEdge(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 = bv.GetVertex(edge.Start); Vertex end = bv.GetVertex(edge.End); Console.Out.WriteLine( String.Format(" From:{0}, To: {1}", start.ToString(), end.ToString())); } } } } Console.In.ReadLine(); }
public void TestFindInputPointSiteException() { 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 using (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(); for (long i = 0; i < bv.CountCells; i++) { Cell cell = bv.GetCell(i); if (cell.SourceCategory != CellSourceCatory.SegmentStartPoint && cell.SourceCategory != CellSourceCatory.SegmentEndPoint && cell.SourceCategory != CellSourceCatory.SinglePoint) { bv.RetrieveInputPoint(cell); } } } }
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 using (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(); for (long i = 0; i < bv.CountCells; i++) { Cell cell = bv.GetCell(i); if (!cell.IsOpen) { List <long> vertexIndexes = cell.VerticesIndex; Assert.AreEqual(vertexIndexes.Count, 5); Assert.AreEqual(vertexIndexes[0], vertexIndexes[vertexIndexes.Count - 1]); } } } }
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 C# Voronoi using (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(); //Test twin reciprocity for (long i = 0; i < bv.CountEdges; i++) { Edge edge = bv.GetEdge(i); Edge twin = bv.GetEdge(edge.Twin); Assert.AreEqual(i, twin.Twin); } } }
public static IReadOnlyList <TerrainNode> Analyze <TNode>(Map2D <TNode> map, Func <TNode, bool> isBlocking, int pruneDistanceToObstacleSquared, int maxDistanceToMergeSquared) { var tracingResult = ComponentLabeling.Trace(map, node => isBlocking(node) ? 1 : 0); var contours = new List <List <Point2D> >(); foreach (var blob in tracingResult.Blobs) { contours.AddRange( new[] { blob.ExternalContour }.Concat(blob.InternalContours).Select( points => DouglasPeucker.Simplify(points.ToList(), 2 * 2, DistanceSquared))); } var edges = new List <Edge>(); var leftBorder = new List <int>(); var rightBorder = new List <int>(); var topBorder = new List <int>(); var bottomBorder = new List <int>(); var wallsTree = new RTree <Edge>(5, 9); using (var voronoi = new BoostVoronoi()) { foreach (var contour in contours) { var startPoint = contour.First(); foreach (var point in contour.Skip(1)) { voronoi.AddSegment((int)startPoint.X, (int)startPoint.Y, (int)point.X, (int)point.Y); wallsTree.Insert(new Edge { Start = startPoint, End = point }, new RTree <Edge> .Envelope(startPoint, point)); if ((int)startPoint.X == 0 && (int)point.X == 0) { leftBorder.Add((int)startPoint.Y); leftBorder.Add((int)point.Y); } if ((int)startPoint.X == map.Width - 1 && (int)point.X == map.Width - 1) { rightBorder.Add((int)startPoint.Y); rightBorder.Add((int)point.Y); } if ((int)startPoint.Y == 0 && (int)point.Y == 0) { topBorder.Add((int)startPoint.X); topBorder.Add((int)point.X); } if ((int)startPoint.Y == map.Height - 1 && (int)point.Y == map.Height - 1) { bottomBorder.Add((int)startPoint.X); bottomBorder.Add((int)point.X); } startPoint = point; } } AddVerticalBorder(voronoi, wallsTree, leftBorder.OrderBy(x => x).ToList(), 0, map.Height - 1); AddVerticalBorder(voronoi, wallsTree, rightBorder.OrderBy(x => x).ToList(), map.Width - 1, map.Height - 1); AddHorizontalBorder(voronoi, wallsTree, topBorder.OrderBy(x => x).ToList(), 0, map.Width - 1); AddHorizontalBorder(voronoi, wallsTree, bottomBorder.OrderBy(x => x).ToList(), map.Height - 1, map.Width - 1); var visitedTwins = new List <long>(); voronoi.Construct(); for (long i = 0; i < voronoi.CountEdges; i++) { var edge = voronoi.GetEdge(i); if (!edge.IsPrimary || !edge.IsFinite || visitedTwins.Contains(edge.Twin)) { continue; } visitedTwins.Add(edge.Twin); var start = voronoi.GetVertex(edge.Start); var end = voronoi.GetVertex(edge.End); if (double.IsNaN(start.X) || double.IsNaN(start.Y) || double.IsNaN(end.X) || double.IsNaN(end.Y)) { continue; } if (edges.Any( e => (int)e.Start.X == (int)start.X && (int)e.Start.Y == (int)start.Y && (int)e.End.X == (int)end.X && (int)e.End.Y == (int)end.Y || (int)e.Start.X == (int)end.X && (int)e.Start.Y == (int)end.Y && (int)e.End.X == (int)start.X && (int)e.End.Y == (int)start.Y)) { continue; } edges.Add(new Edge { Start = new Point2D((int)start.X, (int)start.Y), End = new Point2D((int)end.X, (int)end.Y) }); } } var walkableEdges = edges.Where(edge => IsOnNonBlocking(edge, map, isBlocking)).ToList(); var nodes = new List <InternalNode>(); foreach (var node in walkableEdges) { if (node.Start == node.End) { continue; } var startNode = nodes.Find(x => x.Point == node.Start); if (startNode == null) { startNode = CreateNode(wallsTree, node.Start); nodes.Add(startNode); } var endNode = nodes.Find(x => x.Point == node.End); if (endNode == null) { endNode = CreateNode(wallsTree, node.End); nodes.Add(endNode); } startNode.Neighbors.Add(endNode); endNode.Neighbors.Add(startNode); } PruneNodes(nodes, pruneDistanceToObstacleSquared); GetPointsOfInterest(nodes, pruneDistanceToObstacleSquared, maxDistanceToMergeSquared); var mergedNodes = MergeNodes(nodes, maxDistanceToMergeSquared); return(MapToTerrainNodes(mergedNodes, wallsTree)); }
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(); } }
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 C# Voronoi using (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(); long testEdgeIndex = 2; for (long i = 0; i < bv.CountEdges; i++) { Edge edge = bv.GetEdge(i); Edge twin = bv.GetEdge(edge.Twin); Cell edgeCell = bv.GetCell(edge.Cell); Cell twinCell = bv.GetCell(twin.Cell); if (twinCell.SourceCategory == CellSourceCatory.SinglePoint && edgeCell.Site == 1) { testEdgeIndex = i; } } Edge testEdge = bv.GetEdge(testEdgeIndex); Vertex startVertex = bv.GetVertex(testEdge.Start); Vertex endVertex = bv.GetVertex(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); } }