/// <summary> /// Obtains the geometry for spans along an alternate face attached to this leg. /// </summary> /// <param name="legStart">The position for the start of the leg. /// <param name="legEnd">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 legStart, IPosition legEnd, SpanInfo[] spans) { var result = new ILineGeometry[spans.Length]; Debug.Assert(AlternateFace != null); // Define the arc that corresponds to the complete leg (the circle should have been // already defined when we processed the primary face_. Debug.Assert(Circle != null); var arc = new CircularArcGeometry(Circle, legStart, legEnd, m_Metrics.IsClockwise); // Handle case where the leg is a cul-de-sac with no observed spans on the alternate face if (spans.Length == 1 && spans[0].ObservedDistance == null) { result[0] = arc; return(result); } // Get the required arc length (in meters on the ground) double len = arc.Length.Meters; // Get the observed arc length (in meters on the ground) double obs = AlternateFace.GetTotal(); // Get the adjustment factor for stretching-compressing the observed distances. double factor = len / obs; // Define start of first arc. IPosition sPos = legStart; IPosition ePos = null; // Haven't got anywhere yet. double totobs = 0.0; // Figure out the location of each span for (int i = 0; i < result.Length; i++, sPos = ePos) { if (i == result.Length - 1) { ePos = legEnd; } else { // Add on the unscaled distance totobs += spans[i].ObservedDistance.Meters; // Scale to the required length for the overall leg double elen = totobs * factor; // Define the end position. arc.GetPosition(new Length(elen), out ePos); } result[i] = new CircularArcGeometry(Circle, sPos, ePos, m_Metrics.IsClockwise); } return(result); }
internal override void Render(ISpatialDisplay display, IDrawStyle style) { // At scales larger than 1:1000, it may be advisable to draw an approximation (since // the drawing methods tend to reveal small non-existent glitches at larger scales)... // Draw an approximation of the curve (such that the chord-to-circumference // distance does not exceed 0.2mm at draw scale). /* * ILength tol = new Length(display.MapScale * 0.0002); * IPointGeometry[] pts = CircularArcGeometry.GetApproximation(this, tol); * new LineStringGeometry(pts).Render(display, style); */ CircularArcGeometry.Render(this, display, style); }
internal void Draw() // was Paint { // Nothing to do if parallel points undefined. if (m_South == null || m_North == null) { return; } Debug.Assert(m_Line != null); ISpatialDisplay draw = m_Cmd.ActiveDisplay; IDrawStyle solidStyle = EditingController.Current.Style(Color.Magenta); IDrawStyle dottedStyle = new DottedStyle(); ArcFeature arc = m_Line.GetArcBase(); if (arc != null) { // The parallel portion is solid, while the remaining portion of the circle is dotted. CircularArcGeometry cg = new CircularArcGeometry(arc.Circle.Center, m_South, m_North, arc.IsClockwise); solidStyle.Render(draw, cg); cg.IsClockwise = !cg.IsClockwise; dottedStyle.Render(draw, cg); } else { // What's the bearing from the start to the end of the parallel? double bearing = Geom.BearingInRadians(m_South, m_North); // What's the max length of a diagonal crossing the entire screen? double maxdiag = m_Cmd.MaxDiagonal; // Project to a point below the southern end of the parallel, as // well as a point above the northern end. IPosition below = Geom.Polar(m_South, bearing + Constants.PI, maxdiag); IPosition above = Geom.Polar(m_North, bearing, maxdiag); LineSegmentGeometry.Render(below, m_South, draw, dottedStyle); LineSegmentGeometry.Render(m_South, m_North, draw, solidStyle); LineSegmentGeometry.Render(m_North, above, draw, dottedStyle); // If we have an offset point, draw it in green. if (m_Point != null) { m_Point.Draw(draw, Color.Green); } } }
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> /// 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); }
/// <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); }
/// <summary> /// Draws the current state of the edit /// </summary> internal void Draw() { Debug.Assert(m_Line != null); ISpatialDisplay view = ActiveDisplay; // Figure out the positions for the ends of the parallel line (if any) ... // Assume we already know both terminals. IPosition start = m_Term1; IPosition end = m_Term2; // If either one is undefined, but a dialog for it is active, // try to get the terminal from there instead. if (m_TermDial1 != null && start == null) { start = m_TermDial1.TerminalPosition; } if (m_TermDial2 != null && end == null) { end = m_TermDial2.TerminalPosition; } // If they weren't actually defined, use the parallel points instead. if (start == null) { start = m_Par1; } if (end == null) { end = m_Par2; } // If those weren't defined either, try to calculate them now. if (end == null && Calculate()) { start = m_Par1; end = m_Par2; } // Any offset point if (m_OffsetPoint != null) { m_OffsetPoint.Draw(view, Color.Green); } // Everything else should draw in usual command-style colour. IDrawStyle style = EditingController.Current.Style(Color.Magenta); IDrawStyle dottedStyle = new DottedStyle(); // If the reference line is a curve, get the curve info. ArcFeature arc = m_Line.GetArcBase(); if (arc != null) { bool iscw = arc.IsClockwise; // Reverse the direction if necessary. if (m_IsReversed) { iscw = !iscw; } // Draw the parallel line (the rest of the circle being dotted). if (start != null) { CircularArcGeometry parArc = new CircularArcGeometry(arc.Circle, start, end, iscw); style.Render(view, parArc); parArc.IsClockwise = !parArc.IsClockwise; dottedStyle.Render(view, parArc); } } else { // PARALLEL IS STRAIGHT // If we've got something, figure out positions for dotted portion. if (start != null) { // What's the max length of a diagonal crossing the entire screen? double maxdiag = this.MaxDiagonal; // What's the bearing from the start to the end of the parallel? double bearing = Geom.BearingInRadians(start, end); // Project to a point before the start end of the parallel, as // well as a point after the end. IPosition before = Geom.Polar(start, bearing + Constants.PI, maxdiag); IPosition after = Geom.Polar(end, bearing, maxdiag); LineSegmentGeometry.Render(before, start, view, dottedStyle); LineSegmentGeometry.Render(start, end, view, style); LineSegmentGeometry.Render(end, after, view, dottedStyle); } } // Draw terminal positions (if defined). if (m_Term1 != null) { style.Render(view, m_Term1); } if (m_Term2 != null) { style.Render(view, m_Term2); } // The terminal lines. if (m_TermLine1 != null) { m_TermLine1.Render(view, style); } if (m_TermLine2 != null) { m_TermLine2.Render(view, style); } // Do the active dialog last so their stuff draws on top. if (m_ParDial != null) { m_ParDial.Draw(); } if (m_TermDial1 != null) { m_TermDial1.Draw(); } if (m_TermDial2 != null) { m_TermDial2.Draw(); } }
/// <summary> /// Loads a list of positions with data for this line. /// </summary> /// <param name="positions">The list to append to</param> /// <param name="reverse">Should the data be appended in reverse order?</param> /// <param name="wantFirst">Should the first position be appended? (last if <paramref name="reverse"/> is true)</param> /// <param name="arcTol">Tolerance for approximating circular arcs (the maximum chord-to-circumference distance).</param> internal override void AppendPositions(List <IPosition> positions, bool reverse, bool wantFirst, ILength arcTol) { IPointGeometry[] approx = CircularArcGeometry.GetApproximation(this, arcTol); MultiSegmentGeometry.AppendPositions(approx, positions, reverse, wantFirst); }
/// <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; // Get the window of the circle that this curve lies on. IWindow cwin = m_Circle.Extent; // Get a window for the horizontal segment. IWindow segwin = new Window(s, e); // Return if the windows don't overlap. if (!cwin.IsOverlap(segwin)) { return(false); } // Return if the the segment is to the west of the circle's window. if (segwin.Max.X < cwin.Min.X) { return(false); } // 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); } // Locate up to two intersections of the horizontal segment with the circle. IPosition x1 = null; IPosition x2 = null; uint nx = hseg.Intersect(m_Circle, ref x1, ref x2); // Return if no intersections if (nx == 0) { return(false); } // Return if this arc curve is a complete circle. if (this.IsCircle) { return(false); } // Check whether the first intersection lies on this arc. If // so, update the end of segment, and return. if (CircularArcGeometry.IsInSector(this, x1, 0.0)) { e = new PointGeometry(x1); return(true); } // If we got two intersections with the circle, check the // second intersection as well. if (nx == 2 && CircularArcGeometry.IsInSector(this, x2, 0.0)) { e = new PointGeometry(x2); return(true); } return(false); }
// 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) internal override ILength GetLength(IPosition asFarAs) { return(CircularArcGeometry.GetLength(this, asFarAs)); }
/// <summary> /// Gets the position that is a specific distance from the start of this line. /// </summary> /// <param name="distance">The distance from the start of the line.</param> /// <param name="result">The position found</param> /// <returns>True if the distance is somewhere ON the line. False if the distance /// was less than zero, or more than the line length (in that case, the position /// found corresponds to the corresponding terminal point).</returns> internal override bool GetPosition(ILength distance, out IPosition result) { return(CircularArcGeometry.GetPosition(this, distance, out result)); }
public override ILength Distance(IPosition point) { return(CircularArcGeometry.GetDistance(this, point)); }
internal void Draw() { ISpatialDisplay display = m_Cmd.ActiveDisplay; // Draw the line we're extending in a special colour (any highlighting it // originally had should have been removed during LineExtensionControl_Load) if (m_ExtendLine != null) { m_ExtendLine.Draw(display, Color.DarkBlue); } // If we're doing an update, draw the original extension in grey. LineExtensionOperation pop = UpdateOp; if (pop != null) { LineFeature origLine = pop.NewLine; if (origLine != null) { origLine.Draw(display, Color.Gray); } PointFeature origPoint = pop.NewPoint; if (origPoint != null) { origPoint.Draw(display, Color.Gray); } } // Calculate the start and end points of the extension, initially // assuming that it's a straight line extension. IPosition start, end; if (LineExtensionUI.Calculate(m_ExtendLine, m_IsExtendFromEnd, m_Length, out start, out end)) { // Draw the straight extension line IDrawStyle style = (m_WantLine ? new DrawStyle(Color.Magenta) : new DottedStyle(Color.Magenta)); LineSegmentGeometry seg = new LineSegmentGeometry(start, end); seg.Render(display, style); } else { // Perhaps it's a circular arc ... IPosition center; bool iscw; if (LineExtensionUI.Calculate(m_ExtendLine, m_IsExtendFromEnd, m_Length, out start, out end, out center, out iscw)) { // And draw the curve. IDrawStyle style = (m_WantLine ? new DrawStyle(Color.Magenta) : new DottedStyle(Color.Magenta)); IPointGeometry c = PointGeometry.Create(center); CircularArcGeometry arc = new CircularArcGeometry(c, start, end, iscw); arc.Render(display, style); } else if (m_ExtendLine != null) { // Get the position we're extending from. end = (m_IsExtendFromEnd ? m_ExtendLine.EndPoint : m_ExtendLine.StartPoint); } } // If we actually got something, draw the end point. if (end != null) { IDrawStyle style = m_Cmd.Controller.DrawStyle; style.FillColor = Color.Magenta; style.Render(display, end); } }