Exemplo n.º 1
0
        /// <summary>
        /// Defines links for this face. A prior call to <c>SetLine</c> is required.
        /// </summary>
        /// <param name="prev">The preceding face (after it has been processed via a call to
        /// <c>SetLine</c>, Must refer to the same polygon as this face.</param>
        /// <returns>The links (the number of array elements will equal the value that came
        /// back from the <c>SetLine</c> call)</returns>
        internal PolygonLink[] CreateLinks(PolygonFace prev)
        {
            Debug.Assert(m_Polygon != null);
            Debug.Assert(m_Divider != null);
            Debug.Assert(prev.Divider != null);
            Debug.Assert(Object.ReferenceEquals(prev.Polygon, m_Polygon));

            // Try to obtain a point feature at the beginning of this face.
            ISpatialIndex index      = CadastralMapModel.Current.Index;
            PointFeature  beginPoint = new FindPointQuery(index, m_Begin).Result;

            // If the polygon to the left of the this face? (if so, curve-related
            // things may need to be reversed below)
            bool isPolLeft = (m_Divider.Left == m_Polygon);

            // Default geometric info we need to define
            bool   isCurveEnd = false;
            bool   isRadial   = false;
            double bearing    = 0.0;
            double angle      = 0.0;

            // Is the position at the beginning of this face the start
            // or end of a circular arc (points between 2 curves (on
            // compound curve) are NOT considered to be curve ends). Note
            // that the line could either be a CircularArc, or a topological
            // section based on a circular arc.

            ICircularArcGeometry prevArc = (prev.Divider.LineGeometry as ICircularArcGeometry);
            ICircularArcGeometry thisArc = (m_Divider.LineGeometry as ICircularArcGeometry);
            bool isPrevCurve             = (prevArc != null);
            bool isThisCurve             = (thisArc != null);

            isCurveEnd = (isPrevCurve != isThisCurve);

            // If we are dealing with a point between two curves try to
            // set the curve parameters and, if successful, we will treat
            // the point as a radial point.

            if (isPrevCurve && isThisCurve)
            {
                isRadial = true;

                // Get the curve parameters...

                IPosition prevcen = prevArc.Circle.Center;
                double    prevrad = prevArc.Circle.Radius;

                IPosition thiscen = thisArc.Circle.Center;
                double    thisrad = thisArc.Circle.Radius;

                // We only need to know the sense for one of the arcs
                bool iscw = thisArc.IsClockwise;

                // If the 2 curves do not have the same centre and radius,
                // see if they are really close (to the nearest centimeter
                // on the ground). In that case, use the average values for
                // the 2 curves. If they really are different curves, don't
                // treat this as a radial curve point -- treat it as a
                // curve end instead.

                IPosition centre = null;            // The centre to actually use

                if (!(prevcen == thiscen && Math.Abs(prevrad - thisrad) < Constants.TINY))
                {
                    double xc1 = prevcen.X;
                    double yc1 = prevcen.Y;
                    double xc2 = thiscen.X;
                    double yc2 = thiscen.Y;
                    double dxc = xc2 - xc1;
                    double dyc = yc2 - yc1;

                    if (Math.Abs(dxc) < 0.01 &&
                        Math.Abs(dyc) < 0.01 &&
                        Math.Abs(prevrad - thisrad) < 0.01)
                    {
                        // Close enough
                        centre = new Position(xc1 + dxc * 0.5, yc1 + dyc * 0.5);
                    }
                    else
                    {
                        isRadial   = false;
                        isCurveEnd = true;
                    }
                }
                else
                {
                    centre = prevcen;
                }

                // If the centre and radius were the same (or close enough),
                // define the radial bearing from the centre of the circle.
                // If the polygon is actually on the other side, reverse the
                // bearing so that it's directed INTO the polygon.

                if (isRadial)
                {
                    Debug.Assert(centre != null);
                    bearing = Geom.BearingInRadians(centre, m_Begin);
                    angle   = 0.0;
                    if (iscw != isPolLeft)
                    {
                        bearing += Constants.PI;
                    }
                }
            }

            // If we're not dealing with a radial curve (or we have curves that
            // don't appear to be radial)
            if (!isRadial)
            {
                // Get the clockwise angle from the last position of the
                // preceding face to the first position after the start
                // of this face. Since info is held in a clockwise cycle
                // around the polygon, this will always give us the exterior
                // angle.
                Turn reference = new Turn(m_Begin, prev.TailReference);
                angle = reference.GetAngleInRadians(this.HeadReference);

                // Define the bearing to use for projecting the point. It's
                // in the middle of the angle, but projected into the polygon.
                bearing = reference.BearingInRadians + angle * 0.5 + Constants.PI;
            }

            // Initialize the link at the start of the face
            List <PolygonLink> links = new List <PolygonLink>();
            PolygonLink        link  = new PolygonLink(beginPoint, isCurveEnd, isRadial, bearing, angle);

            links.Add(link);

            // Initialize links for any extra points
            if (m_ExtraPoints != null)
            {
                // Intermediate points can never be curve ends
                isCurveEnd = false;

                // If the face is a curve, they're radial points
                isRadial = isThisCurve;

                // Note any curve info
                double    radius;
                IPosition centre = null;
                bool      iscw   = false;

                if (isRadial)
                {
                    Debug.Assert(m_Divider.Line.LineGeometry is ICircularArcGeometry);
                    ICircularArcGeometry arc = (m_Divider.Line.LineGeometry as ICircularArcGeometry);
                    centre = arc.Circle.Center;
                    radius = arc.Circle.Radius;
                    iscw   = arc.IsClockwise;
                    angle  = 0.0;
                }

                for (uint i = 0; i < m_ExtraPoints.Length; i++)
                {
                    //IPointGeometry loc = m_ExtraPoints[i].Geometry;
                    PointFeature loc = m_ExtraPoints[i];

                    // Figure out the orientation bearing for the point
                    if (isRadial)
                    {
                        Debug.Assert(centre != null);
                        bearing = Geom.BearingInRadians(centre, loc);
                        if (iscw != isPolLeft)
                        {
                            bearing += Constants.PI;
                        }
                    }
                    else
                    {
                        // Get the exterior clockwise angle

                        IPointGeometry back;
                        IPointGeometry fore;

                        if (i == 0)
                        {
                            back = m_Begin;
                        }
                        else
                        {
                            back = m_ExtraPoints[i - 1].Geometry;
                        }

                        if (i == (m_ExtraPoints.Length - 1))
                        {
                            fore = m_End;
                        }
                        else
                        {
                            fore = m_ExtraPoints[i + 1].Geometry;
                        }


                        Turn reference = new Turn(loc, back);
                        angle = reference.GetAngleInRadians(fore);

                        // Define the bearing to use for projecting the point. It's
                        // in the middle of the angle, but projected into the polygon.
                        bearing = reference.BearingInRadians + angle * 0.5 + Constants.PI;
                    }

                    link = new PolygonLink(m_ExtraPoints[i], isCurveEnd, isRadial, bearing, angle);
                    links.Add(link);
                }
            }

            return(links.ToArray());
        }
