/// <summary>
        /// Cuts back a horizontal line segment to the closest intersection with this line.
        /// Used in point in polygon.
        /// </summary>
        /// <param name="s">Start of horizontal segment.</param>
        /// <param name="e">End of segment (will be modified if segment intersects this line)</param>
        /// <param name="status">Return code indicating whether an error has arisen (returned
        /// as 0 if no error).</param>
        /// <returns>True if the horizontal line was cut back.</returns>
        internal override bool GetCloser(IPointGeometry s, ref PointGeometry e, out uint status)
        {
            status = 0;

            // Remember the initial end of segment
            PointGeometry initEnd = new PointGeometry(e);

            // Represent the horizontal segment in a class of its own
            HorizontalRay hseg = new HorizontalRay(s, e.X - s.X);

            if (!hseg.IsValid)
            {
                status = 1;
                return(false);
            }

            // Get relative position code for the start of the line. If it's
            // somewhere on the horizontal segment, cut the line back.
            byte scode = Geom.GetPositionCode(Start, s, e);

            if (scode == 0)
            {
                e = new PointGeometry(Start);
            }

            // Get the position code for the end of the line segment
            byte ecode = Geom.GetPositionCode(End, s, e);

            // If it's coincident with the horizontal segment, cut the
            // line back. Otherwise see whether there is any potential
            // intersection to cut back to.

            if (ecode == 0)
            {
                e = new PointGeometry(End);
            }
            else if ((scode & ecode) == 0)
            {
                IPosition x = null;
                if (hseg.Intersect(Start, End, ref x))
                {
                    e = new PointGeometry(x);
                }
            }

            // Return flag to indicate whether we got closer or not.
            return(!e.IsCoincident(initEnd));
        }
Exemple #2
0
        /// <summary>
        /// Delegate that's called whenever the index finds a line with an extent that
        /// overlaps the query window.
        /// </summary>
        /// <param name="item">The item to process (expected to be some sort of <c>IFeature</c>)</param>
        /// <returns>True (always), meaning the query should continue.</returns>
        private bool OnQueryHit(ISpatialObject item)
        {
            if (item is Circle)
            {
                // Confirm the circle is truly within tolerance
                Circle c    = (item as Circle);
                double rad  = c.Radius;
                double dist = Geom.Distance(c.Center, m_Position);
                if (Math.Abs(rad - dist) < m_Tolerance)
                {
                    m_Result.Add(c);
                }
            }

            return(true);
        }
Exemple #3
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 #4
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 #5
0
        /// <summary>
        /// Checks whether this link object intersects another one.
        /// </summary>
        /// <param name="other">The other link to check.</param>
        /// <returns>
        /// True if there is an intersection. False if:
        ///
        /// 1. The other link is THIS link.
        /// 2. This link is the end of a link.
        /// 3. This link has no link.
        /// 4. The other link is the end of any link.
        /// 5. The other link is not linked.
        /// 6. There is no intersection.
        /// </returns>
        internal bool IsIntersected(PolygonLink other)
        {
            // The other object can't be THIS object.
            if (Object.ReferenceEquals(other, this))
            {
                return(false);
            }

            // The other can't be linked to this.
            if (Object.ReferenceEquals(other, m_Link))
            {
                return(false);
            }

            // Both objects must be linked.
            if (m_Link == null || other.Link == null)
            {
                return(false);
            }

            // It must be the START of both links.
            if (m_IsEnd || other.IsEnd)
            {
                return(false);
            }

            // Get the position of this link.
            double xk = m_Point.X;
            double yk = m_Point.Y;
            double xl = m_Link.Point.X;
            double yl = m_Link.Point.Y;

            // Get the position of the other link.
            double xm = other.Point.X;
            double ym = other.Point.Y;
            double xn = other.Link.Point.X;
            double yn = other.Link.Point.Y;

            // Return if there is any intersection along the length of the test segments.
            double xi, yi;

            return(Geom.CalcIntersect(xk, yk, xl, yl,
                                      xm, ym, xn, yn,
                                      out xi, out yi, true) != 0);
        }
