예제 #1
0
        /// <summary>
        /// Checks whether a location falls in the sector lying between the BC and EC
        /// of a circular arc. The only condition is that the location has an appropriate
        /// bearing with respect to the bearings of the BC & EC (i.e. the location does not
        /// necessarily lie ON the arc).
        /// </summary>
        /// <param name="pos">The position to check</param>
        /// <param name="lintol">Linear tolerance, in meters on the ground (locations that are
        /// beyond the BC or EC by up to this much will also be regarded as "in-sector").</param>
        /// <returns>True if position falls in the sector defined by this arc</returns>
        public static bool IsInSector(ICircularArcGeometry g, IPosition pos, double lintol)
        {
            // If the arc is a complete circle, it's ALWAYS in sector.
            if (IsCircle(g))
            {
                return(true);
            }

            // Express the curve's start & end points in local system,
            // ordered clockwise.
            IPointGeometry start = g.First;
            IPointGeometry end   = g.Second;

            // Get the centre of the circular arc.
            IPosition centre = g.Circle.Center;

            // If we have a linear tolerance, figure out the angular equivalent.
            if (lintol > MathConstants.TINY)
            {
                double angtol = lintol / g.Circle.Radius;
                return(BasicGeom.IsInSector(pos, centre, start, end, angtol));
            }
            else
            {
                return(BasicGeom.IsInSector(pos, centre, start, end, 0.0));
            }
        }
예제 #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 perpendicular point (or closest end)
            IPointGeometry s = Start;
            IPointGeometry e = End;
            double         xp, yp;

            BasicGeom.GetPerpendicular(p.X, p.Y, s.X, s.Y, e.X, e.Y, out xp, out yp);

            // Ignore if point is too far away
            double t  = tol.Meters;
            double dx = p.X - xp;

            if (dx > t)
            {
                return(null);
            }

            double dy = p.Y - yp;

            if (dy > t)
            {
                return(null);
            }

            double dsq = (dx * dx + dy * dy);

            if (dsq > t * t)
            {
                return(null);
            }

            return(new Position(xp, yp));
        }
예제 #3
0
        /// <summary>
        /// Returns the offset distance with respect to a reference direction, in meters
        /// on the ground. Offsets to the left are returned as a negated value, while
        /// offsets to the right are positive values.
        /// </summary>
        /// <param name="dir">The direction that the offset was observed with respect to.</param>
        /// <returns>The signed offset distance, in meters on the ground</returns>
        internal override double GetMetric(Direction dir)
        {
            // Return offset of zero if there is no offset point.
            if (m_Point == null)
            {
                return(0.0);
            }

            // Get the origin of the direction & it's bearing. This gives
            // us the info we need to express the equation of the line
            // in parametric form.

            PointFeature from    = dir.From;
            double       x       = from.X;
            double       y       = from.Y;
            double       bearing = dir.Bearing.Radians;

            // Get the position of the offset point.
            double xoff = m_Point.X;
            double yoff = m_Point.Y;

            // Get the signed perpendicular distance from the offset
            // point to the reference direction.
            return(BasicGeom.SignedDistance(x, y, bearing, xoff, yoff));
        }
예제 #4
0
        /// <summary>
        /// Returns the position of the intersection that is closest to a specific position.
        /// </summary>
        /// <param name="posn">The position to search for.</param>
        /// <param name="xsect">The closest intersection.</param>
        /// <param name="tolsq">The smallest allowable distance (squared) between the
        /// search position and the closest intersection (default=0.0).</param>
        /// <returns>TRUE if the position was found.</returns>
        internal bool GetClosest(IPosition posn, out IPosition xsect, double tolsq)
        {
            xsect = null;

            // Go through each intersection, looking for the closest
            // intersection that is not TOO close.

            double mindsq = Double.MaxValue;
            double dsq;

            foreach (IntersectionData d in m_Data)
            {
                dsq = BasicGeom.DistanceSquared(posn, d.P1);
                if (dsq < mindsq && dsq > tolsq)
                {
                    mindsq = dsq;
                    xsect  = d.P1;
                }

                // If the intersection is a graze, check the 2nd
                // intersection too.
                if (d.IsGraze)
                {
                    dsq = BasicGeom.DistanceSquared(posn, d.P2);
                    if (dsq < mindsq && dsq > tolsq)
                    {
                        mindsq = dsq;
                        xsect  = d.P2;
                    }
                }
            }

            return(xsect != null);
        }
