Exemple #1
0
        /// <summary>
        /// Gets the orientation point for a line. This is utilized to form
        /// network topology at the ends of a topological line.
        /// </summary>
        /// <param name="fromStart">True if the orientation from the start of the line is
        /// required. False to get the end orientation.</param>
        /// <param name="crvDist">Orientation distance for circular arcs (if a value of
        /// zero (or less) is specified, a "reasonable" orientation distance will be used -
        /// currently 5 metres on the ground).
        /// </param>
        /// <returns>The orientation point.</returns>
        internal override IPosition GetOrient(bool fromStart, double crvDist)
        {
            // Point to the BC or EC, depending on what we are orienting.
            IPosition loc = (fromStart ? Start : End);

            // Get the bearing of the location from the center of the circular arc
            IPointGeometry centre  = Circle.Center;
            double         bearing = Geom.BearingInRadians(centre, loc);

            // Get the distance to the orientation point. It should not be
            // any further than the length of the arc. We use a fixed
            // orientation distance of 5 metres on the ground for now.

            double dist;

            if (crvDist < Constants.TINY)
            {
                dist = Math.Min(5.0, Length.Meters);
            }
            else
            {
                dist = Math.Min(crvDist, Length.Meters);
            }

            // If we are coming from the end of the arc, use a negated
            // distance to get the direction right.
            if (!fromStart)
            {
                dist = -dist;
            }

            // Add the angle that subtends the orientation distance (or
            // subtract if the arc goes anti-clockwise).
            double radius = Circle.Radius;

            if (m_IsClockwise)
            {
                bearing += (dist / radius);
            }
            else
            {
                bearing -= (dist / radius);
            }

            // Figure out the orientation point from the new bearing.
            return(Geom.Polar(centre, bearing, radius));
        }
Exemple #2
0
        /// <summary>
        /// Gets the point on this line that is closest to a specified position.
        /// </summary>
        /// <param name="p">The position to search from.</param>
        /// <param name="tol">Maximum distance from line to the search position</param>
        /// <returns>The closest position (null if the line is further away than the specified
        /// max distance)</returns>
        internal override IPosition GetClosest(IPointGeometry p, ILength tol)
        {
            // Get the distance from the centre of the circle to the search point.
            IPointGeometry center = m_Circle.Center;
            double         dist   = Geom.Distance(center, p);

            // Return if the search point is beyond tolerance.
            double radius = m_Circle.Radius;
            double diff   = Math.Abs(dist - radius);

            if (diff > tol.Meters)
            {
                return(null);
            }

            // If the vertex lies in the curve sector, the closest position
            // is along the bearing from the centre through the search
            // position. Otherwise the closest position is the end of
            // the curve that's closest (given that it's within tolerance).

            if (CircularArcGeometry.IsInSector(this, p, 0.0))
            {
                double bearing = Geom.BearingInRadians(center, p);
                return(Geom.Polar(center, bearing, radius));
            }

            double d1 = Geom.DistanceSquared(p, BC);
            double d2 = Geom.DistanceSquared(p, EC);

            double t = tol.Meters;

            if (Math.Min(d1, d2) < (t * t))
            {
                if (d1 < d2)
                {
                    return(BC);
                }
                else
                {
                    return(EC);
                }
            }

            return(null);
        }
Exemple #3
0
        /// <summary>
        /// Obtains the geometry for spans along an alternate face attached to this leg.
        /// </summary>
        /// <param name="start">The position for the start of the leg.
        /// <param name="end">The position for the end of the leg.</param>
        /// <param name="spans">Information for the spans coinciding with this leg.</param>
        /// <returns>The sections along this leg</returns>
        internal override ILineGeometry[] GetSpanSections(IPosition start, IPosition end, SpanInfo[] spans)
        {
            Debug.Assert(AlternateFace != null);

            // Get the desired length (in meters on the ground)
            double len = Geom.Distance(start, end);

            // Get the observed length (in meters on the ground)
            double obs = AlternateFace.GetTotal();

            // Get the adjustment factor for stretching-compressing the observed distances.
            double factor = len / obs;

            // Get the bearing of the line.
            double bearing = Geom.BearingInRadians(start, end);

            return(GetSpanSections(start, bearing, factor, spans));
        }
