/// <summary> /// Construct a group of 4 edges {e[0], e[1], e[2], e[3]} where e[0] represent the canonical /// representative to which edge e belongs. This allows to represent and edge /// by dividing it into 4 edges. /// For more See 2.2 Duality (Definition 2.1.) and 5.BASIC TOPOLOGICAL OPERATORS in the article. /// </summary> public static QuadEdge <T> MakeEdge(Vec3 origin, Vec3 destination) { // Primal QuadEdge <T> qE0 = new QuadEdge <T>(null, null, origin); // Dual QuadEdge <T> qE1 = new QuadEdge <T>(null, null, null); // Primal QuadEdge <T> qE2 = new QuadEdge <T>(null, null, destination); // Dual QuadEdge <T> qE3 = new QuadEdge <T>(null, null, null); // Onext ring of the primal (delaunay) // See Fig.5 (c) qE0._oNext = qE0; qE2._oNext = qE2; // Onext ring of the Dual (Voronoi) // See Fig.5 (c) qE1._oNext = qE3; qE3._oNext = qE1; // Create connection between subdivision (allow to access Primal and Dual) // Implicitly set qE0.Destination = qE2.Origin (Destination == Rot.Rot.Origin) qE0._rot = qE1; qE1._rot = qE2; qE2._rot = qE3; qE3._rot = qE0; // Return the canonical representative. return(qE0); }
/// <summary> /// Construct a face abstraction based on a <paramref name="primal"/> edge. /// </summary> /// <param name="primal">Delaunay edge with Origin as face center.</param> /// <param name="onBounds">Mark face as a face on the faces bounds.</param> /// <param name="reconstructed">Must be true if face has a site at infinity.</param> public Face(QuadEdge <TEdge> primal, bool onBounds, bool reconstructed) { this._primal = primal; this._onBounds = onBounds; this._reconstructed = reconstructed; this._id = nextID++; }
/// <summary> /// This operation affects the two edge rings a.Origin and b.Origin and, independently, /// the two edge rings a.Left and b.Left. In each case, /// - (a) if the two rings are distinct, Splice will combine them into one /// - (b) if the two are exactly the same ring, Splice will break it in two separate pieces /// - (c) if the two are the same ring taken with opposite orientations, Splice will Flip (and reverse the order) /// of a segment of that ring /// </summary> /// <remarks> /// Splice is its own inverse and calling twice in a row revert it back to origin. /// Splice does not affect Rot neither Origin and Destination that have no topological meaning. /// </remarks> /// <param name="a">First QuadEdge<T></param> /// <param name="b">Second QuadEdge<T></param> public static void Splice(QuadEdge <T> a, QuadEdge <T> b) { QuadEdge <T> alpha = a._oNext._rot; QuadEdge <T> beta = b._oNext._rot; // Swap them all ! Helper.Swap <QuadEdge <T> >(ref a._oNext, ref b._oNext); Helper.Swap <QuadEdge <T> >(ref alpha._oNext, ref beta._oNext); }
/// <summary> /// Construct an edge. /// </summary> public QuadEdge(QuadEdge <T> oNext, QuadEdge <T> rot, Vec3 origin) { this._oNext = oNext; this._rot = rot; this._origin = origin; this.Tag = false; _id = QuadEdge <T> .nextID++; }
/// <summary> /// Iterate over every edge destination sharing the same origin (default to CW order) /// </summary> /// <param name="CCW">Select in which order vertices should be returned.</param> public IEnumerable <Vec3> DestinationsFrom(bool CCW = false) { QuadEdge <T> current = this; do { yield return(current.Destination); current = CCW ? current.Onext : current.Oprev; } while (current != this); }
/// <summary> /// Iterate over every edges sharing the same origin (default to CW order) /// </summary> /// <param name="CCW">Select in which order edges should be returned.</param> public IEnumerable <QuadEdge <T> > EdgesFrom(bool CCW = false) { QuadEdge <T> current = this; do { yield return(current); current = CCW ? current.Onext : current.Oprev; } while (current != this); }
/// <summary> /// Iterate over edges with same LEFT face (default to CW order) /// starting from this and return their origin. /// </summary> /// <param name="CCW">Select in which order vertices should be returned.</param> public IEnumerable <Vec3> LeftVertices(bool CCW = false) { QuadEdge <T> current = this; do { yield return(current.Origin); current = CCW ? current.Lnext : current.Lprev; } while (current != this); }
// Helpers enumerables used to abstract structure complexity /// <summary> /// Iterate over edges with same RIGHT face (default to CW order) /// starting from this. /// </summary> /// <param name="CCW">Select in which order vertices should be returned.</param> public IEnumerable <QuadEdge <T> > RightEdges(bool CCW = false) { QuadEdge <T> current = this; do { yield return(current); current = CCW ? current.Rnext : current.Rprev; } while (current != this); }
/// <summary> /// Connect two edges together leading to a.Destination --> b.Origin /// </summary> public static QuadEdge <T> Connect(QuadEdge <T> a, QuadEdge <T> b) { // Connect a to b QuadEdge <T> edge = MakeEdge(a.Destination, b.Origin); // See 6. TOPOLOGICAL OPERATORS FOR DELAUNAY DIAGRAMS Splice(edge, a.Lnext); Splice(edge.Sym, b); return(edge); }
/// <summary> /// Iterate over every vertices forming a face around this edge origin /// (default to CW order) assuming each edge face share the same left face. /// Edge between two sites at infinity does not exists (occurs for a face /// on the convex hull) and then a site will be missing. /// </summary> /// <remarks> /// In case of CCW == false missing edge Origin can be found by first taking /// left most edge (in primal graph) and then its Destination. /// </remarks> /// <param name="CCW">Select in which order vertices should be returned.</param> public IEnumerable <Vec3> FaceLeftVertices(bool CCW = false) { QuadEdge <T> current = this.Rot; var first = current; do { yield return(current.Origin); current = CCW ? current.Lnext : current.Lprev; } while (current != first); }
/// <summary> /// Swap common segment between two triangles. Can be used to transform /// a two non delaunay triangles to a pair of triangle respecting this constraint. /// </summary> /// <remarks> /// /// /|\ / \ /// / | \ / \ /// / | \ / \ /// \ | / ---> \-----/ /// \ | / \ / /// \|/ \ / /// /// /// </remarks> public static void Swap(QuadEdge <T> edge) { QuadEdge <T> a = edge.Oprev; QuadEdge <T> b = edge.Sym.Oprev; // Disconnect edge Splice(edge, a); Splice(edge.Sym, b); // Reconnect edge Splice(edge, a.Lnext); Splice(edge.Sym, b.Lnext); // Update pointers edge._origin = a.Destination; edge.Destination = b.Destination; }
/// <summary> /// Disconnect edge from the structure. Opposite operation of Connect. /// </summary> public static void Delete(QuadEdge <T> edge) { Splice(edge, edge.Oprev); Splice(edge.Sym, edge.Sym.Oprev); }