예제 #5
0
        /// <summary>
        /// Generates an approximation of a circular arc.
        /// </summary>
        /// <param name="tol">The maximum chord-to-circumference distance.</param>
        /// <returns></returns>
        public static IPointGeometry[] GetApproximation(ICircularArcGeometry g, ILength tol)
        {
            // Get info about the circle the curve lies on.
            IPosition center = g.Circle.Center;
            double    radius = g.Circle.Radius;

            // Determine the change in bearing which will satisfy the specified tolerance
            // (if no tolerance has been specified, arbitrarily use a tolerance of 1mm on the ground).
            double tolm  = (tol.Meters > Double.Epsilon ? tol.Meters : 0.001);
            double dbear = Math.Acos((radius - tolm) / radius);

            IPointGeometry start = g.BC;
            IPointGeometry end   = g.EC;
            bool           iscw  = g.IsClockwise;

            // Get the total angle subtended by the curve.
            Turn   reft   = new Turn(center, start);
            double totang = reft.GetAngleInRadians(end); // clockwise

            if (!iscw)
            {
                totang = MathConstants.PIMUL2 - totang;
            }

            // Figure out how many positions we'll generate
            int nv = (int)(totang / dbear); // truncate

            Debug.Assert(nv >= 0);

            // Handle special case of very short arc.
            if (nv == 0)
            {
                return new IPointGeometry[] { start, end }
            }
            ;

            // Sign the delta-bearing the right way.
            if (!iscw)
            {
                dbear = -dbear;
            }

            // Get the initial bearing to the first position along the curve.
            double curbear = reft.BearingInRadians + dbear;

            // Append positions along the length of the curve.
            List <IPointGeometry> result = new List <IPointGeometry>(nv);

            result.Add(start);

            for (int i = 0; i < nv; i++, curbear += dbear)
            {
                IPosition p = BasicGeom.Polar(center, curbear, radius);
                result.Add(PositionGeometry.Create(p));
            }

            result.Add(end);
            return(result.ToArray());
        }
예제 #6
0
        public static ILength GetDistance(ILineSegmentGeometry g, IPosition point)
        {
            double xp, yp;

            BasicGeom.GetPerpendicular(point.X, point.Y, g.Start.X, g.Start.Y, g.End.X, g.End.Y, out xp, out yp);
            double d = BasicGeom.Distance(new Position(xp, yp), point);

            return(new Length(d));
        }
예제 #7
0
        /// <summary>
        /// Checks if a position is coincident with a line segment
        /// </summary>
        /// <param name="p">The position to test</param>
        /// <param name="start">The start of the segment.</param>
        /// <param name="end">The end of the segment.</param>
        /// <param name="tolsq">The tolerance (squared) to use. Default is XYTOLSQ.</param>
        /// <returns>True if the test position lies somewhere along the segment.</returns>
        public static bool IsCoincidentWith(IPointGeometry p, IPointGeometry start, IPointGeometry end, double tolsq)
        {
            // Check whether there is exact coincidence at either end.
            if (p.IsCoincident(start) || p.IsCoincident(end))
            {
                return(true);
            }

            // Get the distance squared of a perpendicular dropped from
            // the test position to the segment (or the closest end if the
            // perpendicular does not fall ON the segment).
            return(BasicGeom.DistanceSquared(p.X, p.Y, start.X, start.Y, end.X, end.Y) < tolsq);
        }
예제 #8
0
        private PointGeometry[] CheckMultiSegmentEnds(PointGeometry[] pts)
        {
            if (pts.Length <= 2)
            {
                return(pts);
            }

            //double tol = (Constants.XYRES * Constants.XYRES);
            double tol = (0.001 * 0.001);

            PointGeometry[] res     = pts;
            bool            doCheck = true;

            while (doCheck && res.Length > 2)
            {
                doCheck = false;

                // If the start position coincides with the second segment, strip out
                // the second position.
                if (BasicGeom.DistanceSquared(res[0].X, res[0].Y, res[1].X, res[1].Y, res[2].X, res[2].Y) < tol)
                {
                    PointGeometry[] tmp = new PointGeometry[res.Length - 1];
                    tmp[0] = res[0];
                    Array.Copy(res, 2, tmp, 1, res.Length - 2);
                    res     = tmp;
                    doCheck = true;
                }
            }

            // If the end position coincides with the second last segment, strip out
            // the second last position.

            doCheck = true;

            while (doCheck && res.Length > 2)
            {
                doCheck = false;

                int last = res.Length - 1;
                if (BasicGeom.DistanceSquared(res[last].X, res[last].Y, res[last - 1].X, res[last - 1].Y, res[last - 2].X, res[last - 2].Y) < tol)
                {
                    PointGeometry[] tmp = new PointGeometry[res.Length - 1];
                    Array.Copy(res, 0, tmp, 0, res.Length - 2);
                    tmp[tmp.Length - 1] = res[last];
                    res     = tmp;
                    doCheck = true;
                }
            }

            return(res);
        }
