OpenCascade中读取STL文件的相同节点合并器(源码分析)

OpenCascade中读取STL文件的相同节点合并器(源码分析)

一、概述

STL文件的格式是没有节点索引的,是以数值来表示节点的,这就导致如果读入的时候不做去重的话,读取后节点会出现重复的情况,不仅浪费内存,而且可能在运行某些算法的时候出现惊人的错误。

STL的面片格式如下

facet normal  5.223066e-02 -1.736872e-01  9.834148e-01
   outer loop
     vertex  3.002048e+02  9.027633e+01  1.639474e+02
     vertex  2.440949e+02  8.656459e+01  1.662719e+02
     vertex  2.513544e+02  6.242381e+01  1.616227e+02
   endloop
 endfacet

二、代码分析

OpenCascade中的RWStl_Reader.cxx实现了对STL文件的读取,并且做到了去掉重复的点,让我们看一下源码
Class MergeNodeTool用于合并相同的点
首先分析一下MergeNodeTool的父类Poly_MergeNodesTool

构造函数:
public:
//! @param[in] theSmoothAngle smooth angle in radians or 0.0 to disable merging by angle
  //! @param[in] theMergeTolerance node merging maximum distance
  //! @param[in] theNbFacets estimated number of facets for map preallocation
  Standard_EXPORT Poly_MergeNodesTool (const double theSmoothAngle,
                                       const double theMergeTolerance = 0.0,
                                       const int    theNbFacets = -1);
类成员定义:
private:

  Handle(Poly_Triangulation) myPolyData;           //!< output triangulation
  MergedNodesMap             myNodeIndexMap;       //!< map of merged nodes
  NCollection_Map<NCollection_Vec4<int>, MergedElemHasher>
                             myElemMap;            //!< map of elements
  NCollection_Vec4<int>      myNodeInds;           //!< current element indexes
  NCollection_Vec3<float>    myTriNormal;          //!< current triangle normal
  gp_XYZ                     myPlaces[4];          //!< current triangle/quad coordinates to push

  Standard_Real              myUnitFactor;         //!< scale factor to apply
  Standard_Integer           myNbNodes;            //!< number of output nodes
  Standard_Integer           myNbElems;            //!< number of output elements
  Standard_Integer           myNbDegenElems;       //!< number of degenerated elements
  Standard_Integer           myNbMergedElems;      //!< number of merged elements
  Standard_Boolean           myToDropDegenerative; //!< flag to filter our degenerate elements
  Standard_Boolean           myToMergeElems;       //!< flag to merge elements

1、如何判断为相同的节点

在vec3AreEqual中使用两种评判标准,如果myInvTol <= 0 则不启用可容忍的误差来判断两点是否相等,仅当点完全一致时为相同顶点,另一种就是加入了可以容忍的误差,当点足够近的时候,也判断为相同的节点(注:代码中的myInvTol = 1.0/可容忍的误差值,避免因为太小而被判断为 == 0.0 导致没有加入可容忍的误差值)

// =======================================================================
inline bool Poly_MergeNodesTool::MergedNodesMap::vec3AreEqual (const NCollection_Vec3<float>& theKey1,
                                                               const NCollection_Vec3<float>& theKey2) const
{
   
  if (myInvTol <= 0.0f)
  {
   
   //! 如果myInvTol <= 0 则不启用可容忍的误差来判断两点是否相等,仅当点完全一致时为相同.
   //bool IsEqual (const NCollection_Vec3& theOther) const
   //{
   
   //return v[0] == theOther.v[0]
        //&& v[1] == theOther.v[1]
        //&& v[2] == theOther.v[2];
   //}
    //调用了NCollection中的IsEqual方法 对比每一个值来判断是否相等
    return theKey1.IsEqual (theKey2);
   }
  /// tolerance should be smaller than triangle size to avoid artifacts
  //const CellVec3i anIndex1 = vec3ToCell (theKey1);
  //const CellVec3i anIndex2 = vec3ToCell (theKey2);
  //return anIndex1.IsEqual (anIndex2);
  float aVal = theKey1.x() - theKey2.x();
  if (aVal < 0) {
    aVal = -aVal; }
  if (aVal > myTolerance) {
    return false; }
  aVal = theKey1.y() - theKey2.y();
  if (aVal < 0) {
    aVal = -aVal; }
  if (aVal > myTolerance) {
    return false; }
  aVal = theKey1.z() - theKey2.z();
  if (aVal < 0) {
    aVal = -aVal; }
  if (aVal > myTolerance) {
    return false; }
  return true;
}

isEqual方法先是调用了之前点是否相等,其次是对两个点的法向量进行了点乘,由于都是单位向量,点乘的结果等于两个法向量夹角的余弦值,如果结果大于我们设定的cos值时,则说明时同一个顶点,应该合并。
当aCosinus <= -myAngleCos时,如果设定了myToMergeOpposite = true(允许合并具有相反方向法线的节点) 则合并。
(注:这玩意在等会的插入三角形的时候会用到,如果节点判断已经出现过了,则会直接返回id,而不会新增一个节点的id)

// =======================================================================
// function : MergedNodesMap::isEqual
// purpose  :
// =======================================================================
inline bool Poly_MergeNodesTool::MergedNodesMap::isEqual (const Vec3AndNormal& theKey1,
                                                          const NCollection_Vec3<float>& thePos2,
                                                          const NCollection_Vec3<float>& theNorm2,
                                                          bool& theIsOpposite) const
{
   
  if (!vec3AreEqual (theKey1.Pos, thePos2))
  {
   
    return false;
  }

  const float aCosinus = theKey1.Norm.Dot (theNorm2);
  if (aCosinus >= myAngleCos)
  {
   
    //theIsOpposite = false;
    return true;
  }
  else if (myToMergeOpposite
        && aCosinus <= 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值