/// <summary> /// Generates an approximation of a circular arc. /// </summary> /// <param name="tol">The maximum chord-to-circumference distance.</param> /// <returns></returns> public static IPointGeometry[] GetApproximation(ICircularArcGeometry g, ILength tol) { // Get info about the circle the curve lies on. IPosition center = g.Circle.Center; double radius = g.Circle.Radius; // Determine the change in bearing which will satisfy the specified tolerance // (if no tolerance has been specified, arbitrarily use a tolerance of 1mm on the ground). double tolm = (tol.Meters > Double.Epsilon ? tol.Meters : 0.001); double dbear = Math.Acos((radius - tolm) / radius); IPointGeometry start = g.BC; IPointGeometry end = g.EC; bool iscw = g.IsClockwise; // Get the total angle subtended by the curve. Turn reft = new Turn(center, start); double totang = reft.GetAngleInRadians(end); // clockwise if (!iscw) { totang = MathConstants.PIMUL2 - totang; } // Figure out how many positions we'll generate int nv = (int)(totang / dbear); // truncate Debug.Assert(nv >= 0); // Handle special case of very short arc. if (nv == 0) { return new IPointGeometry[] { start, end } } ; // Sign the delta-bearing the right way. if (!iscw) { dbear = -dbear; } // Get the initial bearing to the first position along the curve. double curbear = reft.BearingInRadians + dbear; // Append positions along the length of the curve. List <IPointGeometry> result = new List <IPointGeometry>(nv); result.Add(start); for (int i = 0; i < nv; i++, curbear += dbear) { IPosition p = BasicGeom.Polar(center, curbear, radius); result.Add(PositionGeometry.Create(p)); } result.Add(end); return(result.ToArray()); }
/// <summary> /// Gets the position that is a specific distance from the start of a circular arc. /// </summary> /// <param name="g">The geometry for the circular arc</param> /// <param name="distance">The distance from the start of the arc.</param> /// <param name="result">The position found</param> /// <returns>True if the distance is somewhere ON the arc. False if the distance /// was less than zero, or more than the arc length (in that case, the position /// found corresponds to the corresponding terminal point).</returns> public static bool GetPosition(ICircularArcGeometry g, ILength distance, out IPosition result) { // Allow 1 micron tolerance const double TOL = 0.000001; // Check for invalid distances. double d = distance.Meters; if (d < 0.0) { result = g.BC; return(false); } double clen = g.Length.Meters; // Arc length if (d > (clen + TOL)) { result = g.EC; return(false); } // Check for limiting values (if you don't do this, minute // roundoff at the BC & EC can lead to spurious locations). // (although it's possible to use TINY here, use 1 micron // instead, since we can't represent position any better // than that). if (d < TOL) { result = g.BC; return(true); } if (Math.Abs(d - clen) < TOL) { result = g.EC; return(true); } // Get the bearing of the BC ICircleGeometry circle = g.Circle; IPosition c = circle.Center; double radius = circle.Radius; double bearing = BasicGeom.BearingInRadians(c, g.BC); // Add the angle that subtends the required distance (or // subtract if the curve goes anti-clockwise). if (g.IsClockwise) { bearing += (d / radius); } else { bearing -= (d / radius); } // Figure out the required point from the new bearing. result = BasicGeom.Polar(c, bearing, radius); return(true); }