private void TryAddLink()
        {
            // A link be between exactly two polygons.
            if (_intersectedEdges.Count != 2)
            {
                return;
            }

            // A polygon can't connect with itself
            if (_intersectedEdges[0].Polygon == _intersectedEdges[1].Polygon)
            {
                return;
            }

            // Can make a connection.
            PolygonLink polyLink = new PolygonLink(
                _intersectedEdges[0].Polygon,
                _intersectedEdges[0].Edge,
                _intersectedEdges[1].Polygon,
                _intersectedEdges[1].Edge);

            _navMesh.AddLink(polyLink);
        }
        /// <summary>
        /// This function will look up the polygon index right away.
        /// This could potentially cause problems if the XML has the polygon defs later in the file.
        /// The values should really be cached and it should be done after.
        /// (or thrown in a closure but the C# syntax is a little too messy for that)
        /// </summary>
        /// <param name="xmlReader"></param>
        /// <param name="navMesh"></param>
        private static void LoadSingleLink(XmlTextReader xmlReader, NavMesh navMesh)
        {
            int startPolygonIndex = -1;
            int startEdgeStart    = -1;
            int startEdgeEnd      = -1;

            int endPolygonIndex = -1;
            int endEdgeStart    = -1;
            int endEdgeEnd      = -1;

            xmlReader.MoveToContent();
            while (xmlReader.Read())
            {
                if ("start" == xmlReader.Name)
                {
                    startPolygonIndex = int.Parse(xmlReader.GetAttribute("polygon"));
                    startEdgeStart    = int.Parse(xmlReader.GetAttribute("edgestart"));
                    startEdgeEnd      = int.Parse(xmlReader.GetAttribute("edgeend"));
                }
                else if ("end" == xmlReader.Name)
                {
                    endPolygonIndex = int.Parse(xmlReader.GetAttribute("polygon"));
                    endEdgeStart    = int.Parse(xmlReader.GetAttribute("edgestart"));
                    endEdgeEnd      = int.Parse(xmlReader.GetAttribute("edgeend"));
                }
                else if ("link" == xmlReader.Name)
                {
                    PolygonLink polygonLink = new PolygonLink(
                        navMesh.PolygonList[startPolygonIndex],
                        new IndexedEdge(startEdgeStart, startEdgeEnd),
                        navMesh.PolygonList[endPolygonIndex],
                        new IndexedEdge(endEdgeStart, endEdgeEnd));
                    navMesh.AddLink(polygonLink);
                    return;
                }
            }
        }
Example #3
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();
        }