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); }
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; }