public CircularArcGeometry(ICircularArcGeometry g) { m_Circle = g.Circle; m_BC = g.BC; m_EC = g.EC; m_IsClockwise = g.IsClockwise; }
public CircularArcGeometry(ICircleGeometry circle, IPosition bc, IPosition ec, bool isClockwise) { m_Circle = circle; m_BC = PositionGeometry.Create(bc); m_EC = PositionGeometry.Create(ec); m_IsClockwise = isClockwise; }
public CircularArcGeometry(ICircleGeometry circle, IPointGeometry bc, IPointGeometry ec, bool isClockwise) { m_Circle = circle; m_BC = bc; m_EC = ec; m_IsClockwise = isClockwise; }
/// <summary> /// Gets the exact positions for the BC or EC. The "exact" positions are obtained /// by projecting the stored BC/EC to a position that is exactly consistent with the /// definition of the underlying circle. Typically, the shifts will be less than 1 /// micron on the ground. /// </summary> /// <param name="pos">The position to project (either the BC or EC)</param> /// <returns>The position on the circle</returns> IPosition GetCirclePosition(IPosition pos) { // Get the deltas of the position with respect to the centre of the circle. ICircleGeometry c = Circle; double cx = c.Center.X; double cy = c.Center.Y; double dx = pos.X - cx; double dy = pos.Y - cy; double dist = Math.Sqrt(dx * dx + dy * dy); // Return the centre if the position is coincident with the centre. if (dist < Constants.TINY) { return(c.Center); } // Get the factor for projecting the position. double factor = c.Radius / dist; // Figure out the position on the circle. double x = cx + dx * factor; double y = cy + dy * factor; return(new Position(x, y)); }
public static IWindow GetExtent(ICircleGeometry g) { double xc = g.Center.X; double yc = g.Center.Y; double r = g.Radius; return(new Window(xc - r, yc - r, xc + r, yc + r)); }
/// <summary> /// Draws a circular arc /// </summary> /// <param name="display">The display to draw to</param> /// <param name="arc">The circular arc</param> public void Render(ISpatialDisplay display, IClockwiseCircularArcGeometry arc) { ICircleGeometry circle = arc.Circle; IWindow extent = CircleGeometry.GetExtent(circle); float topLeftX = display.EastingToDisplay(extent.Min.X); float topLeftY = display.NorthingToDisplay(extent.Max.Y); float size = 2.0f * display.LengthToDisplay(circle.Radius); float startAngle = (float)(arc.StartBearingInRadians * MathConstants.RADTODEG - 90.0); float sweepAngle = (float)(arc.SweepAngleInRadians * MathConstants.RADTODEG); display.Graphics.DrawArc(m_Pen, topLeftX, topLeftY, size, size, startAngle, sweepAngle); }
// 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) public static ILength GetLength(ICircularArcGeometry g, IPosition asFarAs) { ICircleGeometry circle = g.Circle; double radius = circle.Radius; if (asFarAs == null) { // If the BC coincides with the EC, it's possible the arc has zero // length. As a matter of convention, counter-clockwise arcs will // be regarded as having a length of zero in that case. Meanwhile, // clockwise arcs will have a length that corresponds to the complete // circumference of the circle. if (g.BC.IsCoincident(g.EC)) { if (g.IsClockwise) { return(CircleGeometry.GetLength(circle)); } else { return(Backsight.Length.Zero); } } return(new Length(radius * g.SweepAngleInRadians)); } // Express the position of the BC in a local coordinate system. IPosition c = circle.Center; QuadVertex bc = new QuadVertex(c, g.BC, radius); // Calculate the clockwise angle to the desired point. QuadVertex to = new QuadVertex(c, asFarAs, radius); double ang = to.BearingInRadians - bc.BearingInRadians; if (ang < 0.0) { ang += MathConstants.PIMUL2; } // If the curve is actually anti-clockwise, take the complement. if (!g.IsClockwise) { ang = MathConstants.PIMUL2 - ang; } return(new Length(radius * ang)); }
/// <summary> /// Calculates the position on a circle that is closest to the specified position /// (i.e. takes the supplied position and drop a perpendicular to the circle). /// </summary> /// <param name="g">The circle of interest</param> /// <param name="p">The position to process</param> /// <returns>The position on the circle closest to the supplied position. Null /// if the supplied position coincides with the center of the circle.</returns> public static IPosition GetClosestPosition(ICircleGeometry g, IPosition p) { // Get the deltas of the supplied position with respect to the circle center IPosition c = g.Center; double dx = p.X - c.X; double dy = p.Y - c.Y; double dist = Math.Sqrt(dx * dx + dy * dy); // No result if it's too close to the center. if (dist < MathConstants.TINY) { return(null); } // Get the factor for projecting the position. double factor = g.Radius / dist; // Figure out the position on the circle. return(new Position(c.X + dx * factor, c.Y + dy * factor)); }
/// <summary> /// Do a pair of circles coincide? /// </summary> /// <param name="a">The first circle</param> /// <param name="b">The second circle</param> /// <param name="radiusTol">The tolerance for a radius match, in meters on the ground</param> /// <returns>True if the two circles have the same center point, and the same radius (within /// the specified tolerance)</returns> public static bool IsCoincident(ICircleGeometry a, ICircleGeometry b, double radiusTol) { return(a.Center.IsCoincident(b.Center) && Math.Abs(a.Radius - b.Radius) < radiusTol); }
/// <summary> /// Intersects this direction with a circle. This may lead to 0, 1, or 2 intersections. /// If 2 intersections are found, the first intersection is defined as the one that is /// closer to the origin of the direction object. /// </summary> /// <param name="circle">The circle to intersect with.</param> /// <param name="x1">The 1st intersection (if any). Returned as null if no intersection.</param> /// <param name="x2">The 2nd intersection (if any). Returned as null if no intersection.</param> /// <returns>The number of intersections found.</returns> internal uint Intersect(ICircleGeometry circle, out IPosition x1, out IPosition x2) { // Initialize both intersections. x1 = x2 = null; // Get the origin of the direction & its bearing. IPosition start = this.StartPosition; double bearing = this.Bearing.Radians; // Get the centre of the circle & its radius. IPosition center = circle.Center; double radius = circle.Radius; // The equation of each line is given in parametric form as: // // x = xo + f * r // y = yo + g * r // // where xo,yo is the from point // and f = sin(bearing) // and g = cos(bearing) // and r is the position ratio double g = Math.Cos(bearing); double f = Math.Sin(bearing); double fsq = f * f; double gsq = g * g; double fgsq = fsq + gsq; if (fgsq < Double.Epsilon) // Should be impossible { return(0); } double startx = start.X; double starty = start.Y; double dx = center.X - startx; double dy = center.Y - starty; double fygx = f * dy - g * dx; double root = radius * radius * fgsq - fygx * fygx; // Check for no intersection. if (root < -Constants.TINY) { return(0); } // Check for tangential intersection (but don't count a // tangent if it precedes the start of the direction line). double fxgy = f * dx + g * dy; double prat; if (root < Constants.TINY) { prat = fxgy / fgsq; if (prat < 0.0) { return(0); } x1 = new Position(startx + f * prat, starty + g * prat); return(1); } // We have two intersections, but one or both of them could // precede the start of the direction line. root = Math.Sqrt(root); double fginv = 1.0 / fgsq; double prat1 = (fxgy - root) * fginv; double prat2 = (fxgy + root) * fginv; // No intersections if both are prior to start of direction. if (prat1 < 0.0 && prat2 < 0.0) { return(0); } // If both intersections are valid ... prat = Math.Min(prat1, prat2); if (prat >= 0.0) { x1 = new Position(startx + f * prat, starty + g * prat); prat = Math.Max(prat1, prat2); x2 = new Position(startx + f * prat, starty + g * prat); return(2); } // So only one is valid ... prat = Math.Max(prat1, prat2); x1 = new Position(startx + f * prat, starty + g * prat); return(1); }
/// <summary> /// Intersects 2 clockwise arcs that coincide with the perimeter of a circle. /// </summary> /// <param name="xsect">Intersection results.</param> /// <param name="circle">The circle the arcs coincide with</param> /// <param name="bc1">BC for 1st arc.</param> /// <param name="ec1">EC for 1st arc.</param> /// <param name="bc2">BC for 2nd arc.</param> /// <param name="ec2">EC for 2nd arc.</param> /// <returns>The number of intersections (0, 1, or 2). If non-zero, the intersections /// will be grazes.</returns> static uint ArcIntersect( IntersectionResult xsect , ICircleGeometry circle , IPointGeometry bc1 , IPointGeometry ec1 , IPointGeometry bc2 , IPointGeometry ec2) { // Define the start of the clockwise arc as a reference line, // and get the clockwise angle to it's EC. Turn reft = new Turn(circle.Center, bc1); double sector = reft.GetAngleInRadians(ec1); // Where do the BC and EC of the 2nd curve fall with respect // to the 1st curve's arc sector? double bcang = reft.GetAngleInRadians(bc2); double ecang = reft.GetAngleInRadians(ec2); if (bcang<sector) { if (ecang<bcang) { xsect.Append(bc2, ec1); xsect.Append(bc1, ec2); return 2; } if (ecang<sector) xsect.Append(bc2, ec2); else xsect.Append(bc2, ec1); return 1; } // The BC of the 2nd curve falls beyond the sector of the 1st ... // so we can't have any graze if the EC is even further on. if (ecang>bcang) return 0; // One graze ... if (ecang<sector) xsect.Append(bc1, ec2); else xsect.Append(bc1, ec1); return 1; }
internal static uint Intersect(IntersectionResult results, ICircleGeometry a, ICircleGeometry b) { IPointGeometry centre1 = a.Center; IPointGeometry centre2 = b.Center; double radius1 = a.Radius; double radius2 = b.Radius; // The following looks pretty similar to Geom.IntersectCircles (some tolerance values are // a bit more relaxed here). // Pull out the XY's for the 2 centres. double xc1 = centre1.X; double yc1 = centre1.Y; double xc2 = centre2.X; double yc2 = centre2.Y; // Get distance (squared) between the 2 centres. double dx = xc2 - xc1; double dy = yc2 - yc1; double distsq = dx*dx + dy*dy; // If the two circles have the same centre, check whether // the radii match (if so, we have an overlap case). if (distsq < Constants.TINY) { if (Math.Abs(radius1-radius2) < Constants.XYRES) { double xi = xc1; double yi = yc1 + radius1; results.Append(xi, yi, xi, yi); return 1; } else return 0; } // We'll need the radii squared double rsq1 = radius1 * radius1; double rsq2 = radius2 * radius2; // Now some mathematical magic I got out a book. double delrsq = rsq2 - rsq1; double sumrsq = rsq1 + rsq2; double root = 2.0*sumrsq*distsq - distsq*distsq - delrsq*delrsq; // Check for no intersection. if (root < Constants.TINY) return 0; // We have at least one intersection. double dstinv = 0.5 / distsq; double scl = 0.5 - delrsq*dstinv; double x = dx*scl + xc1; double y = dy*scl + yc1; // Is it tangential? if (root < Constants.TINY) { results.Append(x, y, 0.0); return 1; } // Figure out 2 intersections. root = dstinv * Math.Sqrt(root); double xfac = dx*root; double yfac = dy*root; results.Append(x-yfac, y+xfac, 0.0); results.Append(x+yfac, y-xfac, 0.0); return 2; }
/// <summary> /// Intersect two circles. If there are two intersections, /// they are arranged so that the one with the lowest bearing comes first. /// </summary> /// <param name="a">The 1st circle</param> /// <param name="b">The 2nd circle</param> /// <param name="x1">The 1st intersection (if any).</param> /// <param name="x2">The 2nd intersection (if any).</param> /// <returns>The number of intersections found.</returns> internal static uint Intersect(ICircleGeometry a, ICircleGeometry b, out IPosition x1, out IPosition x2) { // Get the intersections (if any). uint nx = Geom.IntersectCircles(a.Center, a.Radius, b.Center, b.Radius, out x1, out x2); // Return if 0 or 1 intersection. if (nx<2) return nx; // Arrange the intersections so that the one with the lowest bearing comes first. QuadVertex q1x1 = new QuadVertex(a.Center, x1); QuadVertex q1x2 = new QuadVertex(a.Center, x2); QuadVertex q2x1 = new QuadVertex(b.Center, x1); QuadVertex q2x2 = new QuadVertex(b.Center, x2); double b1x1 = q1x1.BearingInRadians; double b1x2 = q1x2.BearingInRadians; double b2x1 = q2x1.BearingInRadians; double b2x2 = q2x2.BearingInRadians; // Switch if the min bearing to the 2nd intersection is actually // less than the min bearing to the 1st intersection. if (Math.Min(b1x2, b2x2) < Math.Min(b1x1, b2x1)) { IPosition temp = x1; x1 = x2; x2 = temp; } return 2; }
internal static uint Intersect(IntersectionResult result, ILineSegmentGeometry seg, ICircleGeometry circle) { return Intersect(result, seg.Start, seg.End, circle.Center, circle.Radius); }
internal override uint IntersectCircle(IntersectionResult results, ICircleGeometry circle) { return(Make().IntersectCircle(results, circle)); }
/// <summary> /// Calculates the position on a circle that is closest to the specified position /// (i.e. takes the supplied position and drop a perpendicular to the circle). /// </summary> /// <param name="g">The circle of interest</param> /// <param name="p">The position to process</param> /// <returns>The position on the circle closest to the supplied position. Null /// if the supplied position coincides with the center of the circle.</returns> public static IPosition GetClosestPosition(ICircleGeometry g, IPosition p) { // Get the deltas of the supplied position with respect to the circle center IPosition c = g.Center; double dx = p.X - c.X; double dy = p.Y - c.Y; double dist = Math.Sqrt(dx*dx + dy*dy); // No result if it's too close to the center. if (dist<MathConstants.TINY) return null; // Get the factor for projecting the position. double factor = g.Radius/dist; // Figure out the position on the circle. return new Position(c.X + dx*factor, c.Y + dy*factor); }
public static ILength Distance(ICircleGeometry g, IPosition p) { double d = BasicGeom.Distance(g.Center, p); return new Length(Math.Abs(d - g.Radius)); }
abstract internal uint IntersectCircle(IntersectionResult results, ICircleGeometry circle);
/// <summary> /// Intersects this direction with a circle. This may lead to 0, 1, or 2 intersections. /// If 2 intersections are found, the first intersection is defined as the one that is /// closer to the origin of the direction object. /// </summary> /// <param name="circle">The circle to intersect with.</param> /// <param name="x1">The 1st intersection (if any). Returned as null if no intersection.</param> /// <param name="x2">The 2nd intersection (if any). Returned as null if no intersection.</param> /// <returns>The number of intersections found.</returns> internal uint Intersect(ICircleGeometry circle, out IPosition x1, out IPosition x2) { // Initialize both intersections. x1 = x2 = null; // Get the origin of the direction & its bearing. IPosition start = this.StartPosition; double bearing = this.Bearing.Radians; // Get the centre of the circle & its radius. IPosition center = circle.Center; double radius = circle.Radius; // The equation of each line is given in parametric form as: // // x = xo + f * r // y = yo + g * r // // where xo,yo is the from point // and f = sin(bearing) // and g = cos(bearing) // and r is the position ratio double g = Math.Cos(bearing); double f = Math.Sin(bearing); double fsq = f*f; double gsq = g*g; double fgsq = fsq + gsq; if (fgsq<Double.Epsilon) // Should be impossible return 0; double startx = start.X; double starty = start.Y; double dx = center.X - startx; double dy = center.Y - starty; double fygx = f*dy - g*dx; double root = radius*radius*fgsq - fygx*fygx; // Check for no intersection. if (root < -Constants.TINY ) return 0; // Check for tangential intersection (but don't count a // tangent if it precedes the start of the direction line). double fxgy = f*dx + g*dy; double prat; if (root < Constants.TINY) { prat = fxgy/fgsq; if (prat<0.0) return 0; x1 = new Position(startx + f*prat, starty + g*prat); return 1; } // We have two intersections, but one or both of them could // precede the start of the direction line. root = Math.Sqrt(root); double fginv = 1.0/fgsq; double prat1 = (fxgy - root)*fginv; double prat2 = (fxgy + root)*fginv; // No intersections if both are prior to start of direction. if (prat1<0.0 && prat2<0.0) return 0; // If both intersections are valid ... prat = Math.Min(prat1,prat2); if (prat>=0.0) { x1 = new Position(startx + f*prat, starty + g*prat); prat = Math.Max(prat1,prat2); x2 = new Position(startx + f*prat, starty + g*prat); return 2; } // So only one is valid ... prat = Math.Max(prat1,prat2); x1 = new Position(startx + f*prat, starty + g*prat); return 1; }
public static void Render(ICircleGeometry g, ISpatialDisplay display, IDrawStyle style) { style.Render(display, g.Center, g.Radius); }
public static IWindow GetExtent(ICircleGeometry g) { double xc = g.Center.X; double yc = g.Center.Y; double r = g.Radius; return new Window(xc-r, yc-r, xc+r, yc+r); }
/// <summary> /// Intersects a circle with a clockwise arc /// </summary> /// <param name="results"></param> /// <param name="c"></param> /// <param name="start"></param> /// <param name="end"></param> /// <param name="arcCircle"></param> /// <returns></returns> static uint Intersect(IntersectionResult xsect, ICircleGeometry c, IPointGeometry start, IPointGeometry end, ICircleGeometry arcCircle) { // If the circles are IDENTICAL, we've got a graze. if (CircleGeometry.IsCoincident(c, arcCircle, Constants.XYRES)) { xsect.Append(start, end); return 1; } // Intersect the 2 circles. IPosition x1, x2; uint nx = Intersect(c, arcCircle, out x1, out x2); // Return if no intersection. if (nx==0) return 0; // Remember the intersection(s) if they fall in the // curve's sector. Use a tolerance which is based on // the circle with the smaller radius (=> bigger angular // tolerance). IPointGeometry centre; double minrad; if (c.Radius < arcCircle.Radius) { minrad = c.Radius; centre = c.Center; } else { minrad = arcCircle.Radius; centre = arcCircle.Center; } // const FLOAT8 angtol = XYTOL/minrad; // const FLOAT8 angtol = 0.00002/minrad; // 20 microns double angtol = 0.002/minrad; // 2mm if (nx==1) { IPointGeometry loc = PointGeometry.Create(x1); if (Geom.IsInSector(loc, centre, start, end, angtol)) { xsect.Append(loc); return 1; } return 0; } else { // Two intersections. They are valid if they fall within the curve's sector. IPointGeometry loc1 = PointGeometry.Create(x1); IPointGeometry loc2 = PointGeometry.Create(x2); uint nok=0; if (Geom.IsInSector(loc1, centre, start, end, angtol)) { xsect.Append(loc1); nok++; } if (Geom.IsInSector(loc2, centre, start, end, angtol)) { xsect.Append(loc2); nok++; } return nok; } }
/// <summary> /// Calculates the perimeter length of a circle. /// </summary> /// <param name="g">The circle of interest</param> /// <returns>The perimeter length of the circle.</returns> public static ILength GetLength(ICircleGeometry g) { return new Length(g.Radius * MathConstants.PIMUL2); }
internal static uint Intersect(IntersectionResult results, IMultiSegmentGeometry line, ICircleGeometry circle) { uint nx=0; IPointGeometry[] segs = line.Data; IPointGeometry c = circle.Center; double r = circle.Radius; for (int i=1; i<segs.Length; i++) nx += Intersect(results, segs[i-1], segs[i], c, r); return nx; }
/// <summary> /// Do a pair of circles coincide? /// </summary> /// <param name="a">The first circle</param> /// <param name="b">The second circle</param> /// <param name="radiusTol">The tolerance for a radius match, in meters on the ground</param> /// <returns>True if the two circles have the same center point, and the same radius (within /// the specified tolerance)</returns> public static bool IsCoincident(ICircleGeometry a, ICircleGeometry b, double radiusTol) { return (a.Center.IsCoincident(b.Center) && Math.Abs(a.Radius - b.Radius)<radiusTol); }
internal static uint Intersect(IntersectionResult results, ICircularArcGeometry a, ICircleGeometry b) { if (CircularArcGeometry.IsCircle(a)) return Intersect(results, a.Circle, b); else return Intersect(results, b, a.First, a.Second, a.Circle); }
/// <summary> /// Intersects a pair of clockwise arcs that sit on the same circle, and where ONE of /// the end points exactly matches. /// </summary> /// <param name="xsect">The intersection results.</param> /// <param name="circle">The circle the arcs coincide with</param> /// <param name="bc1">The BC of the 1st arc</param> /// <param name="ec1">The EC of the 1st arc</param> /// <param name="bc2">The BC of the 2nd arc -- the matching end</param> /// <param name="ec2">The EC of the 2nd arc</param> /// <param name="isStartMatch">Specify <c>true</c> if <paramref name="bc2"/> matches an end /// point of the 1st arc. Specify <c>false</c> if <paramref name="ec2"/> matches an end /// point of the 1st arc.</param> /// <returns>The number of intersections (always 1).</returns> static uint ArcEndIntersect( IntersectionResult xsect , ICircleGeometry circle , IPointGeometry bc1 , IPointGeometry ec1 , IPointGeometry bc2 , IPointGeometry ec2 , bool isStartMatch) { bool bmatch = bc1.IsCoincident(bc2); bool ematch = ec1.IsCoincident(ec2); // If the two curves share the same BC or same EC if (bmatch || ematch) { // We've got some sort of graze ... // Check for total graze. if (bmatch && ematch) xsect.Append(bc1, ec1); else { // We've therefore got a partial graze. // If the length of this arc is longer than the other one, the graze is over the // length of the other one, and vice versa. Since the two curves share the same // radius and direction, the comparison just involves a comparison of the clockwise // angles subtended by the arcs. IPointGeometry centre = circle.Center; double ang1 = new Turn(centre, bc1).GetAngleInRadians(ec1); double ang2 = new Turn(centre, bc2).GetAngleInRadians(ec2); bool isThisGraze = (ang1 < ang2); if (isThisGraze) xsect.Append(bc1, ec1); else xsect.Append(bc2, ec2); } } else { // The only intersection is at the common end. if (bc1.IsCoincident(bc2) || ec1.IsCoincident(bc2)) xsect.Append(bc2); else xsect.Append(ec2); } return 1; }
public CircleGeometry(ICircleGeometry g) { m_Center = g.Center; m_Radius = g.Radius; }
/// <summary> /// Intersects a line segment with a clockwise arc, where at least one end of the /// segment exactly coincides with one end of the arc. /// </summary> /// <param name="xsect">The intersection results.</param> /// <param name="bc">The start of the clockwise arc.</param> /// <param name="ec">The end of the clockwise arc.</param> /// <param name="circle">The circle on which the arc lies.</param> /// <param name="xend">The end of the segment that coincides with one end of the arc.</param> /// <param name="othend">The other end of the segment (may or may not coincide /// with one end of the arc).</param> /// <returns>The number of intersections (either 1 or 2).</returns> static uint EndIntersect( IntersectionResult xsect , IPointGeometry bc , IPointGeometry ec , ICircleGeometry circle , IPointGeometry xend , IPointGeometry othend) { // If the other end is INSIDE the circle, the matching end // location is the one and only intersection. Allow a tolerance // that is consistent with the resolution of data (3 microns). IPointGeometry centre = circle.Center; double radius = circle.Radius; double minrad = (radius-Constants.XYTOL); double minrsq = (minrad*minrad); double othdsq = Geom.DistanceSquared(othend, centre); if (othdsq < minrsq) { xsect.Append(xend); return 1; } // If the other end of the segment also coincides with either // end of the curve, the segment is a chord of the circle that // the curve lies on. However, if it's REAL close, we need to // return it as a graze ... if (othend.IsCoincident(bc) || othend.IsCoincident(ec)) { // Get the midpoint of the chord. IPosition midseg = Position.CreateMidpoint(xend, othend); // If the distance from the centre of the circle to the // midpoint is REAL close to the curve, we've got a graze. if (Geom.DistanceSquared(midseg, centre) > minrsq) { xsect.Append(xend, othend); return 1; } // Two distinct intersections. xsect.Append(xend); xsect.Append(othend); return 2; } // If the other end is within tolerance of the circle, project // it to the circle and see if it's within the curve's sector. // If not, it's not really an intersect. double maxrad = (radius+Constants.XYTOL); double maxrsq = (maxrad*maxrad); if ( othdsq < maxrsq ) { // Check if the angle to the other end is prior to the EC. // If not, it's somewhere off the curve. Turn reft = new Turn(centre, bc); if (reft.GetAngleInRadians(othend) > reft.GetAngleInRadians(ec)) { xsect.Append(xend); return 1; } // And, like above, see if the segment grazes or not ... // Get the midpoint of the chord. IPosition midseg = Position.CreateMidpoint(xend, othend); // If the distance from the centre of the circle to the // midpoint is REAL close to the curve, we've got a graze. if (Geom.DistanceSquared(midseg, centre) > minrsq) { xsect.Append(xend, othend); return 1; } // Two distinct intersections. xsect.Append(xend); xsect.Append(othend); return 2; } // That leaves us with the other end lying somewhere clearly // outside the circle. However, we could still have a graze. // Make sure the BC/EC are EXACTLY coincident with the circle (they // may have been rounded off if the curve has been intersected // with a location that's within tolerance of the circle). IPosition trueBC, trueEC; Position.GetCirclePosition(bc, centre, radius, out trueBC); Position.GetCirclePosition(ec, centre, radius, out trueEC); // As well as the end of the segment that meets the curve. IPosition trueXend = (xend.IsCoincident(bc) ? trueBC : trueEC); // Intersect the segment with the complete circle (this does // NOT return an intersection at the other end, even if it is // really close ... we took care of that above). // The intersection must lie ON the segment (not sure about this though). IPosition othvtx = othend; IPosition x1, x2; bool isTangent; uint nx = Geom.IntersectCircle(centre, radius, trueXend, othvtx, out x1, out x2, out isTangent, true); // If we got NOTHING, that's unexpected, since one end exactly coincides // with the circle. In that case, just return the matching end (NOT // projected to the true position). if (nx==0) { xsect.Append(xend); return 1; } // If we got 2 intersections, pick the one that's further away than the matching end. if (nx==2 && Geom.DistanceSquared(x2, trueXend) > Geom.DistanceSquared(x1, trueXend)) x1 = x2; // That leaves us with ONE intersection with the circle ... now // confirm that it actually intersects the arc! Turn refbc = new Turn(centre, trueBC); double eangle = refbc.GetAngleInRadians(trueEC); double xangle = refbc.GetAngleInRadians(x1); if (xangle > eangle) { xsect.Append(xend); return 1; } // Get the midpoint of the segment that connects the intersection to the true end. IPosition midx = Position.CreateMidpoint(trueXend, x1); // If the midpoint does NOT graze the circle, we've got 2 distinct intersections. // 25-NOV-99: Be realistic about it (avoid meaningless sliver polygons that are // less than 0.1mm wide on the ground). // if ( midx.DistanceSquared(centre) < minrsq ) { double rdiff = Geom.Distance(midx, centre) - radius; if (Math.Abs(rdiff) > 0.0001) { xsect.Append(xend); xsect.Append(x1); return 2; } // We've got a graze, but possibly one that can be ignored(!). To // understand the reasoning here, bear in mind that lines get cut // only so that network topology can be formed. To do that, 2 // orientation points are obtained for the lines incident on xend. // For the segment, the orientation point is the other end of the // segment. For the curve, it's a position 5 metres along the // curve (or the total curve length if it's not that long). So // if the graze is closer than the point that will be used to // get the orientation point, we can ignore the graze, since it // does not provide any useful info. // Given that it's a graze, assume that it's ok to work out // the arc distance as if it was straight. double dsqx = Geom.DistanceSquared(trueXend, x1); // If it's closer than 4m (allow some leeway, seeing how we've // just done an approximation), ignore the intersection. If it's // actually between 4 and 5 metres, it shouldn't do any harm // to make a split there (although it's kind of redundant). if (dsqx < 16.0) { xsect.Append(xend); return 1; } // It's a graze. //CeVertex vxend(xend); // wants a vertex xsect.Append(xend, x1); return 1; }
internal override uint IntersectCircle(IntersectionResult results, ICircleGeometry that) { return IntersectionHelper.Intersect(results, (ILineSegmentGeometry)this, that); }
public static ILength Distance(ICircleGeometry g, IPosition p) { double d = BasicGeom.Distance(g.Center, p); return(new Length(Math.Abs(d - g.Radius))); }
internal override uint IntersectCircle(IntersectionResult results, ICircleGeometry that) { return(IntersectionHelper.Intersect(results, (ICircularArcGeometry)this, that)); }
/// <summary> /// Calculates the perimeter length of a circle. /// </summary> /// <param name="g">The circle of interest</param> /// <returns>The perimeter length of the circle.</returns> public static ILength GetLength(ICircleGeometry g) { return(new Length(g.Radius * MathConstants.PIMUL2)); }
internal override uint IntersectCircle(IntersectionResult results, ICircleGeometry circle) { return Make().IntersectCircle(results, circle); }
/// <summary> /// Intersects a line segment with the data describing a clockwise curve. /// </summary> /// <param name="result">The intersection results.</param> /// <param name="a">The start of the line segment</param> /// <param name="b">The end of the line segment</param> /// <param name="start">The start of the clockwise arc.</param> /// <param name="end">The end of the clockwise arc.</param> /// <param name="circle">The circle on which the arc lies.</param> /// <returns></returns> static uint Intersect( IntersectionResult result , IPointGeometry a , IPointGeometry b , IPointGeometry start , IPointGeometry end , ICircleGeometry circle) { // If the segment exactly meets either end of the curve, it gets handled seperately. if (a.IsCoincident(start) || a.IsCoincident(end)) return EndIntersect(result, start, end, circle, a, b); if (b.IsCoincident(start) || b.IsCoincident(end)) return EndIntersect(result, start, end, circle, b, a); // Get circle definition. IPointGeometry centre = circle.Center; double radius = circle.Radius; // Get up to 2 intersections with the circle. IPosition x1, x2; bool isGraze; uint nx = GetXCircle(a, b, centre, radius, out x1, out x2, out isGraze); // Return if no intersections with the circle. if (nx==0) return 0; // If an intersection is really close to the end of an arc, force it to be there. if (Geom.DistanceSquared(start, x1) < Constants.XYTOLSQ) x1 = start; else if (Geom.DistanceSquared(end, x1) < Constants.XYTOLSQ) x1 = end; if (nx==2) { if (Geom.DistanceSquared(start, x2) < Constants.XYTOLSQ) x2 = start; else if (Geom.DistanceSquared(end, x2) < Constants.XYTOLSQ) x2 = end; } // Determine whether the intersections fall within the sector // that's defined by the clockwise curve (grazes need a bit // more handling, so do that after we see how to do the non- // grazing case. if ( !isGraze ) { PointGeometry xloc1 = PointGeometry.Create(x1); double lintol = Constants.XYTOL / radius; // If we only got one intersect, and it's out of sector, that's us done. if (nx==1) { if (!BasicGeom.IsInSector(xloc1, centre, start, end, lintol)) return 0; result.Append(x1); return 1; } // Two intersections with the circle ... if (BasicGeom.IsInSector(xloc1, centre, start, end, lintol)) result.Append(x1); else nx--; PointGeometry xloc2 = PointGeometry.Create(x2); if (BasicGeom.IsInSector(xloc2, centre, start, end, lintol)) result.Append(x2); else nx--; return nx; } // That leaves us with the case where this segment grazes the // circle. GetXCircle is always supposed to return nx==2 in that // case (they're also supposed to be arranged in the same // direction as this segment). Debug.Assert(nx==2); // Get the clockwise angle subtended by the circular arc. Add // on a tiny bit to cover numerical comparison problems. Turn reft = new Turn(centre, start); double maxangle = reft.GetAngleInRadians(end) + Constants.TINY; // Get the clockwise angles to both intersections. double a1 = reft.GetAngleInRadians(x1); double a2 = reft.GetAngleInRadians(x2); // No graze if both are beyond the arc sector. if (a1>maxangle && a2>maxangle) return 0; // If both intersects are within sector, the only thing to watch // out for is a case where the graze apparently occupies more // than half a circle. In that case, we've actually got 2 grazes. if (a1<maxangle && a2<maxangle) { if (a2>a1 && (a2-a1)>Constants.PI) { result.Append(x1, start); result.Append(end, x2); return 2; } if (a1>a2 && (a1-a2)>Constants.PI) { result.Append(start, x2); result.Append(x1, end); return 2; } // So it's just a regular graze. result.Append(x1, x2); return 1; } // That's covered the cases where both intersects are either // both in sector, or both out. Return the intersection that's // in sector as a simple intersection (NOT a graze). // This is a cop-out. We should really try to figure out which // portion of the curve is grazing, but the logic for doing so // is surprisingly complex, being subject to a variety of special // cases. By returning the intersect as a simple intersect, I'm // hoping it covers most cases. if (a1 < maxangle) result.Append(x1); else result.Append(x2); return 1; }
internal abstract uint IntersectCircle(IntersectionResult results, ICircleGeometry circle);
/// <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); }