Exemple #6
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 #7
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 #8
0
 /// <summary>
 /// Checks whether this closed shape overlaps (encloses) a point.
 /// </summary>
 /// <param name="point">The position to check</param>
 /// <returns>True if the shape overlaps the point</returns>
 internal bool IsOverlap(IPointGeometry point)
 {
     return(m_Extent.IsOverlap(point) && Geom.IsPointInClosedShape(this.Data, point));
 }
 /// <summary>
 /// Checks whether a position is coincident with a line segment, using a tolerance that's
 /// consistent with the resolution of data.
 /// </summary>
 /// <param name="testX">The position to test</param>
 /// <param name="testY"></param>
 /// <param name="xs">Start of line segment.</param>
 /// <param name="ys"></param>
 /// <param name="xe">End of line segment.</param>
 /// <param name="ye"></param>
 /// <returns>True if the distance from the test position to the line segment is less
 /// than <c>Constants.XYTOL</c> (3 microns on the ground)</returns>
 // Redundant?
 private static bool IsCoincident(double testX, double testY, double xs, double ys, double xe, double ye)
 {
     return(Geom.DistanceSquared(testX, testY, xs, ys, xe, ye) < Constants.XYTOLSQ);
 }
Exemple #10
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);
        }
Exemple #11
0
        /// <summary>
        /// Obtains annotation for this line.
        /// </summary>
        /// <param name="dist">The observed distance (if any).</param>
        /// <param name="drawObserved">Draw observed distance? Specify <c>false</c> for
        /// actual distance.</param>
        /// <returns>The annotation (null if it cannot be obtained)</returns>
        Annotation GetAnnotation(Distance dist, bool drawObserved)
        {
            // @devnote This function may not be that hot for curves that
            // are complete circles. At the moment though, I can't see why
            // we'd be drawing a distance alongside a circle.

            // Get the length of the arc
            double len = this.Length.Meters;

            // Get the string to output.
            string distr = GetDistance(len, dist, drawObserved);

            if (distr == null)
            {
                return(null);
            }

            // Get the mid-point of this arc.
            IPosition mid;

            this.GetPosition(new Length(len * 0.5), out mid);

            // Get the bearing from the center to the midpoint.
            IPosition center  = m_Circle.Center;
            double    bearing = BasicGeom.BearingInRadians(center, mid);

            // Get the height of the text, in meters on the ground.
            double grheight = EditingController.Current.LineAnnotationStyle.Height;

            // We will offset by 20% of the height (give a bit of space
            // between the text and the line).
            //double offset = grheight * 0.2;
            // ...looks fine with no offset (there is a space, but it's for descenders
            // that aren't there since we're dealing just with numbers).
            double offset = 0.0;

            // Get the rotation of the text.
            double rotation = bearing - MathConstants.PI;

            // If the midpoint is above the circle centre, we get upside-down
            // text so rotate it the other way. If we don't switch the
            // rotation, we need to make an extra shift, because the text
            // is aligned along its baseline.

            // This depends on whether the annotation is on the default
            // side or not.

            // Not sure about the following... (c.f. revised handling in SegmentGeometry)

            /*
             * if (mid.Y > center.Y)
             * {
             *  rotation += MathConstants.PI;
             *  if (isFlipped)
             *      offset = -0.9 * grheight;
             * }
             * else
             * {
             *  if (isFlipped)
             *      offset = -offset;
             *  else
             *      offset = 0.9 * grheight;	// 1.0 * grheight is too much
             * }
             */

            // ...try this instead

            if (mid.Y > center.Y)
            {
                rotation += MathConstants.PI;
            }
            else
            {
                offset = 1.3 * grheight; // push the text to the outer edge of the arc
            }
            if (dist != null && dist.IsAnnotationFlipped)
            {
                rotation += MathConstants.PI;

                // and may need to adjust offset...
            }

            // Project to the offset point.
            IPosition  p      = Geom.Polar(center, bearing, m_Circle.Radius + offset);
            Annotation result = new Annotation(distr, p, grheight, rotation);

            result.FontStyle = FontStyle.Italic;
            return(result);
        }
        /// <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>
        /// <param name="doLast">Specify true to consider the last segment. False to ignore the
        /// last segment.</param>
        /// <returns>The closest position (null if the line is further away than the specified
        /// max distance)</returns>
        IPosition FindClosest(IPointGeometry p, ILength tol, bool doLast)
        {
            IPointGeometry[] data = Data;

            // Initial "best" distance squared cannot be greater than the square of the match tolerance.
            double tm      = tol.Meters;
            double bestdsq = tm * tm;

            // Best segment number so far (valid segment numbers start at 1).
            int best = 0;

            // Pull out the XY of the search vertex
            double vx = p.X;
            double vy = p.Y;

            // Get start of the initial line segment
            double x1 = data[0].X;
            double y1 = data[0].Y;

            // Only do the last segment when required.
            int nv = data.Length;

            if (!doLast)
            {
                nv--;
            }

            for (int i = 1; i < nv; i++)
            {
                // Pick up the end of the segment & get the window of
                // the segment, expanded by the match tolerance.
                double x2 = data[i].X;
                double y2 = data[i].Y;

                double xmin = Math.Min(x1, x2) - tm;
                double ymin = Math.Min(y1, y2) - tm;
                double xmax = Math.Max(x1, x2) + tm;
                double ymax = Math.Max(y1, y2) + tm;

                // If the search vertex falls within the expanded window,
                // and the distance (squared) to the perpendicular point
                // is better than what we already got, remember the index
                // number of this segment.

                if (vx > xmin && vx < xmax && vy > ymin && vy < ymax)
                {
                    double dsq = Geom.DistanceSquared(vx, vy, x1, y1, x2, y2);
                    if (dsq < bestdsq)
                    {
                        bestdsq = dsq;
                        best    = i;
                    }
                }

                // End of segment is start of next one
                x1 = x2;
                y1 = y2;
            }

            // Return if we did not locate a suitable point
            if (best == 0)
            {
                return(null);
            }

            // Get the position of the perpendicular point.
            double         xp, yp;
            IPointGeometry s = data[best - 1];
            IPointGeometry e = data[best];

            Geom.GetPerpendicular(vx, vy, s.X, s.Y, e.X, e.Y, out xp, out yp);
            return(new Position(xp, yp));
        }
        /// <summary>
        /// Intersects this multi-segment with itself. Only SIMPLE intersections will be
        /// found. There are no special checks for multi-segments that graze themselves.
        /// </summary>
        /// <param name="xsect">The intersection results.</param>
        /// <returns>The number of self-intersections found.</returns>
        uint SelfIntersect(IntersectionResult xsect)
        {
            uint nx = 0;

            // Get an array of cumulative distances for each segment.
            IPointGeometry[] data    = this.Data;
            double[]         cumdist = GetCumDist(data);

            // Note start of initial segment (treat as the end of some imaginary line prior to the start).
            double xs;
            double ys;
            double xe = data[0].X;
            double ye = data[0].Y;

            // How many line segments have we got?
            int nseg = data.Length - 1;

            // Loop through each segment, intersecting it with all subsequent
            // segments, except for the one that immediately follows.
            for (int iseg = 1; iseg <= (nseg - 2); iseg++)
            {
                // The start of this segment is the end of the previous one.
                xs = xe;
                ys = ye;

                // Get the position of the end of the test segment
                xe = data[iseg].X;
                ye = data[iseg].Y;

                // Compare against subsequent segments (except the next one)
                for (int jseg = iseg + 2; jseg <= nseg; jseg++)
                {
                    IPointGeometry start = data[jseg - 1];
                    IPointGeometry end = data[jseg];
                    double         xi, yi;

                    if (Geom.CalcIntersect(start.X, start.Y, end.X, end.Y, xs, ys, xe, ye, out xi, out yi, true) != 0)
                    {
                        // Define distance to the intersection on the i-segment
                        double dx   = xi - xs;
                        double dy   = yi - ys;
                        double ilen = cumdist[iseg - 1] + Math.Sqrt(dx * dx + dy * dy);

                        // Likewise for the j-segment
                        dx = xi - start.X;
                        dy = yi - start.Y;
                        double jlen = cumdist[jseg - 1] + Math.Sqrt(dx * dx + dy * dy);

                        // Append TWO intersections.
                        xsect.Append(xi, yi, ilen);
                        xsect.Append(xi, yi, jlen);
                        nx += 2;
                    }
                }
            }

            // Sort the intersections (DON'T set new sort values).
            xsect.Sort(false);

            // Return the number of intersections
            return(nx);
        }
        /// <summary>
        /// Finds the line segment that a position lies on (if any).
        /// </summary>
        /// <param name="data">The data to search</param>
        /// <param name="doFirst">Should the start of the first segment be considered? (default=true)</param>
        /// <param name="startIndex">The array index of the element in <c>data</c> where
        /// the search should start (default=0).</param>
        /// <param name="find">The position to find</param>
        /// <returns>The index of the segment which the search point is coincident with (-1 if not found)</returns>
        static int FindSegment(IPointGeometry[] data, bool doFirst, int startIndex, IPointGeometry find)
        {
            // There have to be at least 2 positions.
            if (data.Length < 2)
            {
                return(-1);
            }

            // Get the position of the vertex to find
            double x = find.X;
            double y = find.Y;

            // Loop through each line segment. The search point must lie somewhere
            // on, or within the window of the segment.

            int    seg;                 // Index to the vertex at the END of a segment
            double xs, ys;              // Start of segment
            double xe, ye;              // End of segment

            // If the first point is to be excluded, and it matches the
            // search position, start on the second line segment instead.
            if (!doFirst && data[startIndex].IsCoincident(find))
            {
                xs  = data[startIndex + 1].X;
                ys  = data[startIndex + 1].Y;
                seg = startIndex + 2;
            }
            else
            {
                xs  = data[startIndex].X;
                ys  = data[startIndex].Y;
                seg = startIndex + 1;
            }

            for (; seg < data.Length; seg++)
            {
                // Get the easting and northing at the end of the segment
                xe = data[seg].X;
                ye = data[seg].Y;

                // If the point to find lies within the window of the segment,
                // determine the perpendicular distance (squared) between the
                // vertex and the line segment. If within tol, return the
                // current segment number.

                if (x >= Math.Min(xs, xe) - Constants.XYTOL &&
                    x <= Math.Max(xs, xe) + Constants.XYTOL &&
                    y >= Math.Min(ys, ye) - Constants.XYTOL &&
                    y <= Math.Max(ys, ye) + Constants.XYTOL)
                {
                    if (Geom.DistanceSquared(x, y, xs, ys, xe, ye) < Constants.XYTOLSQ)
                    {
                        return(seg - 1);
                    }
                }

                // The end of this line segment is the start of the next one.
                xs = xe;
                ys = ye;
            }

            // No match found
            return(-1);
        }
