/// <summary> /// Checks whether a location falls in the sector lying between the BC and EC /// of a circular arc. The only condition is that the location has an appropriate /// bearing with respect to the bearings of the BC & EC (i.e. the location does not /// necessarily lie ON the arc). /// </summary> /// <param name="pos">The position to check</param> /// <param name="lintol">Linear tolerance, in meters on the ground (locations that are /// beyond the BC or EC by up to this much will also be regarded as "in-sector").</param> /// <returns>True if position falls in the sector defined by this arc</returns> public static bool IsInSector(ICircularArcGeometry g, IPosition pos, double lintol) { // If the arc is a complete circle, it's ALWAYS in sector. if (IsCircle(g)) { return(true); } // Express the curve's start & end points in local system, // ordered clockwise. IPointGeometry start = g.First; IPointGeometry end = g.Second; // Get the centre of the circular arc. IPosition centre = g.Circle.Center; // If we have a linear tolerance, figure out the angular equivalent. if (lintol > MathConstants.TINY) { double angtol = lintol / g.Circle.Radius; return(BasicGeom.IsInSector(pos, centre, start, end, angtol)); } else { return(BasicGeom.IsInSector(pos, centre, start, end, 0.0)); } }
public CircularArcGeometry(ICircularArcGeometry g) { m_Circle = g.Circle; m_BC = g.BC; m_EC = g.EC; m_IsClockwise = g.IsClockwise; }
/// <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()); }
public static double GetSweepAngleInRadians(ICircularArcGeometry g) { IPosition f = g.First; IPosition s = g.Second; Turn t = new Turn(g.Circle.Center, f); return(t.GetAngleInRadians(s)); }
internal InverseArcDistanceForm() { InitializeComponent(); color1Button.BackColor = InverseColors[0]; color2Button.BackColor = InverseColors[1]; m_Point1 = m_Point2 = null; m_Cir1 = m_Cir2 = m_CommCir = null; m_WantShort = true; m_CurrentDistanceArc = null; }
// 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)); }
static double MinDistanceSquared(ICircularArcGeometry g, IPosition p) { // If the position lies in the arc sector, the minimum distance // is given by the distance to the circle. Otherwise the minimum // distance is the distance to the closest end of the arc. if (IsInSector(g, p, 0.0)) { double dist = BasicGeom.Distance(p, g.Circle.Center); double radius = g.Circle.Radius; return((dist - radius) * (dist - radius)); } else { double d1 = BasicGeom.DistanceSquared(p, g.BC); double d2 = BasicGeom.DistanceSquared(p, g.EC); return(Math.Min(d1, d2)); } }
internal virtual void ShowResult() { // If we have two points, get the distance between them, // format the result, and display it. if (m_Point1 != null && m_Point2 != null && m_CommCir != null) { // It's conceivable that the two points share more than // one common circle. For now, just pick off the first // common circle and use that. Circle circle = m_CommCir[0]; // Get the centre of the circle. IPosition c = circle.Center; // Get the clockwise angle from point 1 to point 2. Turn reft = new Turn(c, m_Point1); double angle = reft.GetAngleInRadians(m_Point2); bool iscw = true; // Make sure the angle is consistent with whether we want // the short or the long arc distance. bool isshort = (angle < Constants.PI); if (isshort != m_WantShort) { angle = Constants.PIMUL2 - angle; iscw = false; } // Get the arc distance and display it. double metric = angle * circle.Radius; distanceTextBox.Text = Format(metric, m_Point1, m_Point2); // Remember the geometry that corresponds to the displayed distance (this // will be drawn when the controller periodically calls the Draw method). m_CurrentDistanceArc = new CircularArcGeometry(circle, m_Point1, m_Point2, iscw); } else { distanceTextBox.Text = "<no distance>"; m_CurrentDistanceArc = null; } }
internal static uint Intersect(IntersectionResult result, ILineSegmentGeometry seg, ICircularArcGeometry arc) { if (CircularArcGeometry.IsCircle(arc)) return Intersect(result, seg, arc.Circle); else return Intersect(result, seg.Start, seg.End, arc.First, arc.Second, arc.Circle); }
/// <summary> /// Intersects a pair of circular arcs. /// </summary> /// <param name="results">Where to stick the results</param> /// <param name="a">The first arc</param> /// <param name="b">The second arc</param> /// <returns></returns> internal static uint Intersect(IntersectionResult results, ICircularArcGeometry ab, ICircularArcGeometry pq) { // Special handling if the two arcs share the same circle if (CircleGeometry.IsCoincident(ab.Circle, pq.Circle, Constants.XYRES)) return ArcIntersect(results, ab, pq); // Arcs that meet exactly end to end get handled seperately. IPointGeometry a = ab.First; IPointGeometry b = ab.Second; IPointGeometry p = pq.First; IPointGeometry q = pq.Second; if (a.IsCoincident(p) || a.IsCoincident(q)) return EndIntersect(results, ab, pq, true); if (b.IsCoincident(p) || b.IsCoincident(q)) return EndIntersect(results, ab, pq, false); // Intersect the circle for the two arcs IPosition x1, x2; uint nx = Intersect(ab.Circle, pq.Circle, out x1, out x2); // Return if the circles don't intersect. if (nx==0) return 0; // Remember the intersection(s) if they fall in BOTH curve sectors. IPointGeometry thiscen = ab.Circle.Center; IPointGeometry othrcen = pq.Circle.Center; if (nx==1) { // If we got 1 intersection, it may be VERY close to the end // points. Make sure we also consider the precise check made up top. // Otherwise check if the intersection is in both sectors. IPointGeometry loc = PointGeometry.Create(x1); // rounded to nearest micron if (Geom.IsInSector(loc, thiscen, a, b, 0.0) && Geom.IsInSector(loc, othrcen, p, q, 0.0)) { results.Append(loc); return 1; } return 0; } else { // Two intersections. They are valid if they fall within the arc's sector. // Again, make sure we consider any precise end-point check made above. uint nok=0; IPointGeometry loc1 = PointGeometry.Create(x1); IPointGeometry loc2 = PointGeometry.Create(x2); if (Geom.IsInSector(loc1, thiscen, a, b, 0.0) && Geom.IsInSector(loc1, othrcen, p, q, 0.0)) { results.Append(loc1); nok++; } if (Geom.IsInSector(loc2, thiscen, a, b, 0.0) && Geom.IsInSector(loc2, othrcen, p, q, 0.0)) { results.Append(loc2); nok++; } return nok; } }
internal uint IntersectArc(ICircularArcGeometry arc) { return m_IntersectedObject.LineGeometry.IntersectArc(this, arc); }
internal override uint IntersectArc(IntersectionResult results, ICircularArcGeometry that) { return(IntersectionHelper.Intersect(results, that, (ICircularArcGeometry)this)); }
public static IWindow GetExtent(ICircularArcGeometry g) { // If the curve is a complete circle, just define it the easy way. if (g.BC.IsCoincident(g.EC)) { return(CircleGeometry.GetExtent(g.Circle)); } IPosition bcp = g.BC; IPosition ecp = g.EC; IPosition centre = g.Circle.Center; // Initialize the window with the start location. Window win = new Window(bcp); // Expand using the end location win.Union(ecp); // If the curve is completely within one quadrant, we're done. QuadVertex bc = new QuadVertex(centre, bcp); QuadVertex ec = new QuadVertex(centre, ecp); Quadrant qbc = bc.Quadrant; Quadrant qec = ec.Quadrant; if (qbc == qec) { if (g.IsClockwise) { if (bc.GetTanAngle() < ec.GetTanAngle()) { return(win); } } else { if (ec.GetTanAngle() < bc.GetTanAngle()) { return(win); } } } // Get the window of the circle IWindow circle = CircleGeometry.GetExtent(g.Circle); // If the curve is anticlockwise, switch the quadrants for BC & EC if (!g.IsClockwise) { Quadrant temp = qbc; qbc = qec; qec = temp; } // Expand the window, depending on which quadrants the start & // end points fall in. The lack of breaks in the inner switches // is intentional (e.g. if start & end both fall in Quadrant.NorthEast, // the window we want is the complete circle, having checked above // for the case where the arc is JUST in Quadrant.NorthEast). // Define do-nothing values for the Union's below double wx = win.Min.X; double wy = win.Min.Y; if (qbc == Quadrant.NE) { switch (qec) { case Quadrant.NE: win.Union(wx, circle.Max.Y); goto case Quadrant.NW; case Quadrant.NW: win.Union(circle.Min.X, wy); goto case Quadrant.SW; case Quadrant.SW: win.Union(wx, circle.Min.Y); goto case Quadrant.SE; case Quadrant.SE: win.Union(circle.Max.X, wy); break; } } else if (qbc == Quadrant.SE) { switch (qec) { case Quadrant.SE: win.Union(circle.Max.X, wy); goto case Quadrant.NE; case Quadrant.NE: win.Union(wx, circle.Max.Y); goto case Quadrant.NW; case Quadrant.NW: win.Union(circle.Min.X, wy); goto case Quadrant.SW; case Quadrant.SW: win.Union(wx, circle.Min.Y); break; } } else if (qbc == Quadrant.SW) { switch (qec) { case Quadrant.SW: win.Union(wx, circle.Min.Y); goto case Quadrant.SE; case Quadrant.SE: win.Union(circle.Max.X, wy); goto case Quadrant.NE; case Quadrant.NE: win.Union(wx, circle.Max.Y); goto case Quadrant.NW; case Quadrant.NW: win.Union(circle.Min.X, wy); break; } } else if (qbc == Quadrant.NW) { switch (qec) { case Quadrant.NW: win.Union(circle.Min.X, wy); goto case Quadrant.SW; case Quadrant.SW: win.Union(wx, circle.Min.Y); goto case Quadrant.SE; case Quadrant.SE: win.Union(circle.Max.X, wy); goto case Quadrant.NE; case Quadrant.NE: win.Union(wx, circle.Max.Y); break; } } return(win); }
abstract internal uint IntersectArc(IntersectionResult results, ICircularArcGeometry arc);
// 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> /// The second position of an arc, when reckoned clockwise. /// </summary> public static IPointGeometry GetSecondPosition(ICircularArcGeometry g) { return (g.IsClockwise ? g.EC : g.BC); }
static uint ArcIntersect(IntersectionResult results, ICircularArcGeometry ab, ICircularArcGeometry pq) { // Arcs that meet exactly end to end get handled seperately. IPointGeometry a = ab.First; IPointGeometry b = ab.Second; IPointGeometry p = pq.First; IPointGeometry q = pq.Second; if (a.IsCoincident(p) || a.IsCoincident(q)) //return ArcEndIntersect(results, pq.Circle, p, q, a, b); return ArcEndIntersect(results, pq.Circle, p, q, a, b, true); if (b.IsCoincident(p) || b.IsCoincident(q)) //return ArcEndIntersect(results, pq.Circle, p, q, b, a); return ArcEndIntersect(results, pq.Circle, p, q, a, b, false); return ArcIntersect(results, pq.Circle, p, q, a, b); }
/// <summary> /// The second position of an arc, when reckoned clockwise. /// </summary> public static IPointGeometry GetSecondPosition(ICircularArcGeometry g) { return(g.IsClockwise ? g.EC : g.BC); }
public static ILength GetDistance(ICircularArcGeometry g, IPosition p) { return(new Length(Math.Sqrt(MinDistanceSquared(g, p)))); }
public static double GetStartBearingInRadians(ICircularArcGeometry g) { return(BasicGeom.BearingInRadians(g.Circle.Center, g.First)); }
/// <summary> /// Does a circular arc represent a complete circle (with a /// BC that's coincident with the EC). /// </summary> public static bool IsCircle(ICircularArcGeometry g) { return(g.BC.IsCoincident(g.EC)); }
public static double GetSweepAngleInRadians(ICircularArcGeometry g) { IPosition f = g.First; IPosition s = g.Second; Turn t = new Turn(g.Circle.Center, f); return t.GetAngleInRadians(s); }
/// <summary> /// Checks whether a location falls in the sector lying between the BC and EC /// of a circular arc. The only condition is that the location has an appropriate /// bearing with respect to the bearings of the BC & EC (i.e. the location does not /// necessarily lie ON the arc). /// </summary> /// <param name="pos">The position to check</param> /// <param name="lintol">Linear tolerance, in meters on the ground (locations that are /// beyond the BC or EC by up to this much will also be regarded as "in-sector").</param> /// <returns>True if position falls in the sector defined by this arc</returns> public static bool IsInSector(ICircularArcGeometry g, IPosition pos, double lintol) { // If the arc is a complete circle, it's ALWAYS in sector. if (IsCircle(g)) return true; // Express the curve's start & end points in local system, // ordered clockwise. IPointGeometry start = g.First; IPointGeometry end = g.Second; // Get the centre of the circular arc. IPosition centre = g.Circle.Center; // If we have a linear tolerance, figure out the angular equivalent. if (lintol > MathConstants.TINY) { double angtol = lintol/g.Circle.Radius; return BasicGeom.IsInSector(pos, centre, start, end, angtol); } else return BasicGeom.IsInSector(pos, centre, start, end, 0.0); }
/// <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; }
static double MinDistanceSquared(ICircularArcGeometry g, IPosition p) { // If the position lies in the arc sector, the minimum distance // is given by the distance to the circle. Otherwise the minimum // distance is the distance to the closest end of the arc. if (IsInSector(g, p, 0.0)) { double dist = BasicGeom.Distance(p, g.Circle.Center); double radius = g.Circle.Radius; return (dist-radius)*(dist-radius); } else { double d1 = BasicGeom.DistanceSquared(p, g.BC); double d2 = BasicGeom.DistanceSquared(p, g.EC); return Math.Min(d1, d2); } }
public static double GetStartBearingInRadians(ICircularArcGeometry g) { return BasicGeom.BearingInRadians(g.Circle.Center, g.First); }
public static void Render(ICircularArcGeometry g, ISpatialDisplay display, IDrawStyle style) { style.Render(display, (IClockwiseCircularArcGeometry)g); }
/// <summary> /// Does a circular arc represent a complete circle (with a /// BC that's coincident with the EC). /// </summary> public static bool IsCircle(ICircularArcGeometry g) { return g.BC.IsCoincident(g.EC); }
/// <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); }
/// <summary> /// Defines links for this face. A prior call to <c>SetLine</c> is required. /// </summary> /// <param name="prev">The preceding face (after it has been processed via a call to /// <c>SetLine</c>, Must refer to the same polygon as this face.</param> /// <returns>The links (the number of array elements will equal the value that came /// back from the <c>SetLine</c> call)</returns> internal PolygonLink[] CreateLinks(PolygonFace prev) { Debug.Assert(m_Polygon != null); Debug.Assert(m_Divider != null); Debug.Assert(prev.Divider != null); Debug.Assert(Object.ReferenceEquals(prev.Polygon, m_Polygon)); // Try to obtain a point feature at the beginning of this face. ISpatialIndex index = CadastralMapModel.Current.Index; PointFeature beginPoint = new FindPointQuery(index, m_Begin).Result; // If the polygon to the left of the this face? (if so, curve-related // things may need to be reversed below) bool isPolLeft = (m_Divider.Left == m_Polygon); // Default geometric info we need to define bool isCurveEnd = false; bool isRadial = false; double bearing = 0.0; double angle = 0.0; // Is the position at the beginning of this face the start // or end of a circular arc (points between 2 curves (on // compound curve) are NOT considered to be curve ends). Note // that the line could either be a CircularArc, or a topological // section based on a circular arc. ICircularArcGeometry prevArc = (prev.Divider.LineGeometry as ICircularArcGeometry); ICircularArcGeometry thisArc = (m_Divider.LineGeometry as ICircularArcGeometry); bool isPrevCurve = (prevArc != null); bool isThisCurve = (thisArc != null); isCurveEnd = (isPrevCurve != isThisCurve); // If we are dealing with a point between two curves try to // set the curve parameters and, if successful, we will treat // the point as a radial point. if (isPrevCurve && isThisCurve) { isRadial = true; // Get the curve parameters... IPosition prevcen = prevArc.Circle.Center; double prevrad = prevArc.Circle.Radius; IPosition thiscen = thisArc.Circle.Center; double thisrad = thisArc.Circle.Radius; // We only need to know the sense for one of the arcs bool iscw = thisArc.IsClockwise; // If the 2 curves do not have the same centre and radius, // see if they are really close (to the nearest centimeter // on the ground). In that case, use the average values for // the 2 curves. If they really are different curves, don't // treat this as a radial curve point -- treat it as a // curve end instead. IPosition centre = null; // The centre to actually use if (!(prevcen == thiscen && Math.Abs(prevrad - thisrad) < Constants.TINY)) { double xc1 = prevcen.X; double yc1 = prevcen.Y; double xc2 = thiscen.X; double yc2 = thiscen.Y; double dxc = xc2 - xc1; double dyc = yc2 - yc1; if (Math.Abs(dxc) < 0.01 && Math.Abs(dyc) < 0.01 && Math.Abs(prevrad - thisrad) < 0.01) { // Close enough centre = new Position(xc1 + dxc * 0.5, yc1 + dyc * 0.5); } else { isRadial = false; isCurveEnd = true; } } else { centre = prevcen; } // If the centre and radius were the same (or close enough), // define the radial bearing from the centre of the circle. // If the polygon is actually on the other side, reverse the // bearing so that it's directed INTO the polygon. if (isRadial) { Debug.Assert(centre != null); bearing = Geom.BearingInRadians(centre, m_Begin); angle = 0.0; if (iscw != isPolLeft) { bearing += Constants.PI; } } } // If we're not dealing with a radial curve (or we have curves that // don't appear to be radial) if (!isRadial) { // Get the clockwise angle from the last position of the // preceding face to the first position after the start // of this face. Since info is held in a clockwise cycle // around the polygon, this will always give us the exterior // angle. Turn reference = new Turn(m_Begin, prev.TailReference); angle = reference.GetAngleInRadians(this.HeadReference); // Define the bearing to use for projecting the point. It's // in the middle of the angle, but projected into the polygon. bearing = reference.BearingInRadians + angle * 0.5 + Constants.PI; } // Initialize the link at the start of the face List <PolygonLink> links = new List <PolygonLink>(); PolygonLink link = new PolygonLink(beginPoint, isCurveEnd, isRadial, bearing, angle); links.Add(link); // Initialize links for any extra points if (m_ExtraPoints != null) { // Intermediate points can never be curve ends isCurveEnd = false; // If the face is a curve, they're radial points isRadial = isThisCurve; // Note any curve info double radius; IPosition centre = null; bool iscw = false; if (isRadial) { Debug.Assert(m_Divider.Line.LineGeometry is ICircularArcGeometry); ICircularArcGeometry arc = (m_Divider.Line.LineGeometry as ICircularArcGeometry); centre = arc.Circle.Center; radius = arc.Circle.Radius; iscw = arc.IsClockwise; angle = 0.0; } for (uint i = 0; i < m_ExtraPoints.Length; i++) { //IPointGeometry loc = m_ExtraPoints[i].Geometry; PointFeature loc = m_ExtraPoints[i]; // Figure out the orientation bearing for the point if (isRadial) { Debug.Assert(centre != null); bearing = Geom.BearingInRadians(centre, loc); if (iscw != isPolLeft) { bearing += Constants.PI; } } else { // Get the exterior clockwise angle IPointGeometry back; IPointGeometry fore; if (i == 0) { back = m_Begin; } else { back = m_ExtraPoints[i - 1].Geometry; } if (i == (m_ExtraPoints.Length - 1)) { fore = m_End; } else { fore = m_ExtraPoints[i + 1].Geometry; } Turn reference = new Turn(loc, back); angle = reference.GetAngleInRadians(fore); // Define the bearing to use for projecting the point. It's // in the middle of the angle, but projected into the polygon. bearing = reference.BearingInRadians + angle * 0.5 + Constants.PI; } link = new PolygonLink(m_ExtraPoints[i], isCurveEnd, isRadial, bearing, angle); links.Add(link); } } return(links.ToArray()); }
internal override uint IntersectArc(IntersectionResult results, ICircularArcGeometry arc) { return(Make().IntersectArc(results, arc)); }
internal override uint IntersectArc(IntersectionResult results, ICircularArcGeometry that) { return IntersectionHelper.Intersect(results, (ILineSegmentGeometry)this, that); }
internal virtual void ShowResult() { // If we have two points, get the distance between them, // format the result, and display it. if (m_Point1!=null && m_Point2!=null && m_CommCir!=null) { // It's conceivable that the two points share more than // one common circle. For now, just pick off the first // common circle and use that. Circle circle = m_CommCir[0]; // Get the centre of the circle. IPosition c = circle.Center; // Get the clockwise angle from point 1 to point 2. Turn reft = new Turn(c, m_Point1); double angle = reft.GetAngleInRadians(m_Point2); bool iscw = true; // Make sure the angle is consistent with whether we want // the short or the long arc distance. bool isshort = (angle < Constants.PI); if (isshort != m_WantShort) { angle = Constants.PIMUL2 - angle; iscw = false; } // Get the arc distance and display it. double metric = angle * circle.Radius; distanceTextBox.Text = Format(metric, m_Point1, m_Point2); // Remember the geometry that corresponds to the displayed distance (this // will be drawn when the controller periodically calls the Draw method). m_CurrentDistanceArc = new CircularArcGeometry(circle, m_Point1, m_Point2, iscw); } else { distanceTextBox.Text = "<no distance>"; m_CurrentDistanceArc = null; } }
internal uint IntersectArc(ICircularArcGeometry arc) { return(m_IntersectedObject.LineGeometry.IntersectArc(this, arc)); }
internal override uint IntersectArc(IntersectionResult results, ICircularArcGeometry arc) { return Make().IntersectArc(results, arc); }
/// <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(); }
internal static uint Intersect(IntersectionResult results, IMultiSegmentGeometry line, ICircularArcGeometry arc) { uint nx=0; IPointGeometry[] segs = line.Data; IPointGeometry f = arc.First; IPointGeometry s = arc.Second; ICircleGeometry circle = arc.Circle; for (int i=1; i<segs.Length; i++) nx += Intersect(results, segs[i-1], segs[i], f, s, circle); return nx; }
public static ILength GetDistance(ICircularArcGeometry g, IPosition p) { return new Length(Math.Sqrt(MinDistanceSquared(g, p))); }
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); }
public static IWindow GetExtent(ICircularArcGeometry g) { // If the curve is a complete circle, just define it the easy way. if (g.BC.IsCoincident(g.EC)) return CircleGeometry.GetExtent(g.Circle); IPosition bcp = g.BC; IPosition ecp = g.EC; IPosition centre = g.Circle.Center; // Initialize the window with the start location. Window win = new Window(bcp); // Expand using the end location win.Union(ecp); // If the curve is completely within one quadrant, we're done. QuadVertex bc = new QuadVertex(centre, bcp); QuadVertex ec = new QuadVertex(centre, ecp); Quadrant qbc = bc.Quadrant; Quadrant qec = ec.Quadrant; if (qbc == qec) { if (g.IsClockwise) { if (bc.GetTanAngle() < ec.GetTanAngle()) return win; } else { if (ec.GetTanAngle() < bc.GetTanAngle()) return win; } } // Get the window of the circle IWindow circle = CircleGeometry.GetExtent(g.Circle); // If the curve is anticlockwise, switch the quadrants for BC & EC if (!g.IsClockwise) { Quadrant temp = qbc; qbc = qec; qec = temp; } // Expand the window, depending on which quadrants the start & // end points fall in. The lack of breaks in the inner switches // is intentional (e.g. if start & end both fall in Quadrant.NorthEast, // the window we want is the complete circle, having checked above // for the case where the arc is JUST in Quadrant.NorthEast). // Define do-nothing values for the Union's below double wx = win.Min.X; double wy = win.Min.Y; if (qbc==Quadrant.NE) { switch (qec) { case Quadrant.NE: win.Union(wx, circle.Max.Y); goto case Quadrant.NW; case Quadrant.NW: win.Union(circle.Min.X, wy); goto case Quadrant.SW; case Quadrant.SW: win.Union(wx, circle.Min.Y); goto case Quadrant.SE; case Quadrant.SE: win.Union(circle.Max.X, wy); break; } } else if (qbc==Quadrant.SE) { switch (qec) { case Quadrant.SE: win.Union(circle.Max.X, wy); goto case Quadrant.NE; case Quadrant.NE: win.Union(wx, circle.Max.Y); goto case Quadrant.NW; case Quadrant.NW: win.Union(circle.Min.X, wy); goto case Quadrant.SW; case Quadrant.SW: win.Union(wx, circle.Min.Y); break; } } else if (qbc==Quadrant.SW) { switch (qec) { case Quadrant.SW: win.Union(wx, circle.Min.Y); goto case Quadrant.SE; case Quadrant.SE: win.Union(circle.Max.X, wy); goto case Quadrant.NE; case Quadrant.NE: win.Union(wx, circle.Max.Y); goto case Quadrant.NW; case Quadrant.NW: win.Union(circle.Min.X, wy); break; } } else if (qbc==Quadrant.NW) { switch (qec) { case Quadrant.NW: win.Union(circle.Min.X, wy); goto case Quadrant.SW; case Quadrant.SW: win.Union(wx, circle.Min.Y); goto case Quadrant.SE; case Quadrant.SE: win.Union(circle.Max.X, wy); goto case Quadrant.NE; case Quadrant.NE: win.Union(wx, circle.Max.Y); break; } } return win; }
/// <summary> /// Intersects a pair of clockwise arcs, where one of the ends exactly coincides with the /// other arc. The two arcs are assumed to sit on different circles. /// </summary> /// <param name="xsect">The intersection results.</param> /// <param name="bc">The start of the other arc.</param> /// <param name="ec">The end of the other arc.</param> /// <param name="circle">The circle that the other arc sits on.</param> /// <param name="xend">The end of THIS arc that coincides with one end of the other one.</param> /// <param name="othend">The other end of THIS arc (may or may not coincide with one end of /// the other arc).</param> /// <param name="xCircle">The circle for THIS arc</param> /// <returns>The number of intersections (1 or 2).</returns> static uint EndIntersect( IntersectionResult xsect , ICircularArcGeometry ab , ICircularArcGeometry pq , bool isFirstEndCoincident) { IPointGeometry bc = pq.First; IPointGeometry ec = pq.Second; ICircleGeometry circle = pq.Circle; IPointGeometry xend = (isFirstEndCoincident ? ab.First : ab.Second); IPointGeometry othend = (isFirstEndCoincident ? ab.Second : ab.First); ICircleGeometry xCircle = ab.Circle; // The two curves sit on different circles, so do a precise intersection of the circles. IPointGeometry c1 = xCircle.Center; IPointGeometry c2 = circle.Center; double r1 = xCircle.Radius; double r2 = circle.Radius; IPosition x1, x2; uint nx = Geom.IntersectCircles(c1, r1, c2, r2, out x1, out x2); // If we didn't get ANY intersections, that's a bit unusual // seeing how one of the ends matches. However, it's possible // due to roundoff of the end locations. So in that case, just // return a single intersection at the matching end. if (nx==0) { xsect.Append(xend); return 1; } // @devnote If we got 1 intersection (i.e. the 2 circles just // touch), you might be tempted to think that it must be close // to the matching end location. That is NOT the case if the // circles are big. // If we got 2 intersections, pick the one that's further away // than the matching end. if (nx==2 && Geom.DistanceSquared(x2, xend) > Geom.DistanceSquared(x1, xend)) x1 = x2; // That leaves us with ONE intersection with the circle ... now // confirm that it actually intersects both curves! // Does it fall in the sector defined by the clockwise curve? IPointGeometry centre = c2; Turn reft = new Turn(centre, bc); double eangle = reft.GetAngleInRadians(ec); double xangle = reft.GetAngleInRadians(x1); if (xangle > eangle) { xsect.Append(xend); return 1; } // Does it fall in the sector defined by this curve (NO tolerance allowed). PointGeometry xloc = PointGeometry.Create(x1); bool isxthis = Geom.IsInSector(xloc, c1, ab.First, ab.Second, 0.0); if (!isxthis) { xsect.Append(xend); return 1; } // Get the midpoint of the segment that connects the intersection to the matching end. IPosition midx = Position.CreateMidpoint(xend, 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). Also, // the old way used 'centre' which may refer to r1 OR r2, so // you would have got the correct result only half of the time! // if ( fabs(midx.Distance(centre) - r1) > XYTOL ) { double rdiff = Geom.Distance(midx, c1) - r1; 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 curves, 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(xend, 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. xsect.Append(xend, x1); return 1; }
internal abstract uint IntersectArc(IntersectionResult results, ICircularArcGeometry arc);