Exemplo n.º 2
0
        /// <summary>
        /// Defines links for this face. A prior call to <c>SetLine</c> is required.
        /// </summary>
        /// <param name="prev">The preceding face (after it has been processed via a call to
        /// <c>SetLine</c>, Must refer to the same polygon as this face.</param>
        /// <returns>The links (the number of array elements will equal the value that came
        /// back from the <c>SetLine</c> call)</returns>
        internal PolygonLink[] CreateLinks(PolygonFace prev)
        {
            Debug.Assert(m_Polygon!=null);
            Debug.Assert(m_Divider!=null);
            Debug.Assert(prev.Divider!=null);
            Debug.Assert(Object.ReferenceEquals(prev.Polygon, m_Polygon));

            // Try to obtain a point feature at the beginning of this face.
            ISpatialIndex index = CadastralMapModel.Current.Index;
            PointFeature beginPoint = new FindPointQuery(index, m_Begin).Result;

            // If the polygon to the left of the this face? (if so, curve-related
            // things may need to be reversed below)
            bool isPolLeft = (m_Divider.Left == m_Polygon);

            // Default geometric info we need to define
            bool isCurveEnd = false;
            bool isRadial = false;
            double bearing = 0.0;
            double angle = 0.0;

            // Is the position at the beginning of this face the start
            // or end of a circular arc (points between 2 curves (on
            // compound curve) are NOT considered to be curve ends). Note
            // that the line could either be a CircularArc, or a topological
            // section based on a circular arc.

            ICircularArcGeometry prevArc = (prev.Divider.LineGeometry as ICircularArcGeometry);
            ICircularArcGeometry thisArc = (m_Divider.LineGeometry as ICircularArcGeometry);
            bool isPrevCurve = (prevArc!=null);
            bool isThisCurve = (thisArc!=null);
            isCurveEnd = (isPrevCurve!=isThisCurve);

            // If we are dealing with a point between two curves try to
            // set the curve parameters and, if successful, we will treat
            // the point as a radial point.

            if (isPrevCurve && isThisCurve)
            {
                isRadial = true;

                // Get the curve parameters...

                IPosition prevcen = prevArc.Circle.Center;
                double prevrad = prevArc.Circle.Radius;

                IPosition thiscen = thisArc.Circle.Center;
                double thisrad = thisArc.Circle.Radius;

                // We only need to know the sense for one of the arcs
                bool iscw = thisArc.IsClockwise;

                // If the 2 curves do not have the same centre and radius,
                // see if they are really close (to the nearest centimeter
                // on the ground). In that case, use the average values for
                // the 2 curves. If they really are different curves, don't
                // treat this as a radial curve point -- treat it as a
                // curve end instead.

                IPosition centre = null;	    // The centre to actually use

                if (!(prevcen==thiscen && Math.Abs(prevrad-thisrad)<Constants.TINY))
                {
                    double xc1 = prevcen.X;
                    double yc1 = prevcen.Y;
                    double xc2 = thiscen.X;
                    double yc2 = thiscen.Y;
                    double dxc = xc2-xc1;
                    double dyc = yc2-yc1;

                    if (Math.Abs(dxc)<0.01 &&
                        Math.Abs(dyc)<0.01 &&
                        Math.Abs(prevrad-thisrad)<0.01)
                    {
                        // Close enough
                        centre = new Position(xc1+dxc*0.5, yc1+dyc*0.5);
                    }
                    else
                    {
                        isRadial = false;
                        isCurveEnd = true;
                    }
                }
                else
                    centre = prevcen;

                // If the centre and radius were the same (or close enough),
                // define the radial bearing from the centre of the circle.
                // If the polygon is actually on the other side, reverse the
                // bearing so that it's directed INTO the polygon.

                if (isRadial)
                {
                    Debug.Assert(centre!=null);
                    bearing = Geom.BearingInRadians(centre, m_Begin);
                    angle = 0.0;
                    if (iscw  != isPolLeft)
                        bearing += Constants.PI;
                }
            }

            // If we're not dealing with a radial curve (or we have curves that
            // don't appear to be radial)
            if (!isRadial)
            {
                // Get the clockwise angle from the last position of the
                // preceding face to the first position after the start
                // of this face. Since info is held in a clockwise cycle
                // around the polygon, this will always give us the exterior
                // angle.
                Turn reference = new Turn(m_Begin, prev.TailReference);
                angle = reference.GetAngleInRadians(this.HeadReference);

                // Define the bearing to use for projecting the point. It's
                // in the middle of the angle, but projected into the polygon.
                bearing = reference.BearingInRadians + angle*0.5 + Constants.PI;
            }

            // Initialize the link at the start of the face
            List<PolygonLink> links = new List<PolygonLink>();
            PolygonLink link = new PolygonLink(beginPoint, isCurveEnd, isRadial, bearing, angle);
            links.Add(link);

            // Initialize links for any extra points
            if (m_ExtraPoints!=null)
            {
                // Intermediate points can never be curve ends
                isCurveEnd = false;

                // If the face is a curve, they're radial points
                isRadial = isThisCurve;

                // Note any curve info
                double radius;
                IPosition centre = null;
                bool iscw = false;

                if (isRadial)
                {
                    Debug.Assert(m_Divider.Line.LineGeometry is ICircularArcGeometry);
                    ICircularArcGeometry arc = (m_Divider.Line.LineGeometry as ICircularArcGeometry);
                    centre = arc.Circle.Center;
                    radius = arc.Circle.Radius;
                    iscw = arc.IsClockwise;
                    angle = 0.0;
                }

                for (uint i=0; i<m_ExtraPoints.Length; i++)
                {
                    //IPointGeometry loc = m_ExtraPoints[i].Geometry;
                    PointFeature loc = m_ExtraPoints[i];

                    // Figure out the orientation bearing for the point
                    if (isRadial)
                    {
                        Debug.Assert(centre!=null);
                        bearing = Geom.BearingInRadians(centre, loc);
                        if (iscw  != isPolLeft)
                            bearing += Constants.PI;
                    }
                    else
                    {
                        // Get the exterior clockwise angle

                        IPointGeometry back;
                        IPointGeometry fore;

                        if (i==0)
                            back = m_Begin;
                        else
                            back = m_ExtraPoints[i-1].Geometry;

                        if (i==(m_ExtraPoints.Length-1))
                            fore = m_End;
                        else
                            fore = m_ExtraPoints[i+1].Geometry;

                        Turn reference = new Turn(loc, back);
                        angle = reference.GetAngleInRadians(fore);

                        // Define the bearing to use for projecting the point. It's
                        // in the middle of the angle, but projected into the polygon.
                        bearing = reference.BearingInRadians + angle*0.5 + Constants.PI;
                    }

                    link = new PolygonLink(m_ExtraPoints[i], isCurveEnd, isRadial, bearing, angle);
                    links.Add(link);
                }
            }

            return links.ToArray();
        }
