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_h
19 #define itkGeometricalQuadEdge_h
20 
21 #include "itkQuadEdge.h"
22 
23 namespace itk
24 {
25 /** \class GeometricalQuadEdge
26  * \brief This class extends the QuadEdge by adding a reference to the Origin.
27  *
28  * The class is implemented in such a way that it can generate its own Dual.
29  * In a physical edge, there will be four GeometricalQuadEdge. Two of them will
30  * be Primal and two will be Dual. The Primal ones are parallel to the physical
31  * edge and their origins relate to the mesh points. The Dual ones are
32  * orthogonal to the physical edge and their origins relate to the faces at
33  * each side of the physical edge.
34  *
35  * The only purpose of the last paramater of the template is to guarantee that
36  * the two types GeometricalQuadEdge and GeometricalQuadEdge::Dual
37  * are always different (in the sense that their typeid() are different). If
38  * we only had the four first parameters and assume that
39  * GeometricalQuadEdge gets instantiated with types such that TVRef =
40  * TFRef and TPrimalData = TDualData then this instantiation
41  * GeometricalQuadEdge and GeometricalQuadEdge::Dual would be the
42  * same types (this is simply due to the very definition of
43  * GeometricalQuadEdge::Dual). This would in turn make the types QEType
44  * and QEDual of \ref QuadEdgeMesh identical and would prevent any algorithm
45  * requiring to distinguish those types (e.g. by relying on a
46  * dynamic_cast<QEType*>) to be effective.  This justifies the existence of
47  * last dummy template parameter and it's default value.
48  *
49  * \author Alexandre Gouaillard, Leonardo Florez-Valencia, Eric Boix
50  *
51  * This implementation was contributed as a paper to the Insight Journal
52  * https://hdl.handle.net/1926/306
53  *
54  * \sa QuadEdge
55  *
56  * \ingroup MeshObjects
57  * \ingroup ITKQuadEdgeMesh
58  */
59 template< typename TVRef,  typename TFRef,
60           typename TPrimalData, typename TDualData,
61           bool PrimalDual = true >
62 class ITK_TEMPLATE_EXPORT GeometricalQuadEdge:public QuadEdge
63 {
64 public:
65   /** Hierarchy type alias. */
66   using Self = GeometricalQuadEdge;
67   using Superclass = QuadEdge;
68   using RawPointer = Self *;
69 
70   /**
71    * Dual type, basically the same type with swapped template
72    * parameters.
73    *
74    */
75   using DualType = GeometricalQuadEdge< TFRef, TVRef,
76                                TDualData, TPrimalData, !PrimalDual >;
77 
78   /** Input template parameters & values convenient renaming. */
79   using OriginRefType = TVRef;
80   using DualOriginRefType = TFRef;
81   using PrimalDataType = TPrimalData;
82   using DualDataType = TDualData;
83   // Line Cell Id in Mesh Cell Container
84   // used to go up to LineCell level
85   using LineCellIdentifier = TFRef;
86 
87 public:
88 
89   /** Iterator types. */
90   using IteratorGeom = QuadEdgeMeshIteratorGeom< Self >;
91   using ConstIteratorGeom = QuadEdgeMeshConstIteratorGeom< Self >;
92 
93   /** Basic iterators methods. */
94   inline itkQEDefineIteratorGeomMethodsMacro(Onext);
95   inline itkQEDefineIteratorGeomMethodsMacro(Sym);
96   inline itkQEDefineIteratorGeomMethodsMacro(Lnext);
97   inline itkQEDefineIteratorGeomMethodsMacro(Rnext);
98   inline itkQEDefineIteratorGeomMethodsMacro(Dnext);
99   inline itkQEDefineIteratorGeomMethodsMacro(Oprev);
100   inline itkQEDefineIteratorGeomMethodsMacro(Lprev);
101   inline itkQEDefineIteratorGeomMethodsMacro(Rprev);
102   inline itkQEDefineIteratorGeomMethodsMacro(Dprev);
103   inline itkQEDefineIteratorGeomMethodsMacro(InvOnext);
104   inline itkQEDefineIteratorGeomMethodsMacro(InvLnext);
105   inline itkQEDefineIteratorGeomMethodsMacro(InvRnext);
106   inline itkQEDefineIteratorGeomMethodsMacro(InvDnext);
107 
108   /** QE macros. */
109   itkQEAccessorsMacro(Superclass, Self, DualType);
110 
111 public:
112   GeometricalQuadEdge();
113   GeometricalQuadEdge(const GeometricalQuadEdge &) = default;
114   GeometricalQuadEdge(GeometricalQuadEdge &&) = default;
115   GeometricalQuadEdge & operator=(const GeometricalQuadEdge &) = default;
116   GeometricalQuadEdge & operator=(GeometricalQuadEdge &&) = default;
117   virtual ~GeometricalQuadEdge() override = default;
118 
119   /** Set methods. */
SetOrigin(const OriginRefType v)120   inline void SetOrigin(const OriginRefType v)
121   { m_Origin = v; }
122 
SetDestination(const OriginRefType v)123   inline void SetDestination(const OriginRefType v)
124   { this->GetSym()->SetOrigin(v); }
125 
SetRight(const DualOriginRefType v)126   inline void SetRight(const DualOriginRefType v)
127   { this->GetRot()->SetOrigin(v); }
128 
SetLeft(const DualOriginRefType v)129   inline void SetLeft(const DualOriginRefType v)
130   { this->GetInvRot()->SetOrigin(v); }
131 
132   /**
133    * Set the Left() of all the edges in the Lnext() ring of "this"
134    * with the same given geometrical information.
135    * @param  faceGeom Looks at most maxSize edges in the Lnext() ring.
136    * @param  maxSize Sets at most maxSize edges in the Lnext() ring.
137    * @return Returns true on success. False otherwise.
138    */
139   bool SetLnextRingWithSameLeftFace(const DualOriginRefType faceGeom,
140                                     int maxSize = 100);
141 
UnsetOrigin()142   inline void UnsetOrigin()   { m_Origin = m_NoPoint; }
UnsetDestination()143   inline void UnsetDestination()  { this->GetSym()->UnsetOrigin(); }
UnsetRight()144   inline void UnsetRight() { this->GetRot()->UnsetOrigin(); }
UnsetLeft()145   inline void UnsetLeft()  { this->GetInvRot()->UnsetOrigin(); }
146 
147   /** Get methods. */
148   //ORIENTATION_NOTE: this definition of GetLeft (or GetRight)
149   // implicitely assumes that the Onext order is counter-clockwise !
GetOrigin()150   inline const OriginRefType GetOrigin() const { return ( m_Origin ); }
GetDestination()151   inline const OriginRefType GetDestination()  const { return ( GetSym()->GetOrigin() ); }
GetRight()152   inline const DualOriginRefType GetRight() const { return ( GetRot()->GetOrigin() ); }
GetLeft()153   inline const DualOriginRefType GetLeft() const { return ( GetInvRot()->GetOrigin() ); }
154 
155   /** Boolean accessors. */
156   bool IsOriginSet() const;
157 
158   bool IsDestinationSet() const;
159 
160   bool IsRightSet() const;
161 
162   bool IsLeftSet() const;
163 
164   /** Extra data set methods. */
SetPrimalData(const PrimalDataType data)165   inline void SetPrimalData(const PrimalDataType data)
166   { m_Data = data; this->SetPrimalData(); }
SetDualData(const DualDataType data)167   inline void SetDualData(const DualDataType data)
168   { this->GetRot()->SetPrimalData(data); }
169 
SetPrimalData()170   inline void SetPrimalData() { m_DataSet = true; }
SetDualData()171   inline void SetDualData()   { this->GetRot()->SetPrimalData(); }
172 
UnsetPrimalData()173   inline void UnsetPrimalData() { m_Data = false; }
UnsetDualData()174   inline void UnsetDualData()   { this->GetRot()->UnsetPrimalData(); }
175 
176   /** Extra data get methods. */
GetPrimalData()177   inline PrimalDataType GetPrimalData() { return ( m_Data ); }
GetDualData()178   inline DualDataType   GetDualData()
179   { return ( this->GetRot()->GetPrimalData() ); }
180 
181   /** Boolean accessors. */
IsPrimalDataSet()182   inline bool IsPrimalDataSet() { return ( m_DataSet ); }
IsDualDataSet()183   inline bool IsDualDataSet()
184   { return ( this->GetRot()->IsPrimalDataSet() ); }
185 
186   /**
187    * @return Returns true when "this" has no faces set on both sides.
188    *         Return false otherwise.
189    */
IsWire()190   inline bool IsWire()
191   { return ( !( this->IsLeftSet() ) && !( this->IsRightSet() ) ); }
192 
193   /**
194    * @return Returns true when "this" is on the boundary i.e.
195    *         one and only one of the faces is set. Return false
196    *         otherwise.
197    */
IsAtBorder()198   inline bool IsAtBorder()
199   {
200     return ( ( this->IsLeftSet() && !this->IsRightSet() )
201              || ( !this->IsLeftSet() && this->IsRightSet() ) );
202   }
203 
204   /**
205    * @return Returns true when "this" has faces set on both sides.
206    *         Return false otherwise.
207    */
IsInternal()208   inline bool IsInternal() const
209   { return ( this->IsLeftSet() && this->IsRightSet() ); }
210 
211   bool IsOriginInternal() const;
212 
213   bool IsLnextSharingSameFace(int maxSize = 100);
214 
215   bool IsLnextOfTriangle();
216 
217   bool IsInOnextRing(Self *);
218 
219   bool IsInLnextRing(Self *);
220 
221   Self * GetNextBorderEdgeWithUnsetLeft(Self *edgeTest = nullptr);
222 
223   bool InsertAfterNextBorderEdgeWithUnsetLeft(Self *isol,
224                                               Self *hint = nullptr);
225 
226   bool ReorderOnextRingBeforeAddFace(Self *second);
227 
228   /** Disconnection methods. */
IsOriginDisconnected()229   inline bool IsOriginDisconnected()
230   { return ( this == this->GetOnext() ); }
IsDestinationDisconnected()231   inline bool IsDestinationDisconnected()
232   { return ( this->GetSym()->IsOriginDisconnected() ); }
IsDisconnected()233   inline bool IsDisconnected()
234   {
235     return ( this->IsOriginDisconnected()
236              && this->IsDestinationDisconnected() );
237   }
238 
239   void Disconnect();
240 
SetIdent(const LineCellIdentifier & User_Value)241   inline void SetIdent(const LineCellIdentifier & User_Value) { this->m_LineCellIdent = User_Value; }
GetIdent()242   inline LineCellIdentifier GetIdent() { return ( this->m_LineCellIdent ); }
243 
244 public:
245   // Reserved OriginRefType designated to represent the absence of Origin
246   static const OriginRefType m_NoPoint;
247 
248 protected:
249   OriginRefType      m_Origin;    // Geometrical information
250   PrimalDataType     m_Data;      // User data associated to this edge.
251   bool               m_DataSet{false};   // Indicates if the data is set.
252   LineCellIdentifier m_LineCellIdent;
253 };
254 }
255 
256 #ifndef ITK_MANUAL_INSTANTIATION
257 #include "itkGeometricalQuadEdge.hxx"
258 #endif
259 
260 #endif
261