예제 #9
0
        static double MinDistanceSquared(ICircularArcGeometry g, IPosition p)
        {
            // If the position lies in the arc sector, the minimum distance
            // is given by the distance to the circle. Otherwise the minimum
            // distance is the distance to the closest end of the arc.

            if (IsInSector(g, p, 0.0))
            {
                double dist   = BasicGeom.Distance(p, g.Circle.Center);
                double radius = g.Circle.Radius;
                return((dist - radius) * (dist - radius));
            }
            else
            {
                double d1 = BasicGeom.DistanceSquared(p, g.BC);
                double d2 = BasicGeom.DistanceSquared(p, g.EC);
                return(Math.Min(d1, d2));
            }
        }
예제 #10
0
        /// <summary>
        /// Gets geometric info for this geometry. For use during the formation
        /// of <c>Polygon</c> objects.
        /// </summary>
        /// <param name="window">The window of the geometry</param>
        /// <param name="area">The area (in square meters) between the geometry and the Y-axis.</param>
        /// <param name="length">The length of the geometry (in meters on the (projected) ground).</param>
        internal override void GetGeometry(out IWindow win, out double area, out double length)
        {
            IPosition start = Start;
            IPosition end   = End;

            // Define the window.
            win = new Window(start, end);

            // Define line length
            length = BasicGeom.Distance(start, end);

            // Define area to the left of the line.
            // Uses the mid-X of the segment to get the area left (signed).
            // If the line is directed up the way, it contributes a negative
            // area. If directed down, it contributes a positive area. So,
            // if flat, it contributes nothing.
            double dy = start.Y - end.Y;

            area = dy * 0.5 * (start.X + end.X);
        }
예제 #11
0
        public static bool GetPosition(IPosition start, IPosition end, double d, out IPosition result)
        {
            const double TOL = 0.000002;

            // Check for distance that is real close to the start (less
            // than 1 micron or so, since that's the smallest number we
            // can store).
            if (d < TOL)
            {
                result = start;
                return(d >= 0.0);
            }

            // Get length of the line
            double len = BasicGeom.Distance(start, end);

            // If the required distance is within the limiting tolerance
            // of the end of the line (or beyond it), return the end.
            if (d > len || (len - d) < TOL)
            {
                result = end;
                return(d <= (len + TOL));
            }

            // How far up the line do we need to go?
            double ratio = d / len;

            // Figure out the position
            double x1 = start.X;
            double y1 = start.Y;
            double x2 = end.X;
            double y2 = end.Y;
            double dx = x2 - x1;
            double dy = y2 - y1;

            result = new Position(x1 + ratio * dx, y1 + ratio * dy);

            return(true);
        }
예제 #12
0
        /// <summary>
        /// Gets the position that is a specific distance from the start of a circular arc.
        /// </summary>
        /// <param name="g">The geometry for the circular arc</param>
        /// <param name="distance">The distance from the start of the arc.</param>
        /// <param name="result">The position found</param>
        /// <returns>True if the distance is somewhere ON the arc. False if the distance
        /// was less than zero, or more than the arc length (in that case, the position
        /// found corresponds to the corresponding terminal point).</returns>
        public static bool GetPosition(ICircularArcGeometry g, ILength distance, out IPosition result)
        {
            // Allow 1 micron tolerance
            const double TOL = 0.000001;

            // Check for invalid distances.
            double d = distance.Meters;

            if (d < 0.0)
            {
                result = g.BC;
                return(false);
            }

            double clen = g.Length.Meters; // Arc length

            if (d > (clen + TOL))
            {
                result = g.EC;
                return(false);
            }

            // Check for limiting values (if you don't do this, minute
            // roundoff at the BC & EC can lead to spurious locations).
            // (although it's possible to use TINY here, use 1 micron
            // instead, since we can't represent position any better
            // than that).

            if (d < TOL)
            {
                result = g.BC;
                return(true);
            }

            if (Math.Abs(d - clen) < TOL)
            {
                result = g.EC;
                return(true);
            }

            // Get the bearing of the BC
            ICircleGeometry circle  = g.Circle;
            IPosition       c       = circle.Center;
            double          radius  = circle.Radius;
            double          bearing = BasicGeom.BearingInRadians(c, g.BC);

            // Add the angle that subtends the required distance (or
            // subtract if the curve goes anti-clockwise).
            if (g.IsClockwise)
            {
                bearing += (d / radius);
            }
            else
            {
                bearing -= (d / radius);
            }

            // Figure out the required point from the new bearing.
            result = BasicGeom.Polar(c, bearing, radius);
            return(true);
        }
