コード例 #1
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));
        }
コード例 #2
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));
            }
        }
コード例 #3
0
ファイル: SegmentGeometry.cs プロジェクト: 15831944/backsight
        /// <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);
        }
コード例 #4
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);
        }
コード例 #5
0
ファイル: CircleGeometry.cs プロジェクト: 15831944/backsight
        public static ILength Distance(ICircleGeometry g, IPosition p)
        {
            double d = BasicGeom.Distance(g.Center, p);

            return(new Length(Math.Abs(d - g.Radius)));
        }
コード例 #6
0
ファイル: NtxImport.cs プロジェクト: 15831944/backsight
        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);
        }
コード例 #7
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);
        }
コード例 #8
0
ファイル: PointGeometry.cs プロジェクト: 15831944/backsight
 public ILength Distance(IPosition point)
 {
     return(new Length(BasicGeom.Distance(this, point)));
 }
コード例 #9
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);
        }
コード例 #10
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)
 {
 }
コード例 #11
0
        public static ILength GetLength(ILineSegmentGeometry g)
        {
            double d = BasicGeom.Distance(g.Start, g.End);

            return(new Length(d));
        }
コード例 #12
0
ファイル: DrawStyle.cs プロジェクト: 15831944/backsight
        /// <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();
                }
            }
        }