Exemple #15
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 #16
0
        /// <summary>
        /// Obtains the geometry for spans along this leg.
        /// </summary>
        /// <param name="bc">The position for the start of the leg.
        /// <param name="bcBearing">The bearing on entry into the leg.</param>
        /// <param name="sfac">Scale factor to apply to distances.</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 bc, double bcBearing, double sfac, SpanInfo[] spans)
        {
            // Can't do anything if the leg radius isn't defined
            if (m_Metrics.ObservedRadius == null)
            {
                throw new InvalidOperationException("Cannot create sections for circular leg with undefined radius");
            }

            var result = new ILineGeometry[spans.Length];

            // Use supplied stuff to derive info on the center and EC.
            IPosition center;
            IPosition ec;
            double    bearingToBC;
            double    ecBearing;

            GetPositions(bc, bcBearing, sfac, out center, out bearingToBC, out ec, out ecBearing);

            // Define the underlying circle
            ICircleGeometry circle = new CircleGeometry(PointGeometry.Create(center), BasicGeom.Distance(center, bc));

            // Handle case where the leg is a cul-de-sac with no observed spans
            if (spans.Length == 1 && spans[0].ObservedDistance == null)
            {
                result[0] = new CircularArcGeometry(circle, bc, ec, m_Metrics.IsClockwise);
                return(result);
            }

            /// Initialize scaling factor for distances in cul-de-sacs (ratio of the length calculated from
            /// the CA & Radius, versus the observed distances that were actually specified). For curves that
            /// are not cul-de-sacs, this will be 1.0
            double culFactor = 1.0;

            if (m_Metrics.IsCulDeSac)
            {
                double obsv = PrimaryFace.GetTotal();
                if (obsv > MathConstants.TINY)
                {
                    culFactor = Length.Meters / obsv;
                }
            }

            IPosition sPos        = bc;
            IPosition ePos        = null;
            bool      isClockwise = m_Metrics.IsClockwise;
            double    radius      = RadiusInMeters;
            double    edist       = 0.0;

            for (int i = 0; i < result.Length; i++, sPos = ePos)
            {
                // Add on the unscaled distance
                edist += spans[i].ObservedDistance.Meters;

                // Get the angle subtended at the center of the circle. We use
                // unscaled values here, since the scale factors would cancel out.
                // However, we DO apply any cul-de-sac scaling factor, to account
                // for the fact that the distance may be inconsistent with the
                // curve length derived from the CA and radius. For example, it
                // is possible that the calculated curve length=200, although the
                // total of the observed spans is somehow only 100. In that case,
                // if the supplied distance is 50, we actually want to use a
                // value of 50 * (200/100) = 100.

                double angle = (edist * culFactor) / radius;

                // Get the bearing of the point with respect to the center of the circle.

                double bearing;

                if (isClockwise)
                {
                    bearing = bearingToBC + angle;
                }
                else
                {
                    bearing = bearingToBC - angle;
                }

                // Calculate the position using the scaled radius.
                ePos = Geom.Polar(center, bearing, radius * sfac);

                result[i] = new CircularArcGeometry(circle, sPos, ePos, isClockwise);
            }

            return(result);
        }
