/// <summary> /// Draws the path on the specified display /// </summary> /// <param name="display">The display to draw to</param> internal void Render(ISpatialDisplay display) { EnsureAdjusted(); // Do nothing if the scale factor is undefined. if (Math.Abs(m_ScaleFactor) < MathConstants.TINY) { return; } // Initialize position to the start of the path. IPosition gotend = new Position(m_From); // Initial bearing is whatever the rotation is. double bearing = m_Rotation; for (int i = 0; i < m_Legs.Length; i++) { Leg leg = m_Legs[i]; // Include any angle specified at the start of the leg StraightLeg sLeg = (leg as StraightLeg); if (sLeg != null) { bearing = sLeg.AddStartAngle(bearing); } // Determine exit bearing for circular leg (do it now, in case an extra leg complicates matters below) double exitBearing = bearing; CircularLeg cLeg = (leg as CircularLeg); if (cLeg != null) { exitBearing = cLeg.GetExitBearing(gotend, bearing, m_ScaleFactor); } // Obtain geometry for each span and draw SpanInfo[] spans = leg.PrimaryFace.Spans; ILineGeometry[] sections = leg.GetSpanSections(gotend, bearing, m_ScaleFactor, spans); DrawSpans(display, spans, sections); // If we're dealing with the first face of a staggered leg, process the second face if (leg.AlternateFace != null) { spans = leg.AlternateFace.Spans; sections = leg.GetSpanSections(gotend, bearing, m_ScaleFactor, spans); DrawSpans(display, spans, sections); } // Get to the end of the leg gotend = sections[sections.Length - 1].End; bearing = exitBearing; } // Re-draw the terminal points to ensure that their color is on top. DrawEnds(display); }
/// <summary> /// Creates spatial features (points and lines) for this leg. The created /// features don't have any geometry. /// </summary> /// <param name="ff">The factory for creating new spatial features</param> /// <param name="startPoint">The point (if any) at the start of this leg. May be /// null in a situation where the preceding leg ended with an "omit point" directive.</param> /// <param name="lastPoint">The point that should be used for the very end /// of the leg (specify null if a point should be created at the end of the leg).</param> internal void CreateFeatures(FeatureFactory ff, PointFeature startPoint, PointFeature lastPoint) { // If we're dealing with a circular arc, create the underlying circle (and a // center point). The radius of the circle is undefined at this stage, but the // circle must be present so that created arcs can be cross-referenced to it. // Note that it is conceivable that the center point will end up coinciding with // another point in the map (it could even coincide with another circular leg in // the same connection path). CircularLeg cLeg = (this as CircularLeg); if (cLeg != null) { cLeg.CreateCircle(ff, this.ItemSequence.ToString()); } m_FirstSide.CreateFeatures(ff, startPoint, lastPoint); // Should the end of an alternate face share the end point of the primary face?? if (m_OtherSide != null) { // If the leg is right at the end of a connection path, the alternate face needs to // end at the specified point. Otherwise use the point that was created at the end // of the primary face (in unusual cases, it's possible that no point was created // there - in that case, the alternate face will create the end point). PointFeature endLegPoint = lastPoint; if (endLegPoint == null) { endLegPoint = m_FirstSide.GetEndPoint(ff.Creator); } m_OtherSide.CreateFeatures(ff, startPoint, endLegPoint); } }
/// <summary> /// Creates a circular leg. /// </summary> /// <param name="items">Array of path items.</param> /// <param name="si">Index to the item where the leg data starts.</param> /// <param name="nexti">Index of the item where the next leg starts.</param> /// <returns>The new leg.</returns> static CircularLeg CreateCircularLeg(PathItem[] items, int si, out int nexti) { // Confirm that the first item refers to the BC. if (items[si].ItemType != PathItemType.BC) throw new Exception("PathParser.CreateCircularLeg - Not starting at BC"); // The BC has to be followed by at least 3 items: angle, radius // and EC (add an extra 1 to account for 0-based indexing). if (items.Length < si + 4) throw new Exception("PathParser.CreateCircularLeg - Insufficient curve data"); double bangle = 0.0; // Angle at BC double cangle = 0.0; // Central angle double eangle = 0.0; // Angle at EC bool twoangles = false; // True if bangle & eangle are both defined. bool clockwise = true; // True if curve is clockwise int irad = 0; // Index of the radius item bool cul = false; // True if cul-de-sac case // Point to item following the BC. nexti = si + 1; PathItemType type = items[nexti].ItemType; // If the angle following the BC is a central angle if (type == PathItemType.CentralAngle) { // We have a cul-de-sac cul = true; // Get the central angle. cangle = items[nexti].Value; nexti++; } else if (type == PathItemType.BcAngle) { // Get the entry angle. bangle = items[nexti].Value; nexti++; // Does an exit angle follow? if (items[nexti].ItemType == PathItemType.EcAngle) { eangle = items[nexti].Value; twoangles = true; nexti++; } } else { // The field after the BC HAS to be an angle. throw new ApplicationException("Angle does not follow BC"); } // Must be followed by radius. if (items[nexti].ItemType != PathItemType.Radius) throw new ApplicationException("Radius does not follow angle"); // Get the radius Distance radius = items[nexti].GetDistance(); irad = nexti; nexti++; // The item after the radius indicates whether the curve is counterclockwise. if (items[nexti].ItemType == PathItemType.CounterClockwise) { nexti++; clockwise = false; } // Get the leg ID. int legnum = items[si].LegNumber; // How many distances have we got? int ndist = 0; for (; nexti < items.Length && items[nexti].LegNumber == legnum; nexti++) { if (items[nexti].IsDistance) ndist++; } // Create the leg. CircularLeg leg = new CircularLeg(radius, clockwise, ndist); CircularLegMetrics metrics = leg.Metrics; // Set the entry angle or the central angle, depending on what we have. if (cul) metrics.SetCentralAngle(cangle); else metrics.SetEntryAngle(bangle); // Assign second angle if we have one. if (twoangles) metrics.SetExitAngle(eangle); // Assign each distance, starting one after the radius. ndist = 0; for (int i = irad + 1; i < nexti; i++) { Distance dist = items[i].GetDistance(); if (dist != null) { // See if there is a qualifier after the distance LegItemFlag qual = LegItemFlag.Null; if (i + 1 < nexti) { PathItemType nexttype = items[i + 1].ItemType; if (nexttype == PathItemType.MissConnect) qual = LegItemFlag.MissConnect; if (nexttype == PathItemType.OmitPoint) qual = LegItemFlag.OmitPoint; } leg.PrimaryFace.SetDistance(dist, ndist, qual); ndist++; } } // Return the new leg. return leg; }
/// <summary> /// Creates a circular leg. /// </summary> /// <param name="items">Array of path items.</param> /// <param name="si">Index to the item where the leg data starts.</param> /// <param name="nexti">Index of the item where the next leg starts.</param> /// <returns>The new leg.</returns> static CircularLeg CreateCircularLeg(PathItem[] items, int si, out int nexti) { // Confirm that the first item refers to the BC. if (items[si].ItemType != PathItemType.BC) { throw new Exception("PathParser.CreateCircularLeg - Not starting at BC"); } // The BC has to be followed by at least 3 items: angle, radius // and EC (add an extra 1 to account for 0-based indexing). if (items.Length < si + 4) { throw new Exception("PathParser.CreateCircularLeg - Insufficient curve data"); } double bangle = 0.0; // Angle at BC double cangle = 0.0; // Central angle double eangle = 0.0; // Angle at EC bool twoangles = false; // True if bangle & eangle are both defined. bool clockwise = true; // True if curve is clockwise int irad = 0; // Index of the radius item bool cul = false; // True if cul-de-sac case // Point to item following the BC. nexti = si + 1; PathItemType type = items[nexti].ItemType; // If the angle following the BC is a central angle if (type == PathItemType.CentralAngle) { // We have a cul-de-sac cul = true; // Get the central angle. cangle = items[nexti].Value; nexti++; } else if (type == PathItemType.BcAngle) { // Get the entry angle. bangle = items[nexti].Value; nexti++; // Does an exit angle follow? if (items[nexti].ItemType == PathItemType.EcAngle) { eangle = items[nexti].Value; twoangles = true; nexti++; } } else { // The field after the BC HAS to be an angle. throw new ApplicationException("Angle does not follow BC"); } // Must be followed by radius. if (items[nexti].ItemType != PathItemType.Radius) { throw new ApplicationException("Radius does not follow angle"); } // Get the radius Distance radius = items[nexti].GetDistance(); irad = nexti; nexti++; // The item after the radius indicates whether the curve is counterclockwise. if (items[nexti].ItemType == PathItemType.CounterClockwise) { nexti++; clockwise = false; } // Get the leg ID. int legnum = items[si].LegNumber; // How many distances have we got? int ndist = 0; for (; nexti < items.Length && items[nexti].LegNumber == legnum; nexti++) { if (items[nexti].IsDistance) { ndist++; } } // Create the leg. CircularLeg leg = new CircularLeg(radius, clockwise, ndist); CircularLegMetrics metrics = leg.Metrics; // Set the entry angle or the central angle, depending on what we have. if (cul) { metrics.SetCentralAngle(cangle); } else { metrics.SetEntryAngle(bangle); } // Assign second angle if we have one. if (twoangles) { metrics.SetExitAngle(eangle); } // Assign each distance, starting one after the radius. ndist = 0; for (int i = irad + 1; i < nexti; i++) { Distance dist = items[i].GetDistance(); if (dist != null) { // See if there is a qualifier after the distance LegItemFlag qual = LegItemFlag.Null; if (i + 1 < nexti) { PathItemType nexttype = items[i + 1].ItemType; if (nexttype == PathItemType.MissConnect) { qual = LegItemFlag.MissConnect; } if (nexttype == PathItemType.OmitPoint) { qual = LegItemFlag.OmitPoint; } } leg.PrimaryFace.SetDistance(dist, ndist, qual); ndist++; } } // Return the new leg. return(leg); }