Exemple #4
0
        /// <summary>
        /// Calculates an angle that is parallel to this line (suitable for adding text)
        /// </summary>
        /// <param name="pos">A significant point on the line (the returned angle
        /// will be at a tangent at this point)</param>
        /// <returns>The rotation (in radians, clockwise from horizontal). Always greater
        /// than or equal to 0.0</returns>
        internal override double GetRotation(IPointGeometry pos)
        {
            // Get the bearing from the centre to the midpoint.
            IPosition center  = m_Circle.Center;
            double    bearing = Geom.BearingInRadians(center, pos);

            // If the midpoint is above the circle center, we get upside-down
            // text so rotate it the other way.
            if (pos.Y > center.Y)
            {
                return(bearing);
            }

            double angle = bearing - MathConstants.PI;

            if (angle < 0.0)
            {
                angle = bearing + MathConstants.PI;
            }

            return(angle);
        }
Exemple #5
0
        /// <summary>
        /// Adjusts the path (Helmert adjustment).
        /// </summary>
        /// <param name="dN">Misclosure in northing.</param>
        /// <param name="dE">Misclosure in easting.</param>
        /// <param name="precision">Precision denominator (zero if no adjustment needed).</param>
        /// <param name="length">Total observed length.</param>
        /// <param name="rotation">The clockwise rotation to apply (in radians).</param>
        /// <param name="sfac">The scaling factor to apply.</param>
        void Adjust(out double dN, out double dE, out double precision, out double length,
                    out double rotation, out double sfac)
        {
            dN   = dE = precision = length = rotation = 0.0;
            sfac = 1.0;

            // Initialize position to the start of the path, corresponding to the initial
            // un-adjusted end point.
            IPosition start  = m_From;
            IPosition gotend = new Position(m_From);

            // Initial bearing is due north.
            double bearing = 0.0;

            // Go through each leg, updating the end position, and getting
            // the total path length.
            foreach (Leg leg in m_Legs)
            {
                length += leg.Length.Meters;
                leg.Project(ref gotend, ref bearing, sfac);
            }

            // Get the bearing and distance of the end point we ended up with.
            double gotbear = Geom.BearingInRadians(m_From, gotend);
            double gotdist = Geom.Distance(m_From, gotend);

            // Get the bearing and distance we want.
            double wantbear = Geom.BearingInRadians(m_From, m_To);
            double wantdist = Geom.Distance(m_From, m_To);

            // Figure out the rotation.
            rotation = wantbear - gotbear;

            // Rotate the end point we got.
            gotend = Geom.Rotate(m_From, gotend, new RadianValue(rotation));

            // Calculate the line scale factor.
            double linefac = m_From.MapModel.SpatialSystem.GetLineScaleFactor(m_From, gotend);

            // Figure out where the rotated end point ends up when we apply the line scale factor.
            gotend = Geom.Polar(m_From, wantbear, gotdist * linefac);

            // What misclosure do we have?
            dN = gotend.Y - m_To.Y;
            dE = gotend.X - m_To.X;
            double delta = Math.Sqrt(dN * dN + dE * dE);

            // What's the precision denominator (use a value of 0 to denote an exact match).
            if (delta > MathConstants.TINY)
            {
                precision = wantdist / delta;
            }
            else
            {
                precision = 0.0;
            }

            // Figure out the scale factor for the adjustment (use a value of 0 if the start and end
            // points are coincident). The distances here have NOT been adjusted for the line scale factor.
            if (gotdist > MathConstants.TINY)
            {
                sfac = wantdist / gotdist;
            }
            else
            {
                sfac = 0.0;
            }

            // Remember the rotation and scaling factor
            m_IsAdjusted  = true;
            m_Rotation    = rotation;
            m_ScaleFactor = sfac;
            m_Precision   = precision;
        }
Exemple #6
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());
        }
Exemple #7
0
        /// <summary>
        /// Intersects a line segment with a circle.
        /// </summary>
        /// <param name="centre">Position of the circle's centre.</param>
        /// <param name="radius">Radius of the circle.</param>
        /// <param name="start">Start of segment.</param>
        /// <param name="end">End of segment.</param>
        /// <param name="x1">First intersection (if any).</param>
        /// <param name="x2">Second intersection (if any).</param>
        /// <param name="istangent">Is segment a tangent to the circle? This can be true only if
        /// ONE intersection is returned.</param>
        /// <param name="online">TRUE if the intersection must lie ON the segment.</param>
        /// <returns>The number of intersections found (0, 1, or 2).</returns>
        internal static uint IntersectCircle(IPosition centre
                                             , double radius
                                             , IPosition start
                                             , IPosition end
                                             , out IPosition ox1
                                             , out IPosition ox2
                                             , out bool istangent
                                             , bool online)
        {
            // Initialize the return info.
            Position x1 = new Position(0, 0);
            Position x2 = new Position(0, 0);

            ox1       = x1;
            ox2       = x2;
            istangent = false;

            // Get the bearing of this segment.
            double bearing = Geom.BearingInRadians(start, end);

            // The equation of each line is given in parametric form as:
            //
            //		x = xo + f * r
            //		y = yo + g * r
            //
            // where	xo,yo is the from point
            // and		f = sin(bearing)
            // and		g = cos(bearing)
            // and		r is the distance along the line.

            double g = Math.Cos(bearing);
            double f = Math.Sin(bearing);

            double fsq = f * f;
            double gsq = g * g;

            double startx = start.X;
            double starty = start.Y;
            double dx     = centre.X - startx;
            double dy     = centre.Y - starty;

            double fygx = f * dy - g * dx;
            double root = radius * radius - fygx * fygx;

            // Check for no intersection.
            if (root < -Constants.TINY)
            {
                return(0);
            }

            // We've either got 1 or 2 intersections ...

            // If the intersection has to be ON the line, we'll need
            // the length of the line segment.
            double seglen = 0.0;

            if (online)
            {
                seglen = BasicGeom.Distance(start, end);
            }

            // Check for tangential intersection.

            if (root < Constants.TINY)
            {
                double xdist = f * dx + g * dy;
                if (online && (xdist < 0.0 || xdist > seglen))
                {
                    return(0);
                }
                x1.X      = startx + f * xdist;
                x1.Y      = starty + g * xdist;
                istangent = true;
                return(1);
            }

            // That leaves us with 2 intersections, although one or both of
            // them may not actually fall on the segment.

            double fxgy = f * dx + g * dy;

            root = Math.Sqrt(root);
            double dist1 = (fxgy - root);
            double dist2 = (fxgy + root);

            if (online)
            {
                uint nok = 0;

                if (dist1 > 0.0 && dist1 < seglen)
                {
                    x1.X = startx + f * dist1;
                    x1.Y = starty + g * dist1;
                    nok  = 1;
                }

                if (dist2 > 0.0 && dist2 < seglen)
                {
                    if (nok == 0)
                    {
                        x1.X = startx + f * dist2;
                        x1.Y = starty + g * dist2;
                        return(1);
                    }

                    x2.X = startx + f * dist2;
                    x2.Y = starty + g * dist2;
                    return(2);
                }

                return(nok);
            }

            // Doesn't need to be ON the segment.

            x1.X = startx + f * dist1;
            x1.Y = starty + g * dist1;

            x2.X = startx + f * dist2;
            x2.Y = starty + g * dist2;

            return(2);
        }