Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/opencascade/Poly_MergeNodesTool.hxx was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // Copyright (c) 2015-2021 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef _Poly_MergeNodesTool_HeaderFile
0015 #define _Poly_MergeNodesTool_HeaderFile
0016 
0017 #include <NCollection_Map.hxx>
0018 #include <Poly_Triangulation.hxx>
0019 #include <Standard_HashUtils.hxx>
0020 
0021 //! Auxiliary tool for merging triangulation nodes for visualization purposes.
0022 //! Tool tries to merge all nodes within input triangulation, but split the ones on sharp corners at
0023 //! specified angle.
0024 class Poly_MergeNodesTool : public Standard_Transient
0025 {
0026   DEFINE_STANDARD_RTTIEXT(Poly_MergeNodesTool, Standard_Transient)
0027 public:
0028   //! Merge nodes of existing mesh and return the new mesh.
0029   //! @param[in] theTris triangulation to add
0030   //! @param[in] theTrsf transformation to apply
0031   //! @param[in] theToReverse reverse triangle nodes order
0032   //! @param[in] theSmoothAngle merge angle in radians
0033   //! @param[in] theMergeTolerance linear merge tolerance
0034   //! @param[in] theToForce return merged triangulation even if it's statistics is equal to input
0035   //! one
0036   //! @return merged triangulation or NULL on no result
0037   Standard_EXPORT static Handle(Poly_Triangulation) MergeNodes(
0038     const Handle(Poly_Triangulation)& theTris,
0039     const gp_Trsf&                    theTrsf,
0040     const Standard_Boolean            theToReverse,
0041     const double                      theSmoothAngle,
0042     const double                      theMergeTolerance = 0.0,
0043     const bool                        theToForce        = true);
0044 
0045 public:
0046   //! Constructor
0047   //! @param[in] theSmoothAngle smooth angle in radians or 0.0 to disable merging by angle
0048   //! @param[in] theMergeTolerance node merging maximum distance
0049   //! @param[in] theNbFacets estimated number of facets for map preallocation
0050   Standard_EXPORT Poly_MergeNodesTool(const double theSmoothAngle,
0051                                       const double theMergeTolerance = 0.0,
0052                                       const int    theNbFacets       = -1);
0053 
0054   //! Return merge tolerance; 0.0 by default (only 3D points with exactly matching coordinates are
0055   //! merged).
0056   double MergeTolerance() const { return myNodeIndexMap.MergeTolerance(); }
0057 
0058   //! Set merge tolerance.
0059   void SetMergeTolerance(double theTolerance) { myNodeIndexMap.SetMergeTolerance(theTolerance); }
0060 
0061   //! Return merge angle in radians; 0.0 by default (normals with non-exact directions are not
0062   //! merged).
0063   double MergeAngle() const { return myNodeIndexMap.MergeAngle(); }
0064 
0065   //! Set merge angle.
0066   void SetMergeAngle(double theAngleRad) { myNodeIndexMap.SetMergeAngle(theAngleRad); }
0067 
0068   //! Return TRUE if nodes with opposite normals should be merged; FALSE by default.
0069   bool ToMergeOpposite() const { return myNodeIndexMap.ToMergeOpposite(); }
0070 
0071   //! Set if nodes with opposite normals should be merged.
0072   void SetMergeOpposite(bool theToMerge) { myNodeIndexMap.SetMergeOpposite(theToMerge); }
0073 
0074   //! Setup unit factor.
0075   void SetUnitFactor(double theUnitFactor) { myUnitFactor = theUnitFactor; }
0076 
0077   //! Return TRUE if degenerate elements should be discarded; TRUE by default.
0078   bool ToDropDegenerative() const { return myToDropDegenerative; }
0079 
0080   //! Set if degenerate elements should be discarded.
0081   void SetDropDegenerative(bool theToDrop) { myToDropDegenerative = theToDrop; }
0082 
0083   //! Return TRUE if equal elements should be filtered; FALSE by default.
0084   bool ToMergeElems() const { return myToMergeElems; }
0085 
0086   //! Set if equal elements should be filtered.
0087   void SetMergeElems(bool theToMerge) { myToMergeElems = theToMerge; }
0088 
0089   //! Compute normal for the mesh element.
0090   NCollection_Vec3<float> computeTriNormal() const
0091   {
0092     const gp_XYZ            aVec01 = myPlaces[1] - myPlaces[0];
0093     const gp_XYZ            aVec02 = myPlaces[2] - myPlaces[0];
0094     const gp_XYZ            aCross = aVec01 ^ aVec02;
0095     NCollection_Vec3<float> aNorm((float)aCross.X(), (float)aCross.Y(), (float)aCross.Z());
0096     return aNorm.Normalized();
0097   }
0098 
0099 public:
0100   //! Add another triangulation to created one.
0101   //! @param[in] theTris triangulation to add
0102   //! @param[in] theTrsf transformation to apply
0103   //! @param[in] theToReverse reverse triangle nodes order
0104   Standard_EXPORT virtual void AddTriangulation(const Handle(Poly_Triangulation)& theTris,
0105                                                 const gp_Trsf&         theTrsf      = gp_Trsf(),
0106                                                 const Standard_Boolean theToReverse = false);
0107 
0108   //! Prepare and return result triangulation (temporary data will be truncated to result size).
0109   Standard_EXPORT Handle(Poly_Triangulation) Result();
0110 
0111 public:
0112   //! Add new triangle.
0113   //! @param[in] theElemNodes 3 element nodes
0114   void AddTriangle(const gp_XYZ theElemNodes[3]) { AddElement(theElemNodes, 3); }
0115 
0116   //! Add new quad.
0117   //! @param[in] theElemNodes 4 element nodes
0118   void AddQuad(const gp_XYZ theElemNodes[4]) { AddElement(theElemNodes, 4); }
0119 
0120   //! Add new triangle or quad.
0121   //! @param[in] theElemNodes element nodes
0122   //! @param[in] theNbNodes number of element nodes, should be 3 or 4
0123   Standard_EXPORT void AddElement(const gp_XYZ* theElemNodes, int theNbNodes);
0124 
0125   //! Change node coordinates of element to be pushed.
0126   //! @param[in] theIndex node index within current element, in 0..3 range
0127   gp_XYZ& ChangeElementNode(int theIndex) { return myPlaces[theIndex]; }
0128 
0129   //! Add new triangle or quad with nodes specified by ChangeElementNode().
0130   Standard_EXPORT void PushLastElement(int theNbNodes);
0131 
0132   //! Add new triangle with nodes specified by ChangeElementNode().
0133   void PushLastTriangle() { PushLastElement(3); }
0134 
0135   //! Add new quad with nodes specified by ChangeElementNode().
0136   void PushLastQuad() { PushLastElement(4); }
0137 
0138   //! Return current element node index defined by PushLastElement().
0139   Standard_Integer ElementNodeIndex(int theIndex) const { return myNodeInds[theIndex]; }
0140 
0141   //! Return number of nodes.
0142   int NbNodes() const { return myNbNodes; }
0143 
0144   //! Return number of elements.
0145   int NbElements() const { return myNbElems; }
0146 
0147   //! Return number of discarded degenerate elements.
0148   int NbDegenerativeElems() const { return myNbDegenElems; }
0149 
0150   //! Return number of merged equal elements.
0151   int NbMergedElems() const { return myNbMergedElems; }
0152 
0153   //! Setup output triangulation for modifications.
0154   //! When set to NULL, the tool could be used as a merge map for filling in external mesh
0155   //! structure.
0156   Handle(Poly_Triangulation)& ChangeOutput() { return myPolyData; }
0157 
0158 private:
0159   //! Push triangle node with normal angle comparison.
0160   void pushNodeCheck(bool& theIsOpposite, const int theTriNode)
0161   {
0162     int                           aNodeIndex = myNbNodes;
0163     const gp_XYZ&                 aPlace     = myPlaces[theTriNode];
0164     const NCollection_Vec3<float> aVec3((float)aPlace.X(), (float)aPlace.Y(), (float)aPlace.Z());
0165     if (myNodeIndexMap.Bind(aNodeIndex, theIsOpposite, aVec3, myTriNormal))
0166     {
0167       ++myNbNodes;
0168       if (!myPolyData.IsNull())
0169       {
0170         if (myPolyData->NbNodes() < myNbNodes)
0171         {
0172           myPolyData->ResizeNodes(myNbNodes * 2, true);
0173         }
0174         myPolyData->SetNode(myNbNodes, aPlace * myUnitFactor);
0175       }
0176     }
0177     myNodeInds[theTriNode] = aNodeIndex;
0178   }
0179 
0180   //! Push triangle node without merging vertices.
0181   inline void pushNodeNoMerge(const int theTriNode)
0182   {
0183     int          aNodeIndex = myNbNodes;
0184     const gp_XYZ aPlace     = myPlaces[theTriNode] * myUnitFactor;
0185 
0186     ++myNbNodes;
0187     if (!myPolyData.IsNull())
0188     {
0189       if (myPolyData->NbNodes() < myNbNodes)
0190       {
0191         myPolyData->ResizeNodes(myNbNodes * 2, true);
0192       }
0193       myPolyData->SetNode(myNbNodes, aPlace);
0194     }
0195 
0196     myNodeInds[theTriNode] = aNodeIndex;
0197   }
0198 
0199 private:
0200   //! Pair holding Vec3 and Normal to the triangle
0201   struct Vec3AndNormal
0202   {
0203     NCollection_Vec3<float> Pos;  //!< position
0204     NCollection_Vec3<float> Norm; //!< normal to the element
0205 
0206     Vec3AndNormal(const NCollection_Vec3<float>& thePos, const NCollection_Vec3<float>& theNorm)
0207         : Pos(thePos),
0208           Norm(theNorm)
0209     {
0210     }
0211   };
0212 
0213   //! Custom map class with key as Node + element normal and value as Node index.
0214   //! NCollection_DataMap is not used, as it requires Hasher to be defined as class template and not
0215   //! class field.
0216   class MergedNodesMap : public NCollection_BaseMap
0217   {
0218   public:
0219     typedef NCollection_Vec3<int64_t> CellVec3i;
0220 
0221   public:
0222     //! Main constructor.
0223     Standard_EXPORT MergedNodesMap(const int theNbBuckets);
0224 
0225     //! Return merge angle in radians;
0226     double MergeAngle() const { return myAngle; }
0227 
0228     //! Set merge angle.
0229     void SetMergeAngle(double theAngleRad)
0230     {
0231       myAngle    = (float)theAngleRad;
0232       myAngleCos = (float)Cos(theAngleRad);
0233     }
0234 
0235     //! Return TRUE if merge angle is non-zero.
0236     //! 0 angle means angles should much without a tolerance.
0237     bool HasMergeAngle() const { return myAngle > 0.0f; }
0238 
0239     //! Return TRUE if merge angle comparison can be skipped (angle is close to 90 degrees).
0240     bool ToMergeAnyAngle() const { return myAngleCos <= 0.01f; }
0241 
0242     //! Return TRUE if nodes with opposite normals should be merged; FALSE by default.
0243     bool ToMergeOpposite() const { return myToMergeOpposite; }
0244 
0245     //! Set if nodes with opposite normals should be merged.
0246     void SetMergeOpposite(bool theToMerge) { myToMergeOpposite = theToMerge; }
0247 
0248     //! Return merge tolerance.
0249     double MergeTolerance() const { return myTolerance; }
0250 
0251     //! Set merge tolerance.
0252     Standard_EXPORT void SetMergeTolerance(double theTolerance);
0253 
0254     //! Return TRUE if merge tolerance is non-zero.
0255     bool HasMergeTolerance() const { return myTolerance > 0.0f; }
0256 
0257     //! Bind node to the map or find existing one.
0258     //! @param theIndex [in,out] index of new key to add, or index of existing key, if already bound
0259     //! @param[out] theIsOpposite  flag indicating that existing (already bound) node has opposite
0260     //! direction
0261     //! @param[in] thePos    node position to add or find
0262     //! @param[in] theNorm   element normal for equality check
0263     //! @return TRUE if node was not bound already
0264     Standard_EXPORT bool Bind(int&                           theIndex,
0265                               bool&                          theIsOpposite,
0266                               const NCollection_Vec3<float>& thePos,
0267                               const NCollection_Vec3<float>& theNorm);
0268 
0269     //! ReSize the map.
0270     Standard_EXPORT void ReSize(const int theSize);
0271 
0272   private:
0273     //! Return cell index for specified 3D point and inverted cell size.
0274     CellVec3i vec3ToCell(const NCollection_Vec3<float>& thePnt) const
0275     {
0276       return CellVec3i(thePnt * myInvTol);
0277     }
0278 
0279     //! Hash code for integer vec3.
0280     Standard_EXPORT static size_t vec3iHashCode(
0281       const Poly_MergeNodesTool::MergedNodesMap::CellVec3i& theVec,
0282       const int                                             theUpper);
0283 
0284     //! Compute hash code.
0285     Standard_EXPORT size_t hashCode(const NCollection_Vec3<float>& thePos,
0286                                     const NCollection_Vec3<float>& theNorm,
0287                                     const int                      theUpper) const;
0288 
0289     //! Compute hash code.
0290     size_t hashCode(const Vec3AndNormal& theKey, const int theUpper) const
0291     {
0292       return hashCode(theKey.Pos, theKey.Norm, theUpper);
0293     }
0294 
0295     //! Compare two vectors with inversed tolerance.
0296     Standard_EXPORT bool vec3AreEqual(const NCollection_Vec3<float>& theKey1,
0297                                       const NCollection_Vec3<float>& theKey2) const;
0298 
0299     //! Compare two nodes.
0300     Standard_EXPORT bool isEqual(const Vec3AndNormal&           theKey1,
0301                                  const NCollection_Vec3<float>& thePos2,
0302                                  const NCollection_Vec3<float>& theNorm2,
0303                                  bool&                          theIsOpposite) const;
0304 
0305   private:
0306     //! Map node.
0307     class DataMapNode;
0308 
0309   private:
0310     float myTolerance;       //!< linear tolerance for comparison
0311     float myInvTol;          //!< inversed linear tolerance for comparison
0312     float myAngle;           //!< angle for comparison
0313     float myAngleCos;        //!< angle cosine for comparison
0314     bool  myToMergeOpposite; //!< merge nodes with opposite normals
0315   };
0316 
0317   //! Hasher for merging equal elements (with pre-sorted indexes).
0318   struct MergedElemHasher
0319   {
0320     size_t operator()(const NCollection_Vec4<int>& theVec) const
0321     {
0322       return opencascade::hashBytes(&theVec[0], 4 * sizeof(int));
0323     }
0324 
0325     bool operator()(const NCollection_Vec4<int>& theKey1,
0326                     const NCollection_Vec4<int>& theKey2) const
0327     {
0328       return theKey1.IsEqual(theKey2);
0329     }
0330   };
0331 
0332 private:
0333   Handle(Poly_Triangulation)                               myPolyData;     //!< output triangulation
0334   MergedNodesMap                                           myNodeIndexMap; //!< map of merged nodes
0335   NCollection_Map<NCollection_Vec4<int>, MergedElemHasher> myElemMap;      //!< map of elements
0336   NCollection_Vec4<int>                                    myNodeInds;  //!< current element indexes
0337   NCollection_Vec3<float>                                  myTriNormal; //!< current triangle normal
0338   gp_XYZ myPlaces[4]; //!< current triangle/quad coordinates to push
0339 
0340   Standard_Real    myUnitFactor;         //!< scale factor to apply
0341   Standard_Integer myNbNodes;            //!< number of output nodes
0342   Standard_Integer myNbElems;            //!< number of output elements
0343   Standard_Integer myNbDegenElems;       //!< number of degenerated elements
0344   Standard_Integer myNbMergedElems;      //!< number of merged elements
0345   Standard_Boolean myToDropDegenerative; //!< flag to filter our degenerate elements
0346   Standard_Boolean myToMergeElems;       //!< flag to merge elements
0347 };
0348 
0349 #endif // _Poly_MergeNodesTool_HeaderFile