예제 #13
0
 public ILength Distance(IPosition point)
 {
     return(new Length(BasicGeom.Distance(this, point)));
 }
예제 #14
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);
        }
예제 #15
0
        /// <summary>
        /// Draws a text string (annotation)
        /// </summary>
        /// <param name="display">The display to draw to</param>
        /// <param name="text">The item of text</param>
        public void Render(ISpatialDisplay display, IString text)
        {
            // Draw the outline if it's too small
            Font f = text.CreateFont(display);

            IPosition[] outline = text.Outline;

            if (outline == null)
            {
                // This is a bit of a hack that covers the Backsight.Editor.Annotation class...
                if (f == null)
                {
                    return;
                }

                // Note that the order you apply the transforms is significant...

                IPointGeometry pg = text.Position;
                PointF         p  = CreatePoint(display, pg);
                display.Graphics.TranslateTransform(p.X, p.Y);

                double rotation = text.Rotation.Degrees;
                display.Graphics.RotateTransform((float)rotation);

                StringFormat sf = text.Format;
                if (sf == null)
                {
                    sf = StringFormat.GenericTypographic;
                }

                string s = text.Text;
                display.Graphics.DrawString(s, f, Brush, 0, 0, sf);
                display.Graphics.ResetTransform();

                // TEST -- draw rotated 180 to see if that's all we need to do flip... looks good

                /*
                 * display.Graphics.TranslateTransform(p.X, p.Y);
                 * display.Graphics.RotateTransform((float)rotation+180);
                 * display.Graphics.DrawString(s, f, Brush, 0, 0, sf);
                 * display.Graphics.ResetTransform();
                 */
            }
            else
            {
                if (f == null)
                {
                    Render(display, outline);
                }
                else
                {
                    string s = text.Text;

                    // Note that the order you apply the transforms is significant...

                    PointF p = CreatePoint(display, outline[0]);
                    display.Graphics.TranslateTransform(p.X, p.Y);

                    double rotation = text.Rotation.Degrees;
                    display.Graphics.RotateTransform((float)rotation);

                    Size   size        = TextRenderer.MeasureText(s, f);
                    double groundWidth = BasicGeom.Distance(outline[0], outline[1]);
                    float  xScale      = display.LengthToDisplay(groundWidth) / (float)size.Width;
                    float  yScale      = f.Size / (float)size.Height;

                    // ScaleTransform doesn't like values of 0 (single character names lead to outline with no width,
                    // should really see if proper character width can be determined in that case).
                    if (xScale < Single.Epsilon)
                    {
                        xScale = yScale;
                    }

                    display.Graphics.ScaleTransform(xScale, yScale);

                    // I tried StringFormat.GenericDefault, but that seems to leave too much
                    // leading space.
                    display.Graphics.DrawString(s, f, Brush, 0, 0, StringFormat.GenericTypographic);
                    display.Graphics.ResetTransform();
                }
            }
        }
예제 #16
0
파일: Line.cs 프로젝트: 15831944/backsight
        /// <summary>
        /// The shortest distance between this object and the specified position.
        /// </summary>
        /// <param name="point">The position of interest</param>
        /// <returns>
        /// The shortest distance between the specified position and this object
        /// </returns>
        public ILength Distance(IPosition point)
        {
            double dsq = BasicGeom.MinDistanceSquared(this.PositionArray, point);

            return(new Length(Math.Sqrt(dsq)));
        }
예제 #17
0
        public static ILength GetLength(ILineSegmentGeometry g)
        {
            double d = BasicGeom.Distance(g.Start, g.End);

            return(new Length(d));
        }
예제 #18
0
 /// <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>
 /// <param name="tsq">The tolerance (squared) to use for checking whether the test point is
 /// coincident with the segment.</param>
 /// <returns>True if the distance from the test position to the line segment is less
 /// than the specified tolerance.</returns>
 private static bool IsCoincident(double testX, double testY, double xs, double ys, double xe, double ye, double tsq)
 {
     return(BasicGeom.DistanceSquared(testX, testY, xs, ys, xe, ye) < tsq);
 }
예제 #19
0
        public static ILength GetDistance(IMultiSegmentGeometry g, IPosition p)
        {
            double dsq = BasicGeom.MinDistanceSquared(g.Data, p);

            return(new Length(Math.Sqrt(dsq)));
        }
예제 #20
0
 public static double GetStartBearingInRadians(ICircularArcGeometry g)
 {
     return(BasicGeom.BearingInRadians(g.Circle.Center, g.First));
 }
예제 #21
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);
        }
예제 #22
0
        private ArcFeature ImportArc(Ntx.Line line, Operation creator, ILength tol)
        {
            Debug.Assert(line.IsCurve);
            IEntity what = GetEntityType(line, SpatialType.Line);

            // Get positions defining the arc
            PointGeometry[] pts = GetPositions(line);

            // Ignore zero-length lines
            if (HasZeroLength(pts))
            {
                return(null);
            }

            // Add a point at the center of the circle
            Ntx.Position  pos    = line.Center;
            PointGeometry pc     = new PointGeometry(pos.Easting, pos.Northing);
            PointFeature  center = EnsurePointExists(pc, tol, creator);

            // Calculate exact positions for the arc endpoints
            double          radius = line.Radius;
            ICircleGeometry cg     = new CircleGeometry(pc, radius);
            IPosition       bc     = CircleGeometry.GetClosestPosition(cg, pts[0]);
            IPosition       ec     = CircleGeometry.GetClosestPosition(cg, pts[pts.Length - 1]);

            // Round off to nearest micron
            PointGeometry bcg = PointGeometry.Create(bc);
            PointGeometry ecg = PointGeometry.Create(ec);

            // Ensure point features exist at both ends of the line.
            PointFeature ps = GetArcEndPoint(bcg, tol, creator);
            PointFeature pe = GetArcEndPoint(ecg, tol, creator);

            // Try to find a circle that's already been added by this import.
            Circle c = EnsureCircleExists(center, radius, tol, creator);

            // Determine which way the arc is directed
            bool iscw = LineStringGeometry.IsClockwise(pts, center);

            InternalIdValue id  = CadastralMapModel.Current.WorkingSession.AllocateNextId();
            ArcFeature      arc = new ArcFeature(creator, id, what, c, ps, pe, iscw);

            // The toological status of the incoming arc may override the status that the
            // constructor derived from the entity type
            arc.SetTopology(line.IsTopologicalArc);

            #if DEBUG
            // Confirm the NTX data was valid (ensure it's consistent with what we've imported)...

            double readRad = c.Radius;
            double calcRad = BasicGeom.Distance(c.Center, ps);
            Debug.Assert(Math.Abs(readRad - calcRad) < tol.Meters);

            foreach (IPointGeometry pg in pts)
            {
                ILength check = arc.Geometry.Distance(pg);
                Debug.Assert(check.Meters < tol.Meters);
            }
            #endif

            return(arc);
        }
예제 #23
0
 /// <summary>
 /// Creates a new <c>CircularArcGeometry</c> where the radius of the circle is defined as
 /// distance from the BC to the supplied circle center.
 /// </summary>
 /// <param name="center">The center of the circle</param>
 /// <param name="bc">The start of the arc (the circle passes through this point)</param>
 /// <param name="ec">The end of the arc (assumed to coincide with the circle)</param>
 /// <param name="isClockwise">Is the arc directed clockwise?</param>
 public CircularArcGeometry(IPointGeometry center, IPosition bc, IPosition ec, bool isClockwise)
     : this(new CircleGeometry(center, BasicGeom.Distance(center, bc)), bc, ec, isClockwise)
 {
 }
예제 #24
0
        public static ILength Distance(ICircleGeometry g, IPosition p)
        {
            double d = BasicGeom.Distance(g.Center, p);

            return(new Length(Math.Abs(d - g.Radius)));
        }
예제 #25
0
파일: Geom.cs 프로젝트: 15831944/backsight
        /// <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);
        }