/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkGeometricalQuadEdge_h #define itkGeometricalQuadEdge_h #include "itkQuadEdge.h" namespace itk { /** * \class GeometricalQuadEdge * \brief This class extends the QuadEdge by adding a reference to the Origin. * * The class is implemented in such a way that it can generate its own Dual. * In a physical edge, there will be four GeometricalQuadEdge. Two of them will * be Primal and two will be Dual. The Primal ones are parallel to the physical * edge and their origins relate to the mesh points. The Dual ones are * orthogonal to the physical edge and their origins relate to the faces at * each side of the physical edge. * * The only purpose of the last parameter of the template is to guarantee that * the two types GeometricalQuadEdge and GeometricalQuadEdge::Dual * are always different (in the sense that their typeid() are different). If * we only had the four first parameters and assume that * GeometricalQuadEdge gets instantiated with types such that TVRef = * TFRef and TPrimalData = TDualData then this instantiation * GeometricalQuadEdge and GeometricalQuadEdge::Dual would be the * same types (this is simply due to the very definition of * GeometricalQuadEdge::Dual). This would in turn make the types QEType * and QEDual of \ref QuadEdgeMesh identical and would prevent any algorithm * requiring to distinguish those types (e.g. by relying on a * dynamic_cast) to be effective. This justifies the existence of * last dummy template parameter and its default value. * * \author Alexandre Gouaillard, Leonardo Florez-Valencia, Eric Boix * * This implementation was contributed as a paper to the Insight Journal * https://www.insight-journal.org/browse/publication/122 * * \sa QuadEdge * * \ingroup MeshObjects * \ingroup ITKQuadEdgeMesh */ template class ITK_TEMPLATE_EXPORT GeometricalQuadEdge : public QuadEdge { public: /** Hierarchy type alias. */ using Self = GeometricalQuadEdge; using Superclass = QuadEdge; using RawPointer = Self *; /** * Dual type, basically the same type with swapped template * parameters. * */ using DualType = GeometricalQuadEdge; /** Input template parameters & values convenient renaming. */ using OriginRefType = TVRef; using DualOriginRefType = TFRef; using PrimalDataType = TPrimalData; using DualDataType = TDualData; // Line Cell Id in Mesh Cell Container // used to go up to LineCell level using LineCellIdentifier = TFRef; public: /** Iterator types. */ using IteratorGeom = QuadEdgeMeshIteratorGeom; using ConstIteratorGeom = QuadEdgeMeshConstIteratorGeom; /** Basic iterators methods. */ inline itkQEDefineIteratorGeomMethodsMacro(Onext); inline itkQEDefineIteratorGeomMethodsMacro(Sym); inline itkQEDefineIteratorGeomMethodsMacro(Lnext); inline itkQEDefineIteratorGeomMethodsMacro(Rnext); inline itkQEDefineIteratorGeomMethodsMacro(Dnext); inline itkQEDefineIteratorGeomMethodsMacro(Oprev); inline itkQEDefineIteratorGeomMethodsMacro(Lprev); inline itkQEDefineIteratorGeomMethodsMacro(Rprev); inline itkQEDefineIteratorGeomMethodsMacro(Dprev); inline itkQEDefineIteratorGeomMethodsMacro(InvOnext); inline itkQEDefineIteratorGeomMethodsMacro(InvLnext); inline itkQEDefineIteratorGeomMethodsMacro(InvRnext); inline itkQEDefineIteratorGeomMethodsMacro(InvDnext); /** QE macros. */ itkQEAccessorsMacro(Superclass, Self, DualType); public: GeometricalQuadEdge(); GeometricalQuadEdge(const GeometricalQuadEdge &) = default; GeometricalQuadEdge(GeometricalQuadEdge &&) = default; GeometricalQuadEdge & operator=(const GeometricalQuadEdge &) = default; GeometricalQuadEdge & operator=(GeometricalQuadEdge &&) = default; ~GeometricalQuadEdge() override = default; /** Set methods. */ inline void SetOrigin(const OriginRefType v) { m_Origin = v; } inline void SetDestination(const OriginRefType v) { this->GetSym()->SetOrigin(v); } inline void SetRight(const DualOriginRefType v) { this->GetRot()->SetOrigin(v); } inline void SetLeft(const DualOriginRefType v) { this->GetInvRot()->SetOrigin(v); } /** * Set the Left() of all the edges in the Lnext() ring of "this" * with the same given geometrical information. * @param faceGeom Looks at most maxSize edges in the Lnext() ring. * @param maxSize Sets at most maxSize edges in the Lnext() ring. * @return Returns true on success. False otherwise. */ bool SetLnextRingWithSameLeftFace(const DualOriginRefType faceGeom, int maxSize = 100); inline void UnsetOrigin() { m_Origin = m_NoPoint; } inline void UnsetDestination() { this->GetSym()->UnsetOrigin(); } inline void UnsetRight() { this->GetRot()->UnsetOrigin(); } inline void UnsetLeft() { this->GetInvRot()->UnsetOrigin(); } /** Get methods. */ // ORIENTATION_NOTE: this definition of GetLeft (or GetRight) // implicitly assumes that the Onext order is counter-clockwise ! inline const OriginRefType GetOrigin() const { return (m_Origin); } inline const OriginRefType GetDestination() const { return (GetSym()->GetOrigin()); } inline const DualOriginRefType GetRight() const { return (GetRot()->GetOrigin()); } inline const DualOriginRefType GetLeft() const { return (GetInvRot()->GetOrigin()); } /** Boolean accessors. */ bool IsOriginSet() const; bool IsDestinationSet() const; bool IsRightSet() const; bool IsLeftSet() const; /** Extra data set methods. */ inline void SetPrimalData(const PrimalDataType data) { m_Data = data; this->SetPrimalData(); } inline void SetDualData(const DualDataType data) { this->GetRot()->SetPrimalData(data); } inline void SetPrimalData() { m_DataSet = true; } inline void SetDualData() { this->GetRot()->SetPrimalData(); } inline void UnsetPrimalData() { m_Data = false; } inline void UnsetDualData() { this->GetRot()->UnsetPrimalData(); } /** Extra data get methods. */ inline PrimalDataType GetPrimalData() { return (m_Data); } inline DualDataType GetDualData() { return (this->GetRot()->GetPrimalData()); } /** Boolean accessors. */ inline bool IsPrimalDataSet() { return (m_DataSet); } inline bool IsDualDataSet() { return (this->GetRot()->IsPrimalDataSet()); } /** * @return Returns true when "this" has no faces set on both sides. * Return false otherwise. */ inline bool IsWire() { return (!(this->IsLeftSet()) && !(this->IsRightSet())); } /** * @return Returns true when "this" is on the boundary i.e. * one and only one of the faces is set. Return false * otherwise. */ inline bool IsAtBorder() { return ((this->IsLeftSet() && !this->IsRightSet()) || (!this->IsLeftSet() && this->IsRightSet())); } /** * @return Returns true when "this" has faces set on both sides. * Return false otherwise. */ inline bool IsInternal() const { return (this->IsLeftSet() && this->IsRightSet()); } bool IsOriginInternal() const; bool IsLnextSharingSameFace(int maxSize = 100); bool IsLnextOfTriangle(); bool IsInOnextRing(Self *); bool IsInLnextRing(Self *); Self * GetNextBorderEdgeWithUnsetLeft(Self * edgeTest = nullptr); bool InsertAfterNextBorderEdgeWithUnsetLeft(Self * isol, Self * hint = nullptr); bool ReorderOnextRingBeforeAddFace(Self * second); /** Disconnection methods. */ inline bool IsOriginDisconnected() { return (this == this->GetOnext()); } inline bool IsDestinationDisconnected() { return (this->GetSym()->IsOriginDisconnected()); } inline bool IsDisconnected() { return (this->IsOriginDisconnected() && this->IsDestinationDisconnected()); } void Disconnect(); inline void SetIdent(const LineCellIdentifier & User_Value) { this->m_LineCellIdent = User_Value; } inline LineCellIdentifier GetIdent() { return (this->m_LineCellIdent); } public: // Reserved OriginRefType designated to represent the absence of Origin static const OriginRefType m_NoPoint; protected: OriginRefType m_Origin{}; // Geometrical information PrimalDataType m_Data{}; // User data associated to this edge. bool m_DataSet{ false }; // Indicates if the data is set. LineCellIdentifier m_LineCellIdent{}; }; } // namespace itk #ifndef ITK_MANUAL_INSTANTIATION # include "itkGeometricalQuadEdge.hxx" #endif #endif