1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkGeometricalQuadEdge_hxx
19 #define itkGeometricalQuadEdge_hxx
20 #include "itkGeometricalQuadEdge.h"
21 #include <limits>
22 #include <iostream>
23 
24 namespace itk
25 {
26 /**
27  */
28 template< typename TVRef, typename TFRef,
29           typename TPrimalData, typename TDualData, bool PrimalDual >
30 const typename GeometricalQuadEdge< TVRef, TFRef,
31                                     TPrimalData, TDualData, PrimalDual >::OriginRefType
32 GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::m_NoPoint =
33   std::numeric_limits< OriginRefType >::max();
34 
35 /**
36  *   Constructor
37  */
38 template< typename TVRef, typename TFRef,
39           typename TPrimalData, typename TDualData, bool PrimalDual >
40 GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >
GeometricalQuadEdge()41 ::GeometricalQuadEdge() :
42   m_Origin(m_NoPoint),
43   m_Data(),
44   m_LineCellIdent(0)
45 {
46 }
47 
48 /**
49  */
50 template< typename TVRef, typename TFRef,
51           typename TPrimalData, typename TDualData, bool PrimalDual >
SetLnextRingWithSameLeftFace(const DualOriginRefType faceGeom,int maxSize)52 bool GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::SetLnextRingWithSameLeftFace(
53   const DualOriginRefType faceGeom,
54   int maxSize)
55 {
56 #ifndef NDEBUG
57   if ( !this->IsLnextSharingSameFace(maxSize) )
58     {
59     itkQEDebugMacro("Lnext() edges do NOT share the same Left().");
60     return ( false );
61     }
62 #endif
63 
64   IteratorGeom it = this->BeginGeomLnext();
65 
66   while ( maxSize && ( it != this->EndGeomLnext() ) )
67     {
68     it.Value()->SetLeft(faceGeom);
69     it++;
70     maxSize--;
71     }
72 
73   return ( true );
74 }
75 
76 /**
77  * \brief Check wether the Lnext() ring of "this" edge is exactly of
78  *        size three AND if those three edges all share the same Left().
79  * @return Returns true when the Lnext() ring is the one of a triangle.
80  *         Returns false otherwise.
81  */
82 template< typename TVRef, typename TFRef,
83           typename TPrimalData, typename TDualData, bool PrimalDual >
IsLnextOfTriangle()84 bool GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::IsLnextOfTriangle()
85 {
86   return ( this->IsLnextSharingSameFace(3) );
87 }
88 
89 /**
90  * \brief Check wether the incoming argument is in the Onext() ring
91  *        of "this" edge or not.
92  * @param b The edge to test.
93  * @return Returns true when "this" edge and the incoming argument are
94  *         in the same Onext() ring. Returns false otherwise.
95  */
96 template< typename TVRef, typename TFRef,
97           typename TPrimalData, typename TDualData, bool PrimalDual >
IsInOnextRing(Self * b)98 bool GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::IsInOnextRing(Self *b)
99 {
100   for ( IteratorGeom it  = this->BeginGeomOnext();
101         it != this->EndGeomOnext();
102         it++ )
103     {
104     if ( b == it.Value() )
105       {
106       return true;
107       }
108     }
109   return false;
110 }
111 
112 /**
113  * \brief Check wether the incoming argument is in the Lnext() ring
114  *        of "this" edge or not.
115  * @param b The edge to test.
116  * @return Returns true when "this" edge and the incoming argument are
117  *         in the same Lnext() ring. Returns false otherwise.
118  */
119 template< typename TVRef, typename TFRef,
120           typename TPrimalData, typename TDualData, bool PrimalDual >
IsInLnextRing(Self * b)121 bool GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::IsInLnextRing(Self *b)
122 {
123   for ( IteratorGeom it  = this->BeginGeomLnext();
124         it != this->EndGeomLnext();
125         it++ )
126     {
127     if ( b == it.Value() )
128       {
129       return true;
130       }
131     }
132   return false;
133 }
134 
135 /**
136  * \brief Check wether edge's Origin is internal to the mesh (as opposed
137  *        to being on the boundary) by looking if all the edges in the
138  *        Onext() ring have a face set on both their Left() and Right()
139  *        side.
140  */
141 template< typename TVRef, typename TFRef,
142           typename TPrimalData, typename TDualData, bool PrimalDual >
143 bool
144 GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >
IsOriginInternal() const145 ::IsOriginInternal() const
146 {
147   ConstIteratorGeom it = this->BeginGeomOnext();
148 
149   while ( it != this->EndGeomOnext() )
150     {
151     using QuadEdgeType = typename ConstIteratorGeom::QuadEdgeType;
152     const QuadEdgeType *value = it.Value();
153     if ( !value->IsInternal() ) { return false; }
154     ++it;
155     }
156   return true;
157 }
158 
159 /**
160  * \brief Consider the first few edges in Lnext() ring of "this" edge.
161  *         Check wether those edges all share the same Left().
162  * @param  maxSize Looks at most maxSize edges in the Lnext() ring.
163  * @return Returns true when the Lnext() ring share THE same
164  *         Left() faces. Return false otherwise.
165  */
166 template< typename TVRef, typename TFRef,
167           typename TPrimalData, typename TDualData, bool PrimalDual >
IsLnextSharingSameFace(int maxSize)168 bool GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::IsLnextSharingSameFace(int maxSize)
169 {
170   IteratorGeom it = this->BeginGeomLnext();
171 
172   while ( maxSize && ( it != this->EndGeomLnext() ) )
173     {
174     // The condition isn't complicated: if left faces aren't set,
175     // continue, if just one is set return false, if both are set
176     // check if the face is the same
177     bool facesAreNotSet = !this->IsLeftSet() && !it.Value()->IsLeftSet();
178     bool facesAreTheSame = this->GetLeft() == it.Value()->GetLeft();
179     bool facesAreSet = this->IsLeftSet() && it.Value()->IsLeftSet();
180     //
181     // FIXME: This boolean expression can be simplified.
182     // ALEX : what about the version below ?
183     //
184     // if ( this->IsLeftSet() )         // one left set
185     // {
186     //     if (it.Value()->IsLeftSet()) // two left set
187     //     {
188     //         if( !(this->GetLeft() == it.Value()->GetLeft()) )
189     //          {
190     //              return( false );    // not same face
191     //           }
192     //      }
193     //      else                        // only one set
194     //      {
195     //          return( false );
196     //       }
197     // }
198     // else // one not set
199     // {
200     //     if(it.Value()->IsLeftSet()) // only one set
201     //     {
202     //         return( false );
203     //     }
204     // }
205     //
206     if ( !( facesAreNotSet || ( facesAreSet && facesAreTheSame ) ) )
207       {
208       return ( false );
209       }
210     it++;
211     maxSize--;
212     }
213 
214   if ( it != this->EndGeomLnext() )
215     {
216     // The Lnext ring is bigger than the caller expected
217     return ( false );
218     }
219   return ( true );
220 }
221 
222 /**
223  */
224 template< typename TVRef, typename TFRef,
225           typename TPrimalData, typename TDualData, bool PrimalDual >
226 typename GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::Self *
GetNextBorderEdgeWithUnsetLeft(Self * edgeTest)227 GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::GetNextBorderEdgeWithUnsetLeft(Self *edgeTest)
228 {
229   // Definition: an edge is said to be a boundary edge when it is adjacent to
230   // noface i.e. when at least one of the faces edge->GetLeft() or
231   // edge->GetRight() is unset.  Definition: an point is said to be a boundary
232   // point when at least one of the edges of it's Onext() ring is a boundary
233   // edge.
234   //
235   // Assume "this" edge belongs to a triangulation (i.e. it belongs to a QEMesh
236   // which represents a 2-manifold) which possesses a boundary.  Assume "this"
237   // edge instance is a boundary edge. Let us denote by P the point which is
238   // the origin of "this" edge i.e. P is this->Origin().  By definition P is a
239   // boundary point.  Then AT LEAST two [see the note below] edges of the
240   // Onext() ring of P [which all have the point P as Origin()] are themselves
241   // boundary edges. And among those boundary edges AT LEAST one has it's
242   // Left() face unset.  By iterating over the Onext() ring (which defines a
243   // local ordering on edges) this method searches for the first edge whose
244   // Left() face is unset AND which is encountered AFTER edgeTest.
245   //
246   // @param edgeTest When present, this edge will be considered as
247   //        the entry edge in the Onext() ring. When absent it shall
248   //        be defaulted to "this" edge. (see the warning below).
249   // @return When "this" edge is a boundary edge, return the first
250   //         edge in "this" Onext() ring whose Left() face is unset
251   //         AND located after edgeTest.
252   //         When "this" edge is NOT a boundary edge the 0 is
253   //         returned.
254   // @warning When the Mesh possessing "this" edge is a 2-manifold
255   //          then result of this method is unique in the sense that
256   //          it is independent from the edgeTest parameter.
257   //          But when the Mesh is not 2-manifold (this state can
258   //          happen at intermediary stages of the building process,
259   //          or during "surgical" operations on the Mesh, and
260   //          even though the Mesh represents a triangulation)
261   //          the result of this method is not unique in the sense
262   //          that the result depends on the edgeTest parameter.
263   //          Let us illusatre this dependence by considering a
264   //          Mesh (which is a triangulation) which is not a 2-manifold.
265   //          Assume the point P (the origin of "this" edge i.e.
266   //          P = this->Originv()) is TWICE on the border i.e. it
267   //          is adjacent twice to noface. We can consider the situation
268   //          of the following diagram, which depicts some Onext()
269   //          ring around point P:
270   //
271   //                       \         /                               //
272   //                        \   *   /                                //
273   //                        i3     b2              counter-clockwise //
274   //                  *       \   /   NO FACE      Onext() order.    //
275   //                           \ /                                   //
276   //                 ----b4-----P----b1------                        //
277   //                           /|\                                   //
278   //               NO FACE    / | \                                  //
279   //                         /  |  \    *  <------ a * indicates the //
280   //                        /   |   \         the presence of a face //
281   //                       /    |    \                               //
282   //                     b5    i6     i7                             //
283   //                     /   *  |  *   \                             //
284   //                    /       |       \                            //
285   //
286   //          On this example, and if we assume the Onext() oder is
287   //          represented counter-clockwise, the edges are ordered as
288   //          follows:
289   //             b1, b2, i3, b4, b5, i6, i7
290   //          (when arbitrarily starting at edge b1).
291   //          We have four Boundary edges labeled b1, b2, b4, b5 and
292   //          we have three internal edges (i.e. non boundary edges)
293   //          labeled i3, i6 and i7.
294   //          Depending on edgeTest, the result of this method
295   //          will NOT return the same edge:
296   //            - when edgeTest == b5 (or i6 or i7 or b1) then the edge
297   //              b1 will be returned,
298   //            - when edgeTest == b2 (or i3 or b4) then the edge
299   //              b4 will be returned,
300   //          Eventually, when edgeTest is absent, the result shall
301   //          depend on the position of "this" in the Onext() ring().
302   //
303 
304   // Be sure the Onext ring isn't already full
305   if ( this->IsOriginInternal() )
306     {
307     itkQEDebugMacro("Internal point.");
308     return ( nullptr );
309     }
310 
311   // Update reference
312   edgeTest = ( !edgeTest ) ? this : edgeTest;
313 
314   // On efficiency purposes
315   if ( edgeTest->IsIsolated() )
316     {
317     return ( edgeTest );
318     }
319 
320   // Ok, no more special cases
321   IteratorGeom it   = edgeTest->BeginGeomOnext();
322   IteratorGeom end  = edgeTest->EndGeomOnext();
323 
324   while ( it != end )
325     {
326     if ( !it.Value()->IsLeftSet() )
327       {
328       return ( it.Value() );
329       }
330     it++;
331     }
332 
333   // No border edge found
334   itkQEDebugMacro("Unfound border edge.");
335   return ( nullptr );
336 }
337 
338 /**
339  */
340 template< typename TVRef, typename TFRef,
341           typename TPrimalData, typename TDualData, bool PrimalDual >
InsertAfterNextBorderEdgeWithUnsetLeft(Self * isol,Self * hint)342 bool GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::InsertAfterNextBorderEdgeWithUnsetLeft(
343   Self *isol,
344   Self *hint)
345 {
346   // When the geometry of isol is set it must match the
347   // one of "this" Origin(). If the geometry is not set, we assume
348   // that both Origin are the same, regardless their actual value.
349   // Note: The purpose of this test is to avoid introducing some
350   //       incoherence in the geometry at Origin().
351   // The things should go this way:
352   // 1/ when the geometry of "this" Origin is not set, then be paranoid
353   //    and suspect the situation is already snafu:
354   //    1a/ if all edges of "this" Onext ring have an unset Origin()
355   //        (the situation is coherent), then proceed (Result=0)
356   //        whatever the value of isol.Origin() might be.
357   //    1b/ if one of the edges of "this" Onext ring has an Origin() set,
358   //        then we deduce that there is already some geometrical
359   //        incoherence at this->Origin() and exit this method (Result=1).
360   // 2/ Then when we didn't exit at stage 1, consider isol.Origin():
361   //    2a/ when isol.Origin() is absent proceed (result=0),
362   //    2b/ when isol.Origin() is present and Origin == isol.OriginSet then
363   //        proceed (result=0),
364   //    2c/ when isol.Origin() is present and Origin != isol.OriginSet then
365   //        exit (result=1).
366   //
367   // Here is what is implemented:
368   // +-----------+----------------+--------------------------+--------+
369   // | OriginSet | isol.OriginSet | Origin == isol.OriginSet | Result |
370   // +-----------+----------------+--------------------------+--------+
371   // |      0    |         0      |           0              |    0   |
372   // |      0    |         0      |           1              |    0   |
373   // |      0    |         1      |           0              |    1   |
374   // |      0    |         1      |           1              |    1   |
375   // +-----------+----------------+--------------------------+--------+
376   // |      1    |         0      |           0              |    1   |
377   // |      1    |         0      |           1              |    1   |
378   // |      1    |         1      |           0              |    1   |
379   // |      1    |         1      |           1              |    0   |
380   // +-----------+----------------+--------------------------+--------+
381   //
382   if ( !(   !( IsOriginSet() || isol->IsOriginSet() )
383             || ( IsOriginSet()
384                  && isol->IsOriginSet()
385                  && ( m_Origin == isol->m_Origin ) )
386             )
387        )
388     {
389     itkQEDebugMacro("Isolated Origin() differs from this Origin.");
390     return ( false );
391     }
392 
393   // Find out if this point has some room left for edge insertion:
394   Self *edgeAfter = this->GetNextBorderEdgeWithUnsetLeft(hint);
395   if ( !edgeAfter )
396     {
397     itkQEDebugMacro("This point is yet surrounded by faces.");
398     return ( false );
399     }
400 
401   // Normally, an edge was found
402   edgeAfter->Splice(isol);
403   return ( true );
404 }
405 
406 /**
407  */
408 template< typename TVRef, typename TFRef,
409           typename TPrimalData, typename TDualData, bool PrimalDual >
ReorderOnextRingBeforeAddFace(Self * second)410 bool GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::ReorderOnextRingBeforeAddFace(
411   Self *second)
412 {
413   // Assume "this->Originv()" is a boundary point P that is thrice adjacent
414   // to noface and consider the given situation is the one depicted by
415   // the following diagram where:
416   //   - P is "this->Originv()" instance,
417   //   - the * (star) indicates the presence of a face,
418   //   - b1, b2, b3, b4, b5, b6 denote boundary edges,
419   //   - p denotes some generic point,
420   //   - A and B denote some specific points we want to discuss,
421   //   - the Onext() ring order is represented counter-clockwise
422   //     [which is coherent with the definition of edge->GetRigth()]
423   //     i.e. the ordering of the edges is:
424   //          b1, b2, b3, b4, b5, b6, b1...
425   //
426   //                    p       N       p
427   //                   / \      O      / \                            //
428   //                  /   \           /   \                           //
429   //                 /     \    F    /     \       counter-clockwise  //
430   //                /      b3   A   b2      \      Onext() ring order //
431   //               /         \  C  /         \                        //
432   //              /     *     \ E /     *     \                       //
433   //             /             \ /             \                      //
434   //             A------b4------P------b1-------B                     //
435   //                           / \                                    //
436   //                          /   \                                   //
437   //             NO FACE     /     \      NO FACE                     //
438   //                        /       \                                 //
439   //                      b5         b6                               //
440   //                      /     *     \                               //
441   //                     /             \                              //
442   //                    p---------------p                             //
443   //
444   // At P this Mesh doesn't represent a 2-manifold (since we are thrice
445   // on the boundary). Nevertheless such a situation could arise in
446   // intermediary stages (e.g. when building the Mesh, or during
447   // surgical changes on the Mesh).
448   //    Now, assume we are asked to build the triangle [P, A, B]. Note
449   // that this request is not absurd since the current situation at
450   // P isn't the one of a 2-manifold: hence when building the current
451   // Onext() ring of P, we had not enough information to decide
452   // wheter b4.Onext() should be b5 or b1. It is ONLY when we are
453   // required to build the triangle [P, A, B] that we have the
454   // additional information that b4.Onext() is indeed b1.
455   //    When we are required to build triangle [P, A, B], we hence
456   // need to change the Onext() ring order at P, i.e. we need to deal
457   // with the triangle [P, b5, b6] which currently prevents
458   // b4.Onext() to be b1. In other terms, when considering the
459   // additional information that b4.Onext() is b1, and before
460   // building the triangle [P, A, B], we need to reorder
461   // the Onext() ring of P from it's current state
462   //    b1, b2, b3, b4, b5, b6, b1...
463   // to an order coherent with the [P, A, B] request, i.e.
464   //     b1, b2, b5, b6, b3, b4, b1...
465   //
466   // In order to establish the "proper" Onext() ring at P we use
467   // two Splice operations. The algorithm goes:
468   //   - first disconnect the piece of the surface containing the edge
469   //     [PB] (it would be the same process if we chose [PA]) from
470   //     the Onext() ring at P.
471   //   - second, re-integrate the disconnected piece at the desired
472   //     location i.e. side by side with [PA] (respectively [PB] if
473   //     we chose [PA] at first stage).
474   // By "piece of surface containing the edge [PB]" we mean [all]
475   // the triangle[s] starting at [PB] in the Onext() order and
476   // having a left face set.
477   //
478   // We can illustrate this process on bit more general diagram than
479   // the last case (where the "piece of surface containing the edge
480   // [PB]" is constituted by two triangles) and when using
481   // the arguments of this method (i.e. [PA] = this and [PB] = second).
482   // The initial stage is the following (we note first=this=[PA] and
483   // second=[PB]) where the Onext() ring order is:
484   //     first, b2, b3, second, b5, bsplice, b7, first...
485   //
486   //                    p       N       A                            //
487   //                   / \      O      / \                           //
488   //                  /   \           /   \                          //
489   //                 /     \    F    /     \     counter-clockwise   //
490   //                /      b2   A  first    \    Onext() ring order  //
491   //               /         \  C  /         \                       //
492   //              /     *     \ E /     *     \                      //
493   //             /             \ /             \                     //
494   //            p-------b3------P------b7-------p                    //
495   //                           /|\                                   //
496   //                          / | \                                  //
497   //          NO FACE        /  |  \      NO FACE                    //
498   //                        /   |   \                                //
499   //                  second   b5   bsplice                          //
500   //                      /  *  |  *  \                              //
501   //                     /      |      \                             //
502   //                    B-------p-------p                            //
503   //
504   // The first stage, implemented as
505   //     second->Oprev()->Splice( bsplice ),
506   // yields the following diagram:
507   //
508   //                    p       N       A                            //
509   //                   / \      O      / \                           //
510   //                  /   \     F     /   \                          //
511   //                 /     \    A    /     \      counter-clockwise  //
512   //                /      b2   C  first    \     Onext() ring order //
513   //               /         \  E  /         \                       //
514   //              /     *     \   /     *     \                      //
515   //             /             \ /             \                     //
516   //            p-------b3------P------b7-------p                    //
517   //                                                                 //
518   //                         NO FACE                                 //
519   //                                                                 //
520   //                           /|\                                   //
521   //                          / | \                                  //
522   //                         /  |  \                                 //
523   //                        /   |   \                                //
524   //                  second   b5   bsplice                          //
525   //                      /  *  |  *  \                              //
526   //                     /      |      \                             //
527   //                    B-------p-------p                            //
528   //
529   // and the second stage, implemented as
530   //      first->Splice( bsplice ),
531   // yields the following diagram:
532   //
533   //                                    A                            //
534   //         B__        NO FACE        / \                           //
535   //         |  \__                   /   \                          //
536   //         |     \__               /     \       counter-          //
537   //         |      second         first    \      clockwise for all //
538   //         |           \__       /         \                       //
539   //         |     *        \__   /     *     \                      //
540   //         |                 \ /             \                     //
541   //         p-------b5---------P------b7-------p                    //
542   //         |               __/|\                                   //
543   //         |     *      __/   | \                                  //
544   //         |           /      |  \      NO FACE                    //
545   //         |     bsplice      |   \                                //
546   //         |   __/           b2    b3                              //
547   //         p__/               |  *  \                              //
548   //                NO FACE     |      \                             //
549   //                            p-------p                            //
550   //
551   Self *first = this;
552 
553   // Making sure point adjacency is correct:
554   if ( first->GetOrigin() != second->GetOrigin() )
555     {
556     itkQEDebugMacro("Edges not adjacent at same point!");
557     return ( false );
558     }
559 
560   if ( first->GetOnext() == second )
561     {
562     return ( true );
563     }
564 
565   if ( first->IsLeftSet() )
566     {
567     itkQEDebugMacro("First should NOT have a left face.");
568     return ( false );
569     }
570 
571   // Second is an internal edge.
572   if ( second->IsInternal() )
573     {
574     return ( false );
575     }
576 
577   Self *bsplice; // Does not require initialisation;
578   // Disconnect the triangles containing second:
579   if ( second->IsLeftSet() )
580     {
581     bsplice = second->GetNextBorderEdgeWithUnsetLeft();
582     second->GetOprev()->Splice(bsplice);
583     }
584   else
585     {
586     // Orientation is localy clockwise:
587     bsplice = second;
588     second->GetOprev()->Splice(bsplice);
589     }
590 
591   // Reconnect second after first:
592   first->Splice(bsplice);
593   return ( true );
594 }
595 
596 // ---------------------------------------------------------------------
597 template< typename TVRef, typename TFRef,
598           typename TPrimalData, typename TDualData, bool PrimalDual >
Disconnect()599 void GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >::Disconnect()
600 {
601   if ( this->IsDisconnected() )
602     {
603     return;
604     }
605 
606   // Update faces if the edge isn't a wire
607   if ( this->IsAtBorder() )
608     {
609     Self *       e = ( this->IsRightSet() ) ? this->GetSym() : this;
610     IteratorGeom it = e->BeginGeomLnext();
611     while ( it != e->EndGeomLnext() )
612       {
613       it.Value()->UnsetLeft();
614       it++;
615       }
616     }
617   else if ( this->IsInternal() )
618     {
619     // Consolidate face
620     DualOriginRefType face = this->GetRight();
621     for ( IteratorGeom it  = this->BeginGeomLnext();
622           it != this->EndGeomLnext();
623           it++ )
624       {
625       it.Value()->SetLeft(face);
626       }
627     }
628 
629   // Hint edges
630   Self *e0 = this->GetOprev();
631   Self *e1 = this->GetLnext();
632 
633   // Disconnect entries
634   if ( !this->IsOriginDisconnected() )
635     {
636     e0->Splice(this);
637     }
638   if ( !this->IsDestinationDisconnected() )
639     {
640     e1->Splice( this->GetSym() );
641     }
642 
643   // Normally, this edge is converted to a simple wire
644   this->UnsetOrigin();
645   this->UnsetDestination();
646   this->UnsetLeft();
647   this->UnsetRight();
648 }
649 
650 // ---------------------------------------------------------------------
651 template< typename TVRef, typename TFRef,
652           typename TPrimalData, typename TDualData, bool PrimalDual >
653 bool
654 GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >
IsOriginSet() const655 ::IsOriginSet() const
656 {
657   return ( this->m_Origin != m_NoPoint );
658 }
659 
660 // ---------------------------------------------------------------------
661 template< typename TVRef, typename TFRef,
662           typename TPrimalData, typename TDualData, bool PrimalDual >
663 bool
664 GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >
IsDestinationSet() const665 ::IsDestinationSet() const
666 {
667   const Self *p1 = this->GetSym();
668 
669   if ( p1 == nullptr )
670     {
671     return false; // FIXME: Is this the right answer ?
672     }
673 
674   return p1->IsOriginSet();
675 }
676 
677 // ---------------------------------------------------------------------
678 template< typename TVRef, typename TFRef,
679           typename TPrimalData, typename TDualData, bool PrimalDual >
680 bool
681 GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >
IsRightSet() const682 ::IsRightSet() const
683 {
684   const DualType *p1 = this->GetRot();
685 
686   if ( p1 == nullptr )
687     {
688     return false;  // FIXME: Is this the right answer ?
689     }
690 
691   return p1->IsOriginSet();
692 }
693 
694 // ---------------------------------------------------------------------
695 template< typename TVRef, typename TFRef,
696           typename TPrimalData, typename TDualData, bool PrimalDual >
697 bool
698 GeometricalQuadEdge< TVRef, TFRef, TPrimalData, TDualData, PrimalDual >
IsLeftSet() const699 ::IsLeftSet() const
700 {
701   const DualType *p1 = this->GetInvRot();
702 
703   if ( p1 == nullptr )
704     {
705     return false;  // FIXME: Is this the right answer ?
706     }
707 
708   return p1->IsOriginSet();
709 }
710 } // end of namespace itk
711 
712 #endif
713