Exemple #1
0
        // If the specified position isn't actually on the arc, the length is to the
        // position when it's projected onto the arc (i.e. the perpendicular position)
        public static ILength GetLength(ICircularArcGeometry g, IPosition asFarAs)
        {
            ICircleGeometry circle = g.Circle;
            double          radius = circle.Radius;

            if (asFarAs == null)
            {
                // If the BC coincides with the EC, it's possible the arc has zero
                // length. As a matter of convention, counter-clockwise arcs will
                // be regarded as having a length of zero in that case. Meanwhile,
                // clockwise arcs will have a length that corresponds to the complete
                // circumference of the circle.

                if (g.BC.IsCoincident(g.EC))
                {
                    if (g.IsClockwise)
                    {
                        return(CircleGeometry.GetLength(circle));
                    }
                    else
                    {
                        return(Backsight.Length.Zero);
                    }
                }

                return(new Length(radius * g.SweepAngleInRadians));
            }

            // Express the position of the BC in a local coordinate system.
            IPosition  c  = circle.Center;
            QuadVertex bc = new QuadVertex(c, g.BC, radius);

            // Calculate the clockwise angle to the desired point.
            QuadVertex to  = new QuadVertex(c, asFarAs, radius);
            double     ang = to.BearingInRadians - bc.BearingInRadians;

            if (ang < 0.0)
            {
                ang += MathConstants.PIMUL2;
            }

            // If the curve is actually anti-clockwise, take the complement.
            if (!g.IsClockwise)
            {
                ang = MathConstants.PIMUL2 - ang;
            }

            return(new Length(radius * ang));
        }
Exemple #2
0
 /// <summary>
 /// The distance from the specified position to the perimeter of this circle.
 /// </summary>
 /// <param name="p">The position of interest</param>
 /// <returns>The distance from the specified position to the perimeter of
 /// this circle.</returns>
 public ILength Distance(IPosition p)
 {
     return(CircleGeometry.Distance(this, p));
 }
Exemple #3
0
 public void Render(ISpatialDisplay display, IDrawStyle style)
 {
     CircleGeometry.Render(this, display, style);
 }
 // Circle
 internal uint Intersect(IPointGeometry center, double radius)
 {
     ICircleGeometry circle = new CircleGeometry(center, radius);
     return m_IntersectedObject.LineGeometry.IntersectCircle(this, circle);
 }
Exemple #5
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;
        }
Exemple #6
0
        public static IWindow GetExtent(ICircularArcGeometry g)
        {
            // If the curve is a complete circle, just define it the easy way.
            if (g.BC.IsCoincident(g.EC))
            {
                return(CircleGeometry.GetExtent(g.Circle));
            }

            IPosition bcp    = g.BC;
            IPosition ecp    = g.EC;
            IPosition centre = g.Circle.Center;

            // Initialize the window with the start location.
            Window win = new Window(bcp);

            // Expand using the end location
            win.Union(ecp);

            // If the curve is completely within one quadrant, we're done.
            QuadVertex bc = new QuadVertex(centre, bcp);
            QuadVertex ec = new QuadVertex(centre, ecp);

            Quadrant qbc = bc.Quadrant;
            Quadrant qec = ec.Quadrant;

            if (qbc == qec)
            {
                if (g.IsClockwise)
                {
                    if (bc.GetTanAngle() < ec.GetTanAngle())
                    {
                        return(win);
                    }
                }
                else
                {
                    if (ec.GetTanAngle() < bc.GetTanAngle())
                    {
                        return(win);
                    }
                }
            }

            // Get the window of the circle
            IWindow circle = CircleGeometry.GetExtent(g.Circle);

            // If the curve is anticlockwise, switch the quadrants for BC & EC
            if (!g.IsClockwise)
            {
                Quadrant temp = qbc;
                qbc = qec;
                qec = temp;
            }

            // Expand the window, depending on which quadrants the start &
            // end points fall in. The lack of breaks in the inner switches
            // is intentional (e.g. if start & end both fall in Quadrant.NorthEast,
            // the window we want is the complete circle, having checked above
            // for the case where the arc is JUST in Quadrant.NorthEast).

            // Define do-nothing values for the Union's below
            double wx = win.Min.X;
            double wy = win.Min.Y;

            if (qbc == Quadrant.NE)
            {
                switch (qec)
                {
                case Quadrant.NE:
                    win.Union(wx, circle.Max.Y);
                    goto case Quadrant.NW;

                case Quadrant.NW:
                    win.Union(circle.Min.X, wy);
                    goto case Quadrant.SW;

                case Quadrant.SW:
                    win.Union(wx, circle.Min.Y);
                    goto case Quadrant.SE;

                case Quadrant.SE:
                    win.Union(circle.Max.X, wy);
                    break;
                }
            }
            else if (qbc == Quadrant.SE)
            {
                switch (qec)
                {
                case Quadrant.SE:
                    win.Union(circle.Max.X, wy);
                    goto case Quadrant.NE;

                case Quadrant.NE:
                    win.Union(wx, circle.Max.Y);
                    goto case Quadrant.NW;

                case Quadrant.NW:
                    win.Union(circle.Min.X, wy);
                    goto case Quadrant.SW;

                case Quadrant.SW:
                    win.Union(wx, circle.Min.Y);
                    break;
                }
            }
            else if (qbc == Quadrant.SW)
            {
                switch (qec)
                {
                case Quadrant.SW:
                    win.Union(wx, circle.Min.Y);
                    goto case Quadrant.SE;

                case Quadrant.SE:
                    win.Union(circle.Max.X, wy);
                    goto case Quadrant.NE;

                case Quadrant.NE:
                    win.Union(wx, circle.Max.Y);
                    goto case Quadrant.NW;

                case Quadrant.NW:
                    win.Union(circle.Min.X, wy);
                    break;
                }
            }
            else if (qbc == Quadrant.NW)
            {
                switch (qec)
                {
                case Quadrant.NW:
                    win.Union(circle.Min.X, wy);
                    goto case Quadrant.SW;

                case Quadrant.SW:
                    win.Union(wx, circle.Min.Y);
                    goto case Quadrant.SE;

                case Quadrant.SE:
                    win.Union(circle.Max.X, wy);
                    goto case Quadrant.NE;

                case Quadrant.NE:
                    win.Union(wx, circle.Max.Y);
                    break;
                }
            }

            return(win);
        }
