Пример #1
0
        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);
        }
Пример #2
0
        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;
        }