/// <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); }
/* * // @mfunc Create transient CeMiscText objects for any observed * // angles that are part of this leg. * // * // The caller is responsible for deleting the text * // objects once done with them. * // * // @parm The point the observation must be made from. * // Specify 0 for all points. * // @parm The operation this leg belongs to. * // @parm Scale factor to apply to the leg. * // @parm The position of a backsight prior to the BC (may * // be undefined). * // @parm The position of the start of the leg. * // @parm The bearing to the start of the leg. Updated to * // refer to the bearing to the end of the leg. * // @parm The position of the end of the leg. * // @parm List of pointers to created text objects (appended to). * // @parm Should lines be produced too? * // * // @rdesc TRUE if the specified from point was encountered (this * // does not necessarily mean that any text needed to be * // generated for it). * * LOGICAL CeStraightLeg::CreateAngleText ( const CePoint* const pFrom * , const CeOperation& op * , const FLOAT8 sfac * , const CeVertex& bs * , const CeVertex& from * , FLOAT8& bearing * , CeVertex& to * , CPtrList& text * , const LOGICAL wantLinesToo ) const { * * // Project to the end of the leg. * to = from; * this->Project(to,bearing,sfac); * * // If a from point has been specified, and this leg does * // not start at it, just return. * if ( pFrom && GetpStartPoint(op)!=pFrom ) return FALSE; * * // Return if this leg does not have an initial angle. * const FLOAT8 angle = fabs(m_StartAngle); * if ( angle<TINY ) return TRUE; * * // Return if the angle is real-close to a right angle * if ( fabs(angle-PIDIV2 )<0.000001 || * fabs(angle-PIMUL1P5)<0.000001 ) return TRUE; * * // Create the text. * MakeText(bs,from,to,m_StartAngle,text); * * return TRUE; * * } // end of CreateAngleText */ /// <summary> /// Breaks this leg into two legs. The break must leave at least /// one distance in each of the resultant legs. /// </summary> /// <param name="index">The index of the span that should be at the /// start of the extra leg.</param> /// <returns>The extra leg (at the end of the original leg).</returns> internal StraightLeg Break(int index) { if (this.AlternateFace != null) { throw new InvalidOperationException("Cannot break a staggered leg"); } // Can't break right at the start or end. int nTotal = PrimaryFace.Count; if (index <= 0 || index >= nTotal) { return(null); } // Create a new straight leg with the right number of spans. StraightLeg newLeg = new StraightLeg(PrimaryFace, index); // Retain the spans prior to that PrimaryFace.TruncateLeg(index); return(newLeg); }
/// <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); } } }