/// <summary> /// Determines whether u is in the circumcircle of a, b, and c. /// </summary> public static Containment CircumcircleTest(VecRat2 a, VecRat2 b, VecRat2 c, VecRat2 d) { Turn t = TurnTestDiscrete(a, b, c); if (t == Turn.Right) { VecRat2 temp = b; b = c; c = temp; } else if (t == Turn.Linear) { throw new Exception("Can't do circumcircle test with a,b,c colinear."); } Rational ld = d.LengthSquared(); Rational r = Det3( a.X - d.X, a.Y - d.Y, a.LengthSquared() - ld, b.X - d.X, b.Y - d.Y, b.LengthSquared() - ld, c.X - d.X, c.Y - d.Y, c.LengthSquared() - ld); if (r > 0) { return(Containment.Inside); } else if (r == 0) { return(Containment.Boundary); } else { return(Containment.Outside); } }
private static void FindNewEvent(Segment s1, Segment s2, EventPoint eventPoint, RBTreeMap <EventPoint, LinkedList <Segment> > eventQueue) { //If two segments intersect below the sweep line, or on it and //to the right of the current event point, and the intersection //is not yet present as an event in Q: //then insert a new event point in Q for this intersection VecRat2 pointIntersection = new VecRat2(); SegRat2 segmentIntersection = new SegRat2(); //bool intersectionExists = Segment.ComputeIntersection(s1, s2, out pointIntersection); //if (intersectionExists) SegmentIntersectionType result = GeomAid.SegmentIntersection(s1.ToSegRat2(), s2.ToSegRat2(), ref pointIntersection, ref segmentIntersection); if (result == SegmentIntersectionType.Point) { EventPoint newEventPoint = new EventPoint(null); newEventPoint.Position = pointIntersection; if (eventPoint.CompareTo(newEventPoint) < 0 && !eventQueue.ContainsKey(newEventPoint)) { LinkedList <Segment> upperList = new LinkedList <Segment>(); eventQueue.Add(new RBTreeMapNode <EventPoint, LinkedList <Segment> >(newEventPoint, upperList)); } } else if (result == SegmentIntersectionType.Segment) { throw new NotImplementedException("Didn't think this would ever happen?!"); } }
public SegRat2(VecRat2 a, VecRat2 b, bool aClosed, bool bClosed) { this.A = a; this.B = b; this.AClosed = aClosed; this.BClosed = bClosed; }
private Comparison <OA_Segment> AngleComparisonUpperList(VecRat2 origin) { return(delegate(OA_Segment a, OA_Segment b) { return GeomAid.TurnTest(origin, b.Lower.Position, a.Lower.Position); }); }
public LineProjectionTransform(SegRat2 s) { this.anchor = s.A; this.dir = s.AB(); this.dot_anchor = dir * anchor; this.inv_dir_len_sq = 1 / dir.LengthSquared(); }
public static Rational Det2( VecRat2 row1, VecRat2 row2) { return(Det2( row1.X, row1.Y, row2.X, row2.Y)); }
/// <summary> /// Assumes the two lines u1-v1 and u2-v2 are not parallel. /// </summary> public static VecRat2 LineIntersection(VecRat2 a1, VecRat2 b1, VecRat2 a2, VecRat2 b2) { Rational s1det = MathAid.Det2(a1, b1); Rational s2det = MathAid.Det2(a2, b2); VecRat2 diff1 = a1 - b1; VecRat2 diff2 = a2 - b2; return((s1det * diff2 - s2det * diff1) / MathAid.Det2(diff1, diff2)); }
/// <summary> /// -1 => right turn /// 0 => no turn /// 1 => left turn /// </summary> public static int TurnTest(VecRat2 a, VecRat2 b, VecRat2 c) { //return Rational.Sign(a.X * b.Y + a.Y * c.X + b.X * c.Y - a.X * c.Y - a.Y * b.X - b.Y * c.X); VecRat2 u = b - a; u = new VecRat2(u.Y, -u.X); //turn to right 90 degrees Rational udota = u.X * a.X + u.Y * a.Y; Rational udotc = u.X * c.X + u.Y * c.Y; return(udota.CompareTo(udotc)); }
public Rational CycleArea() { Rational twiceSignedArea = 0; VecRat2 origin = Origin.Position; foreach (DCEL_HalfEdge halfEdge in CycleNext) { twiceSignedArea += GeomAid.TriangleTwiceSignedArea(origin, halfEdge.Origin.Position, halfEdge.Destination.Position); } return(Rational.Abs(twiceSignedArea) / 2); }
public static VecRat2 LineIntersection(VecRat2 u1, VecRat2 v1, VecRat2 u2, VecRat2 v2) { Rational u1v1det = u1.X * v1.Y - u1.Y * v1.X; Rational u2v2det = u2.X * v2.Y - u2.Y * v2.X; VecRat2 diff1 = u1 - v1; VecRat2 diff2 = u2 - v2; Rational denom = diff1.X * diff2.Y - diff1.Y * diff2.X; Rational numx = u1v1det * diff2.X - u2v2det * diff1.X; Rational numy = u1v1det * diff2.Y - u2v2det * diff1.Y; return(new VecRat2(numx / denom, numy / denom)); }
public static Turn TurnTestDiscrete(VecRat2 a, VecRat2 b, VecRat2 c) { int sign = TurnTest(a, b, c); if (sign < 0) { return(Turn.Right); } else if (sign > 0) { return(Turn.Left); } else { return(Turn.Linear); } }
/// <summary> /// Returns whether x is in triangle(abc) /// </summary> public static bool TriangleTest(VecRat2 a, VecRat2 b, VecRat2 c, VecRat2 x) { int s1 = Rational.Sign(TurnTest(a, b, c)); int s2 = Rational.Sign(TurnTest(a, b, x)); if (s1 != s2) { return(false); } int s3 = Rational.Sign(TurnTest(b, c, x)); if (s2 != s3) { return(false); } int s4 = Rational.Sign(TurnTest(c, a, x)); return(s3 == s4); }
/// <summary> /// halfEdge should be Upper->Lower so that the persistent half edges become: /// o halfEdge (Upper->Lower) ==> (vertex->Lower) /// o halfEdge.Twin (Lower->Upper) ==> (Lower->vertex) /// And the two newly created half edges are (vertex->Upper) and (Upper->vertex). /// </summary> private static void SplitEdge(DCEL_Subdivision subdivision, DCEL_HalfEdge halfEdge, DCEL_Vertex vertex) { Debug.Assert(VecRat2.CompareReadingOrder(halfEdge.Origin.Position, halfEdge.Destination.Position) < 0); DCEL_HalfEdge e1 = halfEdge; DCEL_HalfEdge e2 = e1.Twin; DCEL_HalfEdge e1_prev = e1.Prev; DCEL_HalfEdge e2_next = e2.Next; DCEL_Vertex e1_origin = e1.Origin; DCEL_HalfEdge e1_top = new DCEL_HalfEdge(); DCEL_HalfEdge e2_top = new DCEL_HalfEdge(); DCEL_Helper.JoinTwin(e1_top, e2_top); e1_top.IncidentFace = e1.IncidentFace; e2_top.IncidentFace = e2.IncidentFace; DCEL_Helper.JoinIncidentEdge(vertex, e2_top); DCEL_Helper.JoinIncidentEdge(vertex, e1); DCEL_Helper.JoinIncidentEdge(e1_origin, e1_top); if (e2_next == e1) { DCEL_Helper.JoinNext(e2, e2_top); DCEL_Helper.JoinNext(e2_top, e1_top); DCEL_Helper.JoinNext(e1_top, e1); } else { DCEL_Helper.JoinPrevNext(e2, e2_top, e2_next); DCEL_Helper.JoinPrevNext(e1_prev, e1_top, e1); } if (subdivision != null) { subdivision.HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(e1_top)); subdivision.HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(e2_top)); } }
private void FindNewEventPoint(OA_Segment segment1, OA_Segment segment2, OA_EventPoint eventPoint) { VecRat2 pointIntersection = new VecRat2(); SegRat2 segmentIntersection = new SegRat2(); SegmentIntersectionType result = GeomAid.SegmentIntersection(segment1.ToSegRat2(), segment2.ToSegRat2(), ref pointIntersection, ref segmentIntersection); if (result == SegmentIntersectionType.Point) { OA_EventPoint newEventPoint = new OA_EventPoint(pointIntersection); if (eventPoint.CompareTo(newEventPoint) < 0) { //Add the new event point if it isn't already in the event queue eventQueue.Add(new RBTreeSetNode <OA_EventPoint>(newEventPoint)); } } else if (result == SegmentIntersectionType.Segment) { throw new NotImplementedException("Didn't think this would ever happen?!"); } }
/// <summary> /// Create a subdivision from a single segment (u, v). /// </summary> public DCEL_Subdivision(VecRat2 u, VecRat2 v) : this() { if (u == v) { throw new Exception("Tried to create a DCELSubdivision with a segment of length 0."); } DCEL_Vertex vertex_u = new DCEL_Vertex(u); DCEL_Vertex vertex_v = new DCEL_Vertex(v); DCEL_HalfEdge halfedge_uv = new DCEL_HalfEdge(); DCEL_HalfEdge halfedge_vu = new DCEL_HalfEdge(); DCEL_Face face = new DCEL_Face(); vertex_u.IncidentEdge = halfedge_uv; vertex_v.IncidentEdge = halfedge_vu; halfedge_uv.Origin = vertex_u; halfedge_uv.Twin = halfedge_vu; halfedge_uv.IncidentFace = face; halfedge_uv.Prev = halfedge_vu; halfedge_uv.Next = halfedge_vu; halfedge_vu.Origin = vertex_v; halfedge_vu.Twin = halfedge_uv; halfedge_vu.IncidentFace = face; halfedge_vu.Prev = halfedge_uv; halfedge_vu.Next = halfedge_uv; face.InnerComponents.AddLast(halfedge_uv); Vertices.Add(new RBTreeSetNode <DCEL_Vertex>(vertex_u)); Vertices.Add(new RBTreeSetNode <DCEL_Vertex>(vertex_u)); HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(halfedge_uv)); HalfEdges.Add(new RBTreeSetNode <DCEL_HalfEdge>(halfedge_vu)); Faces.Add(new RBTreeSetNode <DCEL_Face>(face)); UnboundedFace = face; }
private LineSegmentIntersection(VecRat2 position, IEnumerable <DCEL_HalfEdge> incidentLineSegments) { Position = position; IncidentLineSegments = new LinkedList <DCEL_HalfEdge>(incidentLineSegments); }
public static int TurnTest(VecRat2 a, VecRat2 b, VecRat2 c) { return(Rational.Sign(TriangleTwiceSignedArea(a, b, c))); }
//If the two segments are disjoint, then None is returned. //Else, if the two segments are colinear, then either Segment is returned. //Else, if the two segments are not colinear, Point is returned. public static SegmentIntersectionType SegmentIntersection(SegRat2 s, SegRat2 t, ref VecRat2 pointIntersection, ref SegRat2 segmentIntersection) { //This check is important for handling degenerate cases like s = [(x,y), (x,y)). if (s.IsEmpty() || t.IsEmpty()) { return(SegmentIntersectionType.None); } //This check is important because the LineProjectionTransform can only be formed with a non-point segment. if (s.IsPoint()) { if (PointInSegment(s.A, t)) { segmentIntersection = s; return(SegmentIntersectionType.Segment); } else { return(SegmentIntersectionType.None); } } int turn_s_ta = TurnTest(s, t.A); int turn_s_tb = TurnTest(s, t.B); if (turn_s_ta == 0 && turn_s_tb == 0) { return(ColinearSegmentIntersection(s, t, ref pointIntersection, ref segmentIntersection)); } if (s.AClosed) { if (t.AClosed && s.A == t.A) { pointIntersection = s.A; return(SegmentIntersectionType.Point); } else if (t.BClosed && s.B == t.B) { pointIntersection = s.B; return(SegmentIntersectionType.Point); } } if (s.BClosed) { if (t.AClosed && s.B == t.A) { pointIntersection = s.B; return(SegmentIntersectionType.Point); } else if (t.BClosed && s.B == t.B) { pointIntersection = s.B; return(SegmentIntersectionType.Point); } } int turn_t_sa = TurnTest(t, s.A); int turn_t_sb = TurnTest(t, s.B); int val_s = turn_s_ta * turn_s_tb; int val_t = turn_t_sa * turn_t_sb; if (val_s < 0 && val_t < 0) { pointIntersection = LineIntersection(s, t); return(SegmentIntersectionType.Point); } else { return(SegmentIntersectionType.None); } }
public int CompareTo(DCEL_Vertex other) { return(VecRat2.CompareReadingOrder(this.Position, other.Position)); }
public DCEL_Vertex(VecRat2 position) : base() { Position = position; IncidentEdge = null; }
public static int TurnTest(SegRat2 s, VecRat2 p) { return(TurnTest(s.A, s.B, p)); }
/// <summary> /// Compared HalfEdges should have Origin = origin and Destination > origin. /// </summary> private Func <DCEL_HalfEdge, DCEL_HalfEdge, int> AngleComparisonUpperList_HalfEdge(VecRat2 origin) { return(delegate(DCEL_HalfEdge a, DCEL_HalfEdge b) { return GeomAid.TurnTest(origin, b.Destination.Position, a.Destination.Position); }); }
public static Rational TriangleTwiceArea(VecRat2 a, VecRat2 b, VecRat2 c) { return(Rational.Abs(TriangleTwiceSignedArea(a, b, c))); }
public OA_EventPoint(VecRat2 position) : this() { Position = position; }
public static SegmentIntersectionType ColinearSegmentIntersection(SegRat2 s, SegRat2 t, ref VecRat2 pointIntersection, ref SegRat2 segmentIntersection) { //This check is important for handling degenerate cases like s = [(x,y), (x,y)). if (s.IsEmpty() || t.IsEmpty()) { return(SegmentIntersectionType.None); } //This check is important because the LineProjectionTransform can only be formed with a non-point segment. if (s.IsPoint()) { if (ColinearPointInSegment(s.A, t)) { pointIntersection = s.A; return(SegmentIntersectionType.Point); } else { return(SegmentIntersectionType.None); } } LineProjectionTransform transform = new LineProjectionTransform(s); SegRat1 proj_s = transform.Project(s); SegRat1 proj_t = transform.Project(t); Rational proj_pointIntersection = new Rational(); SegRat1 proj_segmentIntersection = new SegRat1(); SegmentIntersectionType result = SegmentIntersection( proj_s, proj_t, ref proj_pointIntersection, ref proj_segmentIntersection); if (result == SegmentIntersectionType.Point) { pointIntersection = transform.Unproject(proj_pointIntersection); } else if (result == SegmentIntersectionType.Segment) { segmentIntersection = transform.Unproject(proj_segmentIntersection); } return(result); }
public SegRat2(VecRat2 a, VecRat2 b) : this(a, b, true) { }
public static bool ColinearPointInSegment(VecRat2 p, SegRat2 s) { LineProjectionTransform transform = new LineProjectionTransform(s); return(PointInSegment(transform.Project(p), transform.Project(s))); }
public SegRat2(VecRat2 a, VecRat2 b, bool closed) : this(a, b, closed, closed) { }
public static bool PointInSegment(VecRat2 p, SegRat2 s) { return(TurnTest(s, p) == 0 && ColinearPointInSegment(p, s)); }
public static Rational TriangleTwiceSignedArea(VecRat2 a, VecRat2 b, VecRat2 c) { return(MathAid.Det2(b - a, c - a)); }