Exemple #17
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 #18
0
        void CheckPts(string ptsFileName, CadastralMapModel mm)
        {
            if (!File.Exists(ptsFileName))
            {
                return;
            }

            var badList = new List <CheckData>();

            foreach (string s in File.ReadAllLines(ptsFileName))
            {
                string[] items = s.Split(',');
                uint     id    = UInt32.Parse(items[0]);
                double   x     = Double.Parse(items[1]);
                double   y     = Double.Parse(items[2]);
                Position a     = new Position(x, y);

                PointFeature p = mm.Find <PointFeature>(new InternalIdValue(id));

                if (p != null)
                {
                    double delta = Geom.Distance(a, p);
                    if (delta > 0.001)
                    {
                        badList.Add(new CheckData()
                        {
                            Point = p, Delta = delta
                        });
                    }
                }
            }

            // Obtain the calculation sequence
            Operation[] calcs     = mm.GetCalculationSequence();
            var         editOrder = new Dictionary <uint, uint>();

            for (int i = 0; i < calcs.Length; i++)
            {
                editOrder.Add(calcs[i].EditSequence, (uint)i);
            }

            foreach (CheckData cd in badList)
            {
                cd.CalculationOrder = editOrder[cd.Point.Creator.EditSequence];
            }

            badList.Sort((A, B) => A.CalculationOrder.CompareTo(B.CalculationOrder));

            using (StreamWriter sw = File.CreateText(ptsFileName + ".check"))
            {
                // Dump out the calc order
                //foreach (Operation op in calcs)
                //    sw.WriteLine(String.Format("Edit={0} Order={1} Type={2}", op.EditSequence, editOrder[op.EditSequence], op.EditId));

                sw.WriteLine("Number of points>0.001 = " + badList.Count);
                foreach (CheckData cd in badList)
                {
                    sw.WriteLine(String.Format("Order={0} Id={1}  Delta={2:0.000}",
                                               cd.CalculationOrder, cd.Point.InternalId.ItemSequence, cd.Delta));
                }
            }
        }
