/*************************************************************************** * Copyright (c) 2005 Imetric 3D GmbH * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #ifndef MESH_GRID_H #define MESH_GRID_H #include #include "MeshKernel.h" #include #include #define MESH_CT_GRID 256 // Default value for number of elements per grid #define MESH_MAX_GRIDS 100000 // Default value for maximum number of grids #define MESH_CT_GRID_PER_AXIS 20 namespace MeshCore { class MeshKernel; class MeshGeomFacet; class MeshGrid; //#define MESHGRID_BBOX_EXTENSION 1.0e-3f #define MESHGRID_BBOX_EXTENSION 10.0f /** * The MeshGrid allows to divide a global mesh object into smaller regions * of elements (e.g. facets, points or edges) depending on the resolution * of the grid. All grid elements in the grid structure have the same size. * * Grids can be used within algorithms to avoid to iterate through all elements, * so grids can speed up algorithms dramatically. */ class MeshExport MeshGrid { protected: /** @name Construction */ //@{ /// Construction MeshGrid (const MeshKernel &rclM); /// Construction MeshGrid (void); //@} public: /// Destruction virtual ~MeshGrid (void) { } public: /** Attaches the mesh kernel to this grid, an already attached mesh gets detached. The grid gets rebuilt * automatically. */ virtual void Attach (const MeshKernel &rclM); /** Rebuilds the grid structure. */ virtual void Rebuild (unsigned long ulPerGrid = MESH_CT_GRID, unsigned long ulMaxGrid = MESH_MAX_GRIDS); /** Rebuilds the grid structure. */ virtual void Rebuild (int iCtGridPerAxis = MESH_CT_GRID_PER_AXIS); /** Rebuilds the grid structure. */ virtual void Rebuild (unsigned long ulX, unsigned long ulY, unsigned long ulZ); /** @name Search */ //@{ /** Searches for elements lying in the intersection area of the grid and the bounding box. */ virtual unsigned long Inside (const Base::BoundBox3f &rclBB, std::vector &raulElements, bool bDelDoubles = true) const; /** Searches for elements lying in the intersection area of the grid and the bounding box. */ virtual unsigned long Inside (const Base::BoundBox3f &rclBB, std::set &raulElementss) const; /** Searches for elements lying in the intersection area of the grid and the bounding box. */ virtual unsigned long Inside (const Base::BoundBox3f &rclBB, std::vector &raulElements, const Base::Vector3f &rclOrg, float fMaxDist, bool bDelDoubles = true) const; /** Searches for the nearest grids that contain elements from a point, the result are grid indices. */ void SearchNearestFromPoint (const Base::Vector3f &rclPt, std::set &rclInd) const; //@} /** @name Getters */ //@{ /** Returns the indices of the elements in the given grid. */ unsigned long GetElements (unsigned long ulX, unsigned long ulY, unsigned long ulZ, std::set &raclInd) const; unsigned long GetElements (const Base::Vector3f &rclPoint, std::vector& aulFacets) const; //@} /** Returns the lengths of the grid elements in x,y and z direction. */ virtual void GetGridLengths (float &rfLenX, float &rfLenY, float &rfLenZ) const { rfLenX = _fGridLenX; rfLenY = _fGridLenY; rfLenZ = _fGridLenZ; } /** Returns the number of grid elements in x,y and z direction. */ virtual void GetCtGrids (unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const { rulX = _ulCtGridsX; rulY = _ulCtGridsY; rulZ = _ulCtGridsZ; } /** @name Boundings */ //@{ /** Returns the bounding box of a given grid element. */ inline Base::BoundBox3f GetBoundBox (unsigned long ulX, unsigned long ulY, unsigned long ulZ) const; /** Returns the bounding box of the whole. */ inline Base::BoundBox3f GetBoundBox (void) const; /** Returns an extended bounding box of the mesh object. */ inline Base::BoundBox3f GetMeshBoundBox (void) const; //@} /** Returns an index for the given grid position. If the specified triple is not a valid grid position ULONG_MAX is returned. * If the index is valid than its value is between zero and the number of grid elements. For each different grid position * a different index is returned. */ unsigned long GetIndexToPosition(unsigned long ulX, unsigned long ulY, unsigned long ulZ) const; /** Returns the grid position to the given index. If the index is equal to or higher than the number of grid elements false is returned * and the triple is set to ULONG_MAX. */ bool GetPositionToIndex(unsigned long id, unsigned long& ulX, unsigned long& ulY, unsigned long& ulZ) const; /** Returns the number of elements in a given grid. */ unsigned long GetCtElements(unsigned long ulX, unsigned long ulY, unsigned long ulZ) const { return _aulGrid[ulX][ulY][ulZ].size(); } /** Validates the grid structure and rebuilds it if needed. Must be implemented in sub-classes. */ virtual void Validate (const MeshKernel &rclM) = 0; /** Verifies the grid structure and returns false if inconsistencies are found. */ virtual bool Verify() const = 0; /** Checks whether the point is inside the grid. In case it is inside true is returned with the grid position, * otherwise false is returned and the grid position is undefined. */ bool CheckPosition (const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const; /** Returns the indices of the grid this point lies in. If the point is outside the grid the indices of * the nearest grid element are taken.*/ virtual void Position (const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const; /** Checks if this is a valid grid position. */ inline bool CheckPos (unsigned long ulX, unsigned long ulY, unsigned long ulZ) const; /** Get the indices of all elements lying in the grids around a given grid with distance \a ulDistance. */ void GetHull (unsigned long ulX, unsigned long ulY, unsigned long ulZ, unsigned long ulDistance, std::set &raclInd) const; protected: /** Initializes the size of the internal structure. */ virtual void InitGrid (void); /** Deletes the grid structure. */ virtual void Clear (void); /** Calculates the grid length dependent on maximum number of grids. */ virtual void CalculateGridLength (unsigned long ulCtGrid, unsigned long ulMaxGrids); /** Calculates the grid length dependent on the number of grids per axis. */ virtual void CalculateGridLength (int iCtGridPerAxis); /** Rebuilds the grid structure. Must be implemented in sub-classes. */ virtual void RebuildGrid (void) = 0; /** Returns the number of stored elements. Must be implemented in sub-classes. */ virtual unsigned long HasElements (void) const = 0; protected: std::vector > > > _aulGrid; /**< Grid data structure. */ const MeshKernel* _pclMesh; /**< The mesh kernel. */ unsigned long _ulCtElements;/**< Number of grid elements for validation issues. */ unsigned long _ulCtGridsX; /**< Number of grid elements in z. */ unsigned long _ulCtGridsY; /**< Number of grid elements in z. */ unsigned long _ulCtGridsZ; /**< Number of grid elements in z. */ float _fGridLenX; /**< Length of grid elements in x. */ float _fGridLenY; /**< Length of grid elements in y. */ float _fGridLenZ; /**< Length of grid elements in z. */ float _fMinX; /**< Grid null position in x. */ float _fMinY; /**< Grid null position in y. */ float _fMinZ; /**< Grid null position in z. */ // friends friend class MeshGridIterator; }; /** * Special grid class that stores facet indices of the mesh object * in its grids. */ class MeshExport MeshFacetGrid: public MeshGrid { public: /** @name Construction */ //@{ /// Construction MeshFacetGrid (const MeshKernel &rclM); /// Construction MeshFacetGrid (void) : MeshGrid() { } /// Construction MeshFacetGrid (const MeshKernel &rclM, unsigned long ulX, unsigned long ulY, unsigned long ulZ); /// Construction MeshFacetGrid (const MeshKernel &rclM, int iCtGridPerAxis); /// Construction MeshFacetGrid (const MeshKernel &rclM, float fGridLen); /// Destruction virtual ~MeshFacetGrid (void) { } //@} /** @name Search */ //@{ /** Searches for the nearest facet from a point. */ unsigned long SearchNearestFromPoint (const Base::Vector3f &rclPt) const; /** Searches for the nearest facet from a point with the maximum search area. */ unsigned long SearchNearestFromPoint (const Base::Vector3f &rclPt, float fMaxSearchArea) const; /** Searches for the nearest facet in a given grid element and returns the facet index and the actual distance. */ void SearchNearestFacetInGrid(unsigned long ulX, unsigned long ulY, unsigned long ulZ, const Base::Vector3f &rclPt, float &rfMinDist, unsigned long &rulFacetInd) const; /** Does basically the same as the method above unless that grid neighbours up to the order of \a ulDistance * are introduced into the search. */ void SearchNearestFacetInHull (unsigned long ulX, unsigned long ulY, unsigned long ulZ, unsigned long ulDistance, const Base::Vector3f &rclPt, unsigned long &rulFacetInd, float &rfMinDist) const; //@} /** Validates the grid structure and rebuilds it if needed. */ virtual void Validate (const MeshKernel &rclM); /** Validates the grid structure and rebuilds it if needed. */ virtual void Validate (void); /** Verifies the grid structure and returns false if inconsistencies are found. */ virtual bool Verify() const; protected: /** Returns the grid numbers to the given point \a rclPoint. */ inline void Pos (const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const; /** Returns the grid numbers to the given point \a rclPoint. */ inline void PosWithCheck (const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const; /** Adds a new facet element to the grid structure. \a rclFacet is the geometric facet and \a ulFacetIndex * the corresponding index in the mesh kernel. The facet is added to each grid element that intersects * the facet. */ inline void AddFacet (const MeshGeomFacet &rclFacet, unsigned long ulFacetIndex, float fEpsilon = 0.0f); /** Returns the number of stored elements. */ unsigned long HasElements (void) const { return _pclMesh->CountFacets(); } /** Rebuilds the grid structure. */ virtual void RebuildGrid (void); }; /** * Special grid class that stores point indices of the mesh object * in its grids. */ class MeshExport MeshPointGrid: public MeshGrid { public: /** @name Construction */ //@{ /// Construction MeshPointGrid (void); /// Construction MeshPointGrid (const MeshKernel &rclM); /// Construction MeshPointGrid (const MeshKernel &rclM, int iCtGridPerAxis); /// Construction MeshPointGrid (const MeshKernel &rclM, float fGridLen); /// Construction MeshPointGrid (const MeshKernel &rclM, unsigned long ulX, unsigned long ulY, unsigned long ulZ); /// Destruction virtual ~MeshPointGrid (void) {} //@} /** Finds all points that lie in the same grid as the point \a rclPoint. */ unsigned long FindElements(const Base::Vector3f &rclPoint, std::set& aulElements) const; /** Validates the grid structure and rebuilds it if needed. */ virtual void Validate (const MeshKernel &rclM); /** Validates the grid structure and rebuilds it if needed. */ virtual void Validate (void); /** Verifies the grid structure and returns false if inconsistencies are found. */ virtual bool Verify() const; protected: /** Adds a new point element to the grid structure. \a rclPt is the geometric point and \a ulPtIndex * the corresponding index in the mesh kernel. */ void AddPoint (const MeshPoint &rclPt, unsigned long ulPtIndex, float fEpsilon = 0.0f); /** Returns the grid numbers to the given point \a rclPoint. */ void Pos(const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const; /** Returns the number of stored elements. */ unsigned long HasElements (void) const { return _pclMesh->CountPoints(); } /** Rebuilds the grid structure. */ virtual void RebuildGrid (void); }; /** * The MeshGridIterator class provides an interface to walk through * all grid elements of a mesh grid. */ class MeshExport MeshGridIterator { public: /// Construction MeshGridIterator (const MeshGrid &rclG); /** Returns the bounding box of the current grid element. */ Base::BoundBox3f GetBoundBox (void) const { return _rclGrid.GetBoundBox(_ulX, _ulY, _ulZ); } /** Returns indices of the elements in the current grid. */ void GetElements (std::vector &raulElements) const { raulElements.insert(raulElements.end(), _rclGrid._aulGrid[_ulX][_ulY][_ulZ].begin(), _rclGrid._aulGrid[_ulX][_ulY][_ulZ].end()); } /** Returns the number of elements in the current grid. */ unsigned long GetCtElements() const { return _rclGrid.GetCtElements(_ulX, _ulY, _ulZ); } /** @name Iteration */ //@{ /** Sets the iterator to the first element*/ void Init (void) { _ulX = _ulY = _ulZ = 0; } /** Checks if the iterator has not yet reached the end position. */ bool More (void) const { return (_ulZ < _rclGrid._ulCtGridsZ); } /** Go to the next grid. */ void Next (void) { if (++_ulX >= (_rclGrid._ulCtGridsX)) _ulX = 0; else return; if (++_ulY >= (_rclGrid._ulCtGridsY)) { _ulY = 0; _ulZ++; } else return; } //@} /** @name Tests with rays */ //@{ /** Searches for facets around the ray. */ bool InitOnRay (const Base::Vector3f &rclPt, const Base::Vector3f &rclDir, std::vector &raulElements); /** Searches for facets around the ray. */ bool InitOnRay (const Base::Vector3f &rclPt, const Base::Vector3f &rclDir, float fMaxSearchArea, std::vector &raulElements); /** Searches for facets around the ray. */ bool NextOnRay (std::vector &raulElements); //@} /** Returns the grid number of the current position. */ void GetGridPos (unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const { rulX = _ulX; rulY = _ulY; rulZ = _ulZ; } protected: const MeshGrid& _rclGrid; /**< The mesh kernel. */ unsigned long _ulX; /**< Number of grids in x. */ unsigned long _ulY; /**< Number of grids in y. */ unsigned long _ulZ; /**< Number of grids in z. */ Base::Vector3f _clPt; /**< Base point of search ray. */ Base::Vector3f _clDir; /**< Direction of search ray. */ bool _bValidRay; /**< Search ray ok? */ float _fMaxSearchArea; /** Checks if a grid position is already visited by NextOnRay(). */ struct GridElement { GridElement( unsigned long x, unsigned long y, unsigned long z) { this->x = x; this->y = y; this->z = z; } bool operator < (const GridElement& pos) const { if ( x == pos.x) { if ( y == pos.y) return z < pos.z; else return y < pos.y; } else { return x < pos.x; } } private: unsigned long x,y,z; }; std::set _cSearchPositions; }; // -------------------------------------------------------------- inline Base::BoundBox3f MeshGrid::GetBoundBox (unsigned long ulX, unsigned long ulY, unsigned long ulZ) const { float fX, fY, fZ; fX = _fMinX + (float(ulX) * _fGridLenX); fY = _fMinY + (float(ulY) * _fGridLenY); fZ = _fMinZ + (float(ulZ) * _fGridLenZ); return Base::BoundBox3f(fX, fY, fZ, fX + _fGridLenX, fY + _fGridLenY, fZ + _fGridLenZ); } inline Base::BoundBox3f MeshGrid::GetBoundBox (void) const { return Base::BoundBox3f(_fMinX, _fMinY, _fMinZ, _fMinX + (_fGridLenX * float(_ulCtGridsX)), _fMinY + (_fGridLenY * float(_ulCtGridsY)), _fMinZ + (_fGridLenZ * float(_ulCtGridsZ))); } inline Base::BoundBox3f MeshGrid::GetMeshBoundBox (void) const { Base::BoundBox3f clBBenlarged = _pclMesh->GetBoundBox(); clBBenlarged.Enlarge(MESHGRID_BBOX_EXTENSION); return clBBenlarged; } inline bool MeshGrid::CheckPos (unsigned long ulX, unsigned long ulY, unsigned long ulZ) const { return ((ulX < _ulCtGridsX) && (ulY < _ulCtGridsY) && (ulZ < _ulCtGridsZ)); } // -------------------------------------------------------------- inline void MeshFacetGrid::Pos (const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const { rulX = (unsigned long)((rclPoint.x - _fMinX) / _fGridLenX); rulY = (unsigned long)((rclPoint.y - _fMinY) / _fGridLenY); rulZ = (unsigned long)((rclPoint.z - _fMinZ) / _fGridLenZ); assert((rulX < _ulCtGridsX) && (rulY < _ulCtGridsY) && (rulZ < _ulCtGridsZ)); } inline void MeshFacetGrid::PosWithCheck (const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const { if ( rclPoint.x < _fMinX) rulX = 0; else { rulX = (unsigned long)((rclPoint.x - _fMinX) / _fGridLenX); if (rulX >= _ulCtGridsX) rulX = (_ulCtGridsX-1); } if ( rclPoint.y < _fMinY) rulY = 0; else { rulY = (unsigned long)((rclPoint.y - _fMinY) / _fGridLenY); if (rulY >= _ulCtGridsY) rulY = (_ulCtGridsY-1); } if ( rclPoint.z < _fMinZ) rulZ = 0; else { rulZ = (unsigned long)((rclPoint.z - _fMinZ) / _fGridLenZ); if (rulZ >= _ulCtGridsZ) rulZ = (_ulCtGridsZ-1); } assert((rulX < _ulCtGridsX) && (rulY < _ulCtGridsY) && (rulZ < _ulCtGridsZ)); } inline void MeshFacetGrid::AddFacet (const MeshGeomFacet &rclFacet, unsigned long ulFacetIndex, float /*fEpsilon*/) { #if 0 unsigned long i, ulX, ulY, ulZ, ulX1, ulY1, ulZ1, ulX2, ulY2, ulZ2; ulX1 = ulY1 = ulZ1 = ULONG_MAX; ulX2 = ulY2 = ulZ2 = 0; for (i = 0; i < 3; i++) { Pos(rclFacet._aclPoints[i], ulX, ulY, ulZ); _aulGrid[ulX][ulY][ulZ].insert(ulFacetIndex); ulX1 = RSmin(ulX1, ulX); ulY1 = RSmin(ulY1, ulY); ulZ1 = RSmin(ulZ1, ulZ); ulX2 = RSmax(ulX2, ulX); ulY2 = RSmax(ulY2, ulY); ulZ2 = RSmax(ulZ2, ulZ); } // falls Facet ueber mehrere BB reicht if ((ulX1 < ulX2) || (ulY1 < ulY2) || (ulZ1 < ulZ2)) { for (ulX = ulX1; ulX <= ulX2; ulX++) { for (ulY = ulY1; ulY <= ulY2; ulY++) { for (ulZ = ulZ1; ulZ <= ulZ2; ulZ++) { if (CMeshFacetFunc::BBoxContainFacet(GetBoundBox(ulX, ulY, ulZ), rclFacet) == true) _aulGrid[ulX][ulY][ulZ].insert(ulFacetIndex); } } } } #else unsigned long ulX, ulY, ulZ; unsigned long ulX1, ulY1, ulZ1, ulX2, ulY2, ulZ2; Base::BoundBox3f clBB; clBB.Add(rclFacet._aclPoints[0]); clBB.Add(rclFacet._aclPoints[1]); clBB.Add(rclFacet._aclPoints[2]); //float fDiagonalLength = clBB.CalcDiagonalLength(); //clBB.Enlarge(fEpsilon*fDiagonalLength); Pos(Base::Vector3f(clBB.MinX,clBB.MinY,clBB.MinZ), ulX1, ulY1, ulZ1); Pos(Base::Vector3f(clBB.MaxX,clBB.MaxY,clBB.MaxZ), ulX2, ulY2, ulZ2); /* if (ulX1 > 0) ulX1--; if (ulY1 > 0) ulY1--; if (ulZ1 > 0) ulZ1--; if (ulX2 < (_ulCtGridsX-1)) ulX2++; if (ulY2 < (_ulCtGridsY-1)) ulY2++; if (ulZ2 < (_ulCtGridsZ-1)) ulZ2++; */ // falls Facet ueber mehrere BB reicht if ((ulX1 < ulX2) || (ulY1 < ulY2) || (ulZ1 < ulZ2)) { for (ulX = ulX1; ulX <= ulX2; ulX++) { for (ulY = ulY1; ulY <= ulY2; ulY++) { for (ulZ = ulZ1; ulZ <= ulZ2; ulZ++) { if ( rclFacet.IntersectBoundingBox( GetBoundBox(ulX, ulY, ulZ) ) ) _aulGrid[ulX][ulY][ulZ].insert(ulFacetIndex); } } } } else _aulGrid[ulX1][ulY1][ulZ1].insert(ulFacetIndex); #endif } } // namespace MeshCore #endif // MESH_GRID_H