Exemplo n.º 3
0
        /// <summary>
        /// Constructor (that does a lot of stuff)
        /// </summary>
        /// <param name="polygon">The polygon being subdivided.</param>
        internal PolygonSub(Polygon polygon)
        {
            m_Polygon = polygon;
            m_Faces   = null;
            m_Links   = null;

            // Get the boundaries defining the exterior edge of the polygon
            IDivider[] lines = polygon.Edge;
            if (lines == null || lines.Length == 0)
            {
                return;
            }

            // Allocate an array for holding info on each polygon face,
            // and associate each one with the divider that acts as the primary face.
            uint numLink = 0;

            m_Faces = new PolygonFace[lines.Length];
            for (int i = 0; i < lines.Length; i++)
            {
                m_Faces[i] = new PolygonFace();
                numLink   += m_Faces[i].SetDivider(m_Polygon, lines[i]);
            }

            // Create an array of link objects (one for each point)
            if (numLink == 0)
            {
                return;
            }

            m_Links = new PolygonLink[numLink];

            // Initialize the links for first face
            int nDone = 0;

            PolygonLink[] links = m_Faces[0].CreateLinks(m_Faces[m_Faces.Length - 1]);
            Array.Copy(links, m_Links, links.Length);
            nDone += links.Length;

            // Initialize links for each subsequent face
            for (int i = 1; i < m_Faces.Length; i++)
            {
                links = m_Faces[i].CreateLinks(m_Faces[i - 1]);
                for (int j = 0; j < links.Length; j++)
                {
                    m_Links[nDone + j] = links[j];
                }

                nDone += links.Length;
            }


            Debug.Assert(nDone == m_Links.Length);

            // Assign a side number to each link position

            uint nside = 0;               // No side number assigned so far.
            uint ncorn = 0;               // Number of corners

            for (int i = 0; i < m_Links.Length; i++)
            {
                // Skip if we are dealing with a corner.
                if (m_Links[i].IsCorner())
                {
                    ncorn++;
                    continue;
                }

                // Skip if the side number has already been assigned.
                if (m_Links[i].Side != 0)
                {
                    continue;
                }

                // Assign next side number.
                nside++;

                // Continue till we reach a corner, assigning intermediate
                // faces the same side number.
                for (int j = i; j < m_Links.Length; j++)
                {
                    if (m_Links[j].IsCorner())
                    {
                        break;
                    }
                    m_Links[j].Side = nside;
                }

                // If we just assigned a side number to the very first face,
                //  loop back from the end of the array.
                if (i == 0)
                {
                    for (int k = m_Links.Length - 1; k > 0; k--)
                    {
                        if (m_Links[k].IsCorner())
                        {
                            break;
                        }
                        m_Links[k].Side = nside;
                    }
                }
            }

            // Return if we only have one side (or less)
            // if ( nside<2 ) return;

            // Define the max angular difference (10 degrees, but in radians)
            double ANGTOL = (10.0 * Constants.DEGTORAD);

            // Process all the radial faces first.

            for (uint i = 0; i < m_Links.Length; i++)
            {
                if (m_Links[i].IsRadial)
                {
                    this.SetLink(i, ANGTOL);
                }
            }

            // For each point that is not a corner or a curve end, cycle
            // through all the subsequent points, looking for a point to
            // connect to. Don't try to do curve end points just yet.

            for (uint i = 0; i < m_Links.Length; i++)
            {
                if (!m_Links[i].IsRadial && !m_Links[i].IsCurveEnd)
                {
                    this.SetLink(i, ANGTOL);
                }
            }

            // Process any points at the end of curves.

            for (uint i = 0; i < m_Links.Length; i++)
            {
                if (m_Links[i].IsCurveEnd)
                {
                    this.SetLink(i, ANGTOL);
                }
            }

            // Eliminate self-intersections ...

            // Start by counting the number of intersections each link has.
            uint maxnx = 0;

            for (uint i = 0; i < m_Links.Length; i++)
            {
                uint nx = this.SetIntersectionCount(i);
                maxnx = Math.Max(maxnx, nx);
            }

            uint nloop = 0;               // Number of loops (just in case of infinite loop).

            while (maxnx > 0)
            {
                // Find a link with the max number of intersections.
                int rem = -1;
                for (int i = 0; i < m_Links.Length; i++)
                {
                    if (m_Links[i].NumIntersect == maxnx)
                    {
                        rem = i;
                        break;
                    }
                }

                // We SHOULD have found something.
                if (rem < 0)
                {
                    throw new Exception("PolygonSub: Unexpected intersection count");
                }

                // If the count was greater than one, just remove the link. Otherwise get the
                // thing that was intersected. If one is a radial or a curve end, & the other isn't,
                // drop the radial. Otherwise drop the one with the poorer link angle.

                if (maxnx > 1)
                {
                    m_Links[rem].SetLink(null);
                }
                else
                {
                    PolygonLink pLink1 = m_Links[rem];
                    PolygonLink pLink2 = null;
                    for (int i = 0; pLink2 != null && i < m_Links.Length; i++)
                    {
                        if (pLink1.IsIntersected(m_Links[i]))
                        {
                            pLink2 = m_Links[i];
                        }
                    }

                    if (pLink2 == null)
                    {
                        throw new Exception("PolygonSub: Intersection not found");
                    }

                    // Check if radial.
                    bool rad1 = pLink1.IsRadial || pLink1.Link.IsRadial;
                    bool rad2 = pLink2.IsRadial || pLink2.Link.IsRadial;

                    // Check if end of curves.
                    bool end1 = pLink1.IsCurveEnd || pLink1.Link.IsCurveEnd;
                    bool end2 = pLink2.IsCurveEnd || pLink2.Link.IsCurveEnd;

                    // We treat radials and end of curves the same.
                    bool curve1 = (rad1 || end1);
                    bool curve2 = (rad2 || end2);

                    // If one is a curve-related and the other isn't, drop
                    // the one that's curve-related.
                    if (curve1 != curve2)
                    {
                        if (curve1)
                        {
                            pLink1.SetLink(null);
                        }
                        else
                        {
                            pLink2.SetLink(null);
                        }
                    }
                    else
                    {
                        // Neither is curve related, or both are. Drop the
                        // one with the poorer link angle.

                        if (pLink1.LinkAngle > pLink2.LinkAngle)
                        {
                            pLink1.SetLink(null);
                        }
                        else
                        {
                            pLink2.SetLink(null);
                        }
                    }
                }

                // Rework the intersect counts where necessary.

                maxnx = 0;
                for (uint i = 0; i < m_Links.Length; i++)
                {
                    if (m_Links[i].NumIntersect > 0)
                    {
                        maxnx = Math.Max(maxnx, this.SetIntersectionCount(i));
                    }
                }

                // Make sure we don't go into an infinite loop.
                nloop++;
                if (nloop > m_Links.Length)
                {
                    throw new Exception("PolygonSub: Breaking from infinite loop");
                }
            } // end while
        }