Exemple #19
0
        private Feature ImportName(Ntx.Name name, Operation creator)
        {
            /*
             * // Get pointer to the applicable map theme
             * CeTheme theme(Name.GetTheme());
             * CeTheme* pTheme = theme.AddTheme();
             *
             * // Get pointer to the entity type.
             * GRAPHICSTYPE geom = ANNOTATION;
             * if ( Name.IsLabel() ) geom = POLYGON;
             * CeEntity* pEntity = AddEntity(Name.GetpFeatureCode(),pTheme,geom);
             */
            IEntity entity = GetEntityType(name, SpatialType.Text);

            // Get the text string
            string text = name.Text;

            // Get the position of the centre of the 1st character
            Ntx.Position pos     = name.Position(0);
            IPosition    vcentre = new Position(pos.Easting, pos.Northing);

            // Get text metrics
            float height   = name.Height;
            float spacing  = name.Spacing;
            float rotation = name.Rotation;

            // Calculate the top left corner of the first character using
            // the text metrics we just got ...

            // Get the width of the first character. For names that contain
            // only one character, the spacing we have will be zero, so in
            // that case, deduce the width of the character via the covering
            // rectangle.

            float charwidth = spacing;

            if (charwidth < Constants.TINY)
            {
                // Get the covering rectangle.
                Ntx.Position nw = name.NorthWest;
                Ntx.Position se = name.SouthEast;

                // And get the dimensions.
                double dx = se.Easting - nw.Easting;
                double dy = nw.Northing - se.Northing;

                // If the cover is screwed up, assume the width is 80% of the text height.
                if (dy < Constants.TINY)
                {
                    charwidth = (float)(height * 0.8);
                }
                else
                {
                    charwidth = (float)(height * (dx / dy));
                }
            }

            // Define the bearing from bottom to top of the text.
            double vbear = (double)rotation;

            // Get position directly above the centre of the 1st char.
            IPosition above = Geom.Polar(vcentre, vbear, 0.5 * (double)height);

            // Define the bearing from the point we just got to the
            // start of the text string.
            double hbear = vbear - Constants.PIDIV2;

            // Back up half a character to get the initial corner.
            PointGeometry topleft = new PointGeometry(Geom.Polar(above, hbear, 0.5 * (double)charwidth));

            IFont       font   = null;
            double      width  = (double)text.Length * charwidth;
            TextFeature result = null;

            if (name.IsLabel)
            {
                // Create key text
                string          keystr = name.Text;
                KeyTextGeometry kt     = new KeyTextGeometry(topleft, font, height, width, rotation);
                InternalIdValue id     = CadastralMapModel.Current.WorkingSession.AllocateNextId();
                result   = new TextFeature(creator, id, entity, kt);
                kt.Label = result;
                result.SetTopology(true);

                // Define the label's foreign ID and form a two-way association
                ForeignId fid = GetFeatureId(keystr);
                Debug.Assert(fid != null);
                fid.Add(result);

                // Remember the reference position of the label.
                Ntx.Position   xp = name.RefPosition;
                IPointGeometry pp = new PointGeometry(xp.Easting, xp.Northing);
                result.SetPolPosition(pp);
            }
            else
            {
                // Create a miscellaneous text label.
                MiscTextGeometry mt = new MiscTextGeometry(text, topleft, font, height, width, rotation);
                InternalIdValue  id = CadastralMapModel.Current.WorkingSession.AllocateNextId();
                result = new TextFeature(creator, id, entity, mt);
                result.SetTopology(false);
            }

            return(result);
        }
        static bool GetPosition(IPosition[] line, double d, out IPosition result)
        {
            if (line.Length < 2)
            {
                throw new Exception("Line contains fewer than 2 positions");
            }

            // Check for invalid distance
            if (d < 0.0)
            {
                result = line[0];
                return(false);
            }

            double walked = 0.0;        // Distance walked so far

            // Loop through the segments until we get to a distance that
            // exceeds the required distance.
            for (int i = 1; i < line.Length; i++)
            {
                // Update total length walked to end of segment
                double seglen = Geom.Distance(line[i - 1], line[i]);
                walked += seglen;

                // If the accumulated distance exceeds the required distance,
                // the point we want is somewhere in the current segment.
                if (walked >= d)
                {
                    double ratio = (walked - d) / seglen;

                    // Check whether the ratio yields a length that matches segment length to within
                    // the order of the data precision (1 micron). If so, return the start of the segment.
                    // If you don't do this, minute shifts occur when points are inserted into the
                    // multisegment. This means that if you repeat the GetPosition call with the SAME distance,
                    // you may actually get a point that is fractionally different from the initially returned
                    // point.

                    if ((seglen - ratio * seglen) < 0.000002)
                    {
                        result = line[i - 1];
                    }
                    else
                    {
                        // Make damn sure!

                        double xs   = line[i - 1].X;
                        double ys   = line[i - 1].Y;
                        double xe   = line[i].X;
                        double ye   = line[i].Y;
                        double dx   = xe - xs;
                        double dy   = ye - ys;
                        double xres = xe - ratio * dx;
                        double yres = ye - ratio * dy;

                        if (Math.Abs(xres - xe) < 0.000002 && Math.Abs(yres - ye) < 0.000002)
                        {
                            result = line[i];
                        }
                        else
                        {
                            result = new Position(xres, yres);
                        }
                    }

                    return(true);
                }
            }

            // Got to the end, so the distance is too much
            result = line[line.Length - 1];
            return(false);
        }