/// <summary> /// Given the position of the start of this leg, along with an initial bearing, /// project the end of the leg, along with an exit bearing. /// </summary> /// <param name="pos">The position at the start of the leg.</param> /// <param name="bearing">The initial bearing (e.g. if the previous leg was also /// a straight leg from A to B, the bearing is from A through B).</param> /// <param name="sfac">Scaling factor to apply. Default=1.0</param> internal override void Project(ref IPosition pos, ref double bearing, double sfac) { // Add on any initial angle bearing = AddStartAngle(bearing); // Get the total length of the leg. double length = PrimaryFace.GetTotal() * sfac; // Figure out shifts. double dE = length * Math.Sin(bearing); double dN = length * Math.Cos(bearing); // Define the end position. pos = new Position(pos.X + dE, pos.Y + dN); }
/// <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> /// Given the position of the start of this leg, along with an initial bearing, get /// other positions (and bearings) relating to the circle. /// </summary> /// <param name="bc">The position for the BC.</param> /// <param name="sbearing">The position for the BC.</param> /// <param name="sfac">Scale factor to apply to distances.</param> /// <param name="center">Position of the circle centre.</param> /// <param name="bear2bc">Bearing from the centre to the BC.</param> /// <param name="ec">Position of the EC.</param> /// <param name="ebearing">Exit bearing.</param> internal void GetPositions(IPosition bc, double sbearing, double sfac, out IPosition center, out double bear2bc, out IPosition ec, out double ebearing) { // Have we got a cul-de-sac? bool cul = m_Metrics.IsCulDeSac; // Remember reverse bearing if we have a cul-de-sac. double revbearing = sbearing + Math.PI; // Initialize current bearing. double bearing = sbearing; // Counter-clockwise? bool ccw = (m_Metrics.IsClockwise == false); // Get radius in meters on the ground (and scale it). double radius = RadiusInMeters * sfac; // Get to the center (should really get to the P.I., but not sure // where that is when the curve is > half a circle -- need to // check some book). if (cul) { double halfAngle = m_Metrics.CentralAngle * 0.5; if (ccw) { bearing -= halfAngle; } else { bearing += halfAngle; } } else { double entryAngle = m_Metrics.EntryAngle; if (ccw) { bearing -= (Math.PI - entryAngle); } else { bearing += (Math.PI - entryAngle); } } double dE = radius * Math.Sin(bearing); double dN = radius * Math.Cos(bearing); double x = bc.X + dE; double y = bc.Y + dN; center = new Position(x, y); // Return the bearing from the center to the BC (the reverse // of the bearing we just used). bear2bc = bearing + Math.PI; // Now go out to the EC. For regular curves, figure out the // central angle by comparing the observed length of the curve // to the total circumference. if (cul) { double ca = m_Metrics.CentralAngle; if (ccw) { bearing -= (Math.PI - ca); } else { bearing += (Math.PI - ca); } } else { double length = PrimaryFace.GetTotal() * sfac; double circumf = radius * MathConstants.PIMUL2; double ca = MathConstants.PIMUL2 * (length / circumf); if (ccw) { bearing += (Math.PI - ca); } else { bearing -= (Math.PI - ca); } } // Define the position of the EC. x += (radius * Math.Sin(bearing)); y += (radius * Math.Cos(bearing)); ec = new Position(x, y); // Define the exit bearing. For cul-de-sacs, the exit bearing // is the reverse of the original bearing (lines are parallel). if (cul) { ebearing = revbearing; } else { // If we have a second angle, use that double angle = m_Metrics.ExitAngle; if (ccw) { ebearing = bearing - (Math.PI - angle); } else { ebearing = bearing + (Math.PI - angle); } } }