Exemple #7
0
        public void Render(ISpatialDisplay display, IDrawStyle style)
        {
            if (this.category == CadastralLineCategory.Radial)
                style = new DottedStyle(style.LineColor);

            if (m_Center == null)
                style.Render(display, this.PositionArray);
            else
            {
                // radius less than zero may represent a counter-clockwise direction
                bool isClockwise = (this.radius > 0.0);

                // Define a circular arc that is assumed to run clockwise.
                ICircleGeometry circle = new CircleGeometry(m_Center.Geometry, Math.Abs(this.radius));
                ICircularArcGeometry arc = new CircularArcGeometry(circle, m_From.Geometry, m_To.Geometry, isClockwise);

                // Assume clockwise, see what it looks like
                style.Render(display, arc);
            }

                /*
            else
            {
                if (!this.arcLengthSpecified)
                    throw new ApplicationException("Cannot determine arc direction");

                // Define a circular arc that is assumed to run clockwise.
                CircleGeometry circle = new CircleGeometry(m_Center.Geometry, this.radius);
                CircularArcGeometry arc = new CircularArcGeometry(circle, m_From.Geometry, m_To.Geometry, true);

                // Assume clockwise, see what it looks like
                new DrawStyle(Color.Red).Render(display, arc);

                //double arcLength = arc.Length.Meters;
                //double othLength = circle.Length.Meters;

                //// Get the arc length in meters (TODO: need to access file header to determine how to convert lengths)
                //if (Math.Abs(othLength - this.arcLength) < Math.Abs(arcLength - this.arcLength))
                //    arc.IsClockwise = false;
            }
                 */
        }
        /// <summary>
        /// Calculates the intersection point.
        /// </summary>
        /// <param name="dir">Direction observation.</param>
        /// <param name="distance">Distance observation.</param>
        /// <param name="from">The point the distance was observed from.</param>
        /// <param name="usedefault">True if the default intersection is required (the one 
        /// closer to the origin of the direction line). False for the other one (if any).</param>
        /// <param name="xsect">The position of the intersection (if any).</param>
        /// <param name="xsect1">The 1st choice intersection (if any).</param>
        /// <param name="xsect2">The 2nd choice intersection (if any).</param>
        /// <returns>True if intersections were calculated. False if the distance circles
        /// don't intersect.</returns>
        internal static bool Calculate(Direction dir, Observation distance, PointFeature from, bool usedefault,
            out IPosition xsect, out IPosition xsect1, out IPosition xsect2)
        {
            // Initialize intersection positions.
            xsect = xsect1 = xsect2 = null;

            // Get the distance.
            double dist = distance.GetDistance(from).Meters;
            if (dist < Constants.TINY)
                return false;

            // Form circle with a radius that matches the observed distance.
            ICircleGeometry circle = new CircleGeometry(from, dist);

            // See if there is actually an intersection between the direction & the circle.
            IPosition x1, x2;
            uint nx = dir.Intersect(circle, out x1, out x2);
            if (nx==0)
                return false;

            // If we have 2 intersections, and we need the non-default one, pick up the 2nd
            // intersection. If only 1 intersection, use that, regardless of the setting for
            // the "use default" flag.

            if (nx==2 && !usedefault)
                xsect = x2;
            else
                xsect = x1;

            // Return if the distance is an offset point.
            OffsetPoint offset = (distance as OffsetPoint);

            if (offset!=null)
            {
                xsect1 = x1;
                xsect2 = x2;
                return true;
            }

            // Reduce observed distance to the mapping plane.
            ISpatialSystem sys = CadastralMapModel.Current.SpatialSystem;
            dist = dist * sys.GetLineScaleFactor(from, xsect);

            // And calculate the exact intersection (like above)...
            // Form circle with a radius that matches the reduced distance.
            ICircleGeometry circlep = new CircleGeometry(from, dist);

            // See if there is actually an intersection between the direction & the circle.
            nx = dir.Intersect(circlep, out x1, out x2);
            if (nx==0)
                return false;

            // If we have 2 intersections, and we need the non-default one, pick up the 2nd
            // intersection. If only 1 intersection, use that, regardless of the setting for
            // the "use default" flag.

            if (nx==2 && !usedefault)
                xsect = x2;
            else
                xsect = x1;

            xsect1 = x1;
            xsect2 = x2;

            return true;
        }
        /// <summary>
        /// Calculates intersection points.
        /// </summary>
        /// <param name="dist1">1st distance observation.</param>
        /// <param name="from1">The point the 1st distance was observed from.</param>
        /// <param name="dist2">2nd distance observation.</param>
        /// <param name="from2">The point the 2nd distance was observed from.</param>
        /// <param name="usedefault">True if the default intersection is required (the one that has the
        /// lowest bearing with respect to the 2 from points). False for the other one (if any).</param>
        /// <param name="xsect">The position of the intersection (if any).</param>
        /// <param name="xsect1">The 1st choice intersection (if any).</param>
        /// <param name="xsect2">The 2nd choice intersection (if any).</param>
        /// <returns>True if intersections were calculated. False if the distance circles
        /// don't intersect.</returns>
        internal static bool Calculate(Observation dist1, PointFeature from1, Observation dist2, PointFeature from2, bool usedefault,
            out IPosition xsect, out IPosition xsect1, out IPosition xsect2)
        {
            // Initialize intersection positions.
            xsect = xsect1 = xsect2 = null;

            // Get the 2 distances.
            double d1 = dist1.GetDistance(from1).Meters;
            double d2 = dist2.GetDistance(from2).Meters;
            if (d1 < Constants.TINY || d2 < Constants.TINY)
                return false;

            // Form circles with radii that match the observed distances.
            ICircleGeometry circle1 = new CircleGeometry(from1, d1);
            ICircleGeometry circle2 = new CircleGeometry(from2, d2);

            // See if there is actually an intersection between the two circles.
            IPosition x1, x2;
            uint nx = IntersectionHelper.Intersect(circle1, circle2, out x1, out x2);
            if (nx==0)
                return false;

            // If we have 2 intersections, and we need the non-default one, pick up the 2nd
            // intersection. If only 1 intersection, use that, regardless of the setting for
            // the "use default" flag.

            if (nx==2 && !usedefault)
                xsect = x2;
            else
                xsect = x1;

            // Return if both distances are offset points.
            OffsetPoint offset1 = (dist1 as OffsetPoint);
            OffsetPoint offset2 = (dist2 as OffsetPoint);

            if (offset1!=null && offset2!=null)
            {
                xsect1 = x1;
                xsect2 = x2;
                return true;
            }

            // Reduce observed distances to the mapping plane.
            ISpatialSystem sys = CadastralMapModel.Current.SpatialSystem;

            if (offset1==null)
                d1 = d1 * sys.GetLineScaleFactor(from1, xsect);

            if (offset2==null)
                d2 = d2 * sys.GetLineScaleFactor(from2, xsect);

            // And calculate the exact intersection (like above)...
            // Form circles with radii that match the observed distances.
            ICircleGeometry circle1p = new CircleGeometry(from1, d1);
            ICircleGeometry circle2p = new CircleGeometry(from2, d2);

            // See if there is still an intersection between the two circles.
            nx = IntersectionHelper.Intersect(circle1p, circle2p, out x1, out x2);
            if (nx==0)
                return false;

            // If we have 2 intersections, and we need the non-default one, pick up the 2nd
            // intersection. If only 1 intersection, use that, regardless of the setting for
            // the "use default" flag.

            if (nx==2 && !usedefault)
                xsect = x2;
            else
                xsect = x1;

            xsect1 = x1;
            xsect2 = x2;

            return true;
        }
        /// <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;
        }