FreeCAD/src/Mod/Mesh/App/Core/Grid.cpp
2011-10-10 13:44:52 +00:00

1163 lines
35 KiB
C++

/***************************************************************************
* 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 *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <algorithm>
#endif
#include "Grid.h"
#include "Iterator.h"
#include "MeshKernel.h"
#include "Algorithm.h"
#include "Tools.h"
using namespace MeshCore;
MeshGrid::MeshGrid (const MeshKernel &rclM)
: _pclMesh(&rclM),
_ulCtElements(0),
_ulCtGridsX(0), _ulCtGridsY(0), _ulCtGridsZ(0),
_fGridLenX(0.0f), _fGridLenY(0.0f), _fGridLenZ(0.0f),
_fMinX(0.0f), _fMinY(0.0f), _fMinZ(0.0f)
{
}
MeshGrid::MeshGrid (void)
: _pclMesh(NULL),
_ulCtElements(0),
_ulCtGridsX(MESH_CT_GRID), _ulCtGridsY(MESH_CT_GRID), _ulCtGridsZ(MESH_CT_GRID),
_fGridLenX(0.0f), _fGridLenY(0.0f), _fGridLenZ(0.0f),
_fMinX(0.0f), _fMinY(0.0f), _fMinZ(0.0f)
{
}
void MeshGrid::Attach (const MeshKernel &rclM)
{
_pclMesh = &rclM;
RebuildGrid();
}
void MeshGrid::Clear (void)
{
_aulGrid.clear();
_pclMesh = NULL;
}
void MeshGrid::Rebuild (unsigned long ulX, unsigned long ulY, unsigned long ulZ)
{
_ulCtGridsX = ulX;
_ulCtGridsY = ulY;
_ulCtGridsZ = ulZ;
_ulCtElements = HasElements();
RebuildGrid();
}
void MeshGrid::Rebuild (unsigned long ulPerGrid, unsigned long ulMaxGrid)
{
_ulCtElements = HasElements();
CalculateGridLength(ulPerGrid, ulMaxGrid);
RebuildGrid();
}
void MeshGrid::Rebuild (int iCtGridPerAxis)
{
_ulCtElements = HasElements();
CalculateGridLength(iCtGridPerAxis);
RebuildGrid();
}
void MeshGrid::InitGrid (void)
{
assert(_pclMesh != NULL);
unsigned long i, j;
// Grid Laengen berechnen wenn nicht initialisiert
//
if ((_ulCtGridsX == 0) || (_ulCtGridsX == 0) || (_ulCtGridsX == 0))
CalculateGridLength(MESH_CT_GRID, MESH_MAX_GRIDS);
// Grid Laengen und Offset bestimmen
//
{
Base::BoundBox3f clBBMesh = _pclMesh->GetBoundBox();
float fLengthX = clBBMesh.LengthX();
float fLengthY = clBBMesh.LengthY();
float fLengthZ = clBBMesh.LengthZ();
{
// Offset fGridLen/2
//
_fGridLenX = (1.0f + fLengthX) / float(_ulCtGridsX);
_fMinX = clBBMesh.MinX - 0.5f;
}
{
_fGridLenY = (1.0f + fLengthY) / float(_ulCtGridsY);
_fMinY = clBBMesh.MinY - 0.5f;
}
{
_fGridLenZ = (1.0f + fLengthZ) / float(_ulCtGridsZ);
_fMinZ = clBBMesh.MinZ - 0.5f;
}
}
// Daten-Struktur anlegen
_aulGrid.clear();
_aulGrid.resize(_ulCtGridsX);
for (i = 0; i < _ulCtGridsX; i++)
{
_aulGrid[i].resize(_ulCtGridsY);
for (j = 0; j < _ulCtGridsY; j++)
_aulGrid[i][j].resize(_ulCtGridsZ);
}
}
unsigned long MeshGrid::Inside (const Base::BoundBox3f &rclBB, std::vector<unsigned long> &raulElements,
bool bDelDoubles) const
{
unsigned long i, j, k, ulMinX, ulMinY, ulMinZ, ulMaxX, ulMaxY, ulMaxZ;
raulElements.clear();
// Grid-Boxen zur naehreren Auswahl
Position(Base::Vector3f(rclBB.MinX, rclBB.MinY, rclBB.MinZ), ulMinX, ulMinY, ulMinZ);
Position(Base::Vector3f(rclBB.MaxX, rclBB.MaxY, rclBB.MaxZ), ulMaxX, ulMaxY, ulMaxZ);
for (i = ulMinX; i <= ulMaxX; i++)
{
for (j = ulMinY; j <= ulMaxY; j++)
{
for (k = ulMinZ; k <= ulMaxZ; k++)
{
raulElements.insert(raulElements.end(), _aulGrid[i][j][k].begin(), _aulGrid[i][j][k].end());
}
}
}
if (bDelDoubles == true)
{
// doppelte Nennungen entfernen
std::sort(raulElements.begin(), raulElements.end());
raulElements.erase(std::unique(raulElements.begin(), raulElements.end()), raulElements.end());
}
return raulElements.size();
}
unsigned long MeshGrid::Inside (const Base::BoundBox3f &rclBB, std::vector<unsigned long> &raulElements,
const Base::Vector3f &rclOrg, float fMaxDist, bool bDelDoubles) const
{
unsigned long i, j, k, ulMinX, ulMinY, ulMinZ, ulMaxX, ulMaxY, ulMaxZ;
float fGridDiag = GetBoundBox(0, 0, 0).CalcDiagonalLength();
float fMinDistP2 = (fGridDiag * fGridDiag) + (fMaxDist * fMaxDist);
raulElements.clear();
// Grid-Boxen zur naehreren Auswahl
Position(Base::Vector3f(rclBB.MinX, rclBB.MinY, rclBB.MinZ), ulMinX, ulMinY, ulMinZ);
Position(Base::Vector3f(rclBB.MaxX, rclBB.MaxY, rclBB.MaxZ), ulMaxX, ulMaxY, ulMaxZ);
for (i = ulMinX; i <= ulMaxX; i++)
{
for (j = ulMinY; j <= ulMaxY; j++)
{
for (k = ulMinZ; k <= ulMaxZ; k++)
{
if (Base::DistanceP2(GetBoundBox(i, j, k).CalcCenter(), rclOrg) < fMinDistP2)
raulElements.insert(raulElements.end(), _aulGrid[i][j][k].begin(), _aulGrid[i][j][k].end());
}
}
}
if (bDelDoubles == true)
{
// doppelte Nennungen entfernen
std::sort(raulElements.begin(), raulElements.end());
raulElements.erase(std::unique(raulElements.begin(), raulElements.end()), raulElements.end());
}
return raulElements.size();
}
unsigned long MeshGrid::Inside (const Base::BoundBox3f &rclBB, std::set<unsigned long> &raulElements) const
{
unsigned long i, j, k, ulMinX, ulMinY, ulMinZ, ulMaxX, ulMaxY, ulMaxZ;
raulElements.clear();
// Grid-Boxen zur naehreren Auswahl
Position(Base::Vector3f(rclBB.MinX, rclBB.MinY, rclBB.MinZ), ulMinX, ulMinY, ulMinZ);
Position(Base::Vector3f(rclBB.MaxX, rclBB.MaxY, rclBB.MaxZ), ulMaxX, ulMaxY, ulMaxZ);
for (i = ulMinX; i <= ulMaxX; i++)
{
for (j = ulMinY; j <= ulMaxY; j++)
{
for (k = ulMinZ; k <= ulMaxZ; k++)
{
raulElements.insert(_aulGrid[i][j][k].begin(), _aulGrid[i][j][k].end());
}
}
}
return raulElements.size();
}
bool MeshGrid::CheckPosition (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);
if ( (rulX < _ulCtGridsX) && (rulY < _ulCtGridsY) && (rulZ < _ulCtGridsZ) )
return true;
return false;
}
void MeshGrid::Position (const Base::Vector3f &rclPoint, unsigned long &rulX, unsigned long &rulY, unsigned long &rulZ) const
{
if (rclPoint.x <= _fMinX)
rulX = 0;
else
rulX = std::min<unsigned long>((unsigned long)((rclPoint.x - _fMinX) / _fGridLenX), _ulCtGridsX - 1);
if (rclPoint.y <= _fMinY)
rulY = 0;
else
rulY = std::min<unsigned long>((unsigned long)((rclPoint.y - _fMinY) / _fGridLenY), _ulCtGridsY - 1);
if (rclPoint.z <= _fMinZ)
rulZ = 0;
else
rulZ = std::min<unsigned long>((unsigned long)((rclPoint.z - _fMinZ) / _fGridLenZ), _ulCtGridsZ - 1);
}
void MeshGrid::CalculateGridLength (unsigned long ulCtGrid, unsigned long ulMaxGrids)
{
// Grid Laengen bzw. Anzahl der Grids pro Dimension berechnen
// pro Grid sollen ca. 10 (?!?!) Facets liegen
// bzw. max Grids sollten 10000 nicht ueberschreiten
Base::BoundBox3f clBBMeshEnlarged = _pclMesh->GetBoundBox();
float fVolElem;
if (_ulCtElements > (ulMaxGrids * ulCtGrid))
fVolElem = (clBBMeshEnlarged.LengthX() * clBBMeshEnlarged.LengthY() * clBBMeshEnlarged.LengthZ()) / float(ulMaxGrids * ulCtGrid);
else
fVolElem = (clBBMeshEnlarged.LengthX() * clBBMeshEnlarged.LengthY() * clBBMeshEnlarged.LengthZ()) / float(_ulCtElements);
float fVol = fVolElem * float(ulCtGrid);
float fGridLen = float(pow((float)fVol,(float) 1.0f / 3.0f));
_ulCtGridsX = std::max<unsigned long>((unsigned long)(clBBMeshEnlarged.LengthX() / fGridLen), 1);
_ulCtGridsY = std::max<unsigned long>((unsigned long)(clBBMeshEnlarged.LengthY() / fGridLen), 1);
_ulCtGridsZ = std::max<unsigned long>((unsigned long)(clBBMeshEnlarged.LengthZ() / fGridLen), 1);
}
void MeshGrid::CalculateGridLength (int iCtGridPerAxis)
{
if (iCtGridPerAxis<=0)
{
CalculateGridLength(MESH_CT_GRID, MESH_MAX_GRIDS);
return;
}
// Grid Laengen bzw. Anzahl der Grids pro Dimension berechnen
// pro Grid sollen ca. 10 (?!?!) Facets liegen
// bzw. max Grids sollten 10000 nicht ueberschreiten
Base::BoundBox3f clBBMesh = _pclMesh->GetBoundBox();
float fLenghtX = clBBMesh.LengthX();
float fLenghtY = clBBMesh.LengthY();
float fLenghtZ = clBBMesh.LengthZ();
float fLenghtD = clBBMesh.CalcDiagonalLength();
float fLengthTol = 0.05f * fLenghtD;
bool bLenghtXisZero = (fLenghtX <= fLengthTol);
bool bLenghtYisZero = (fLenghtY <= fLengthTol);
bool bLenghtZisZero = (fLenghtZ <= fLengthTol);
int iFlag = 0;
int iMaxGrids = 1;
if (bLenghtXisZero)
iFlag += 1;
else
iMaxGrids *= iCtGridPerAxis;
if (bLenghtYisZero)
iFlag += 2;
else
iMaxGrids *= iCtGridPerAxis;
if (bLenghtZisZero)
iFlag += 4;
else
iMaxGrids *= iCtGridPerAxis;
unsigned long ulGridsFacets = 10;
float fFactorVolumen = 40.0;
float fFactorArea = 10.0;
switch (iFlag)
{
case 0:
{
float fVolumen = fLenghtX * fLenghtY * fLenghtZ;
float fVolumenGrid = (fVolumen * ulGridsFacets) / (fFactorVolumen * _ulCtElements);
if ((fVolumenGrid * iMaxGrids) < fVolumen)
fVolumenGrid = fVolumen / (float)iMaxGrids;
float fLengthGrid = float(pow((float)fVolumenGrid,(float) 1.0f / 3.0f));
_ulCtGridsX = std::max<unsigned long>((unsigned long)(fLenghtX / fLengthGrid), 1);
_ulCtGridsY = std::max<unsigned long>((unsigned long)(fLenghtY / fLengthGrid), 1);
_ulCtGridsZ = std::max<unsigned long>((unsigned long)(fLenghtZ / fLengthGrid), 1);
} break;
case 1:
{
_ulCtGridsX = 1; // bLenghtXisZero
float fArea = fLenghtY * fLenghtZ;
float fAreaGrid = (fArea * ulGridsFacets) / (fFactorArea * _ulCtElements);
if ((fAreaGrid * iMaxGrids) < fArea)
fAreaGrid = fArea / (float)iMaxGrids;
float fLengthGrid = float(sqrt(fAreaGrid));
_ulCtGridsY = std::max<unsigned long>((unsigned long)(fLenghtY / fLengthGrid), 1);
_ulCtGridsZ = std::max<unsigned long>((unsigned long)(fLenghtZ / fLengthGrid), 1);
} break;
case 2:
{
_ulCtGridsY = 1; // bLenghtYisZero
float fArea = fLenghtX * fLenghtZ;
float fAreaGrid = (fArea * ulGridsFacets) / (fFactorArea * _ulCtElements);
if ((fAreaGrid * iMaxGrids) < fArea)
fAreaGrid = fArea / (float)iMaxGrids;
float fLengthGrid = float(sqrt(fAreaGrid));
_ulCtGridsX = std::max<unsigned long>((unsigned long)(fLenghtX / fLengthGrid), 1);
_ulCtGridsZ = std::max<unsigned long>((unsigned long)(fLenghtZ / fLengthGrid), 1);
} break;
case 3:
{
_ulCtGridsX = 1; // bLenghtXisZero
_ulCtGridsY = 1; // bLenghtYisZero
_ulCtGridsZ = iMaxGrids; // bLenghtYisZero
} break;
case 4:
{
_ulCtGridsZ = 1; // bLenghtZisZero
float fArea = fLenghtX * fLenghtY;
float fAreaGrid = (fArea * ulGridsFacets) / (fFactorArea * _ulCtElements);
if ((fAreaGrid * iMaxGrids) < fArea)
fAreaGrid = fArea / (float)iMaxGrids;
float fLengthGrid = float(sqrt(fAreaGrid));
_ulCtGridsX = std::max<unsigned long>((unsigned long)(fLenghtX / fLengthGrid), 1);
_ulCtGridsY = std::max<unsigned long>((unsigned long)(fLenghtY / fLengthGrid), 1);
} break;
case 5:
{
_ulCtGridsX = 1; // bLenghtXisZero
_ulCtGridsZ = 1; // bLenghtZisZero
_ulCtGridsY = iMaxGrids; // bLenghtYisZero
} break;
case 6:
{
_ulCtGridsY = 1; // bLenghtYisZero
_ulCtGridsZ = 1; // bLenghtZisZero
_ulCtGridsX = iMaxGrids; // bLenghtYisZero
} break;
case 7:
{
_ulCtGridsX = iMaxGrids; // bLenghtXisZero
_ulCtGridsY = iMaxGrids; // bLenghtYisZero
_ulCtGridsZ = iMaxGrids; // bLenghtZisZero
} break;
}
}
void MeshGrid::SearchNearestFromPoint (const Base::Vector3f &rclPt, std::set<unsigned long> &raclInd) const
{
raclInd.clear();
Base::BoundBox3f clBB = GetBoundBox();
if (clBB.IsInBox(rclPt) == true)
{ // Punkt liegt innerhalb
unsigned long ulX, ulY, ulZ;
Position(rclPt, ulX, ulY, ulZ);
//int nX = ulX, nY = ulY, nZ = ulZ;
unsigned long ulLevel = 0;
while (raclInd.size() == 0)
GetHull(ulX, ulY, ulZ, ulLevel++, raclInd);
GetHull(ulX, ulY, ulZ, ulLevel, raclInd);
}
else
{ // Punkt ausserhalb
Base::BoundBox3f::SIDE tSide = clBB.GetSideFromRay(rclPt, clBB.CalcCenter() - rclPt);
switch (tSide)
{
case Base::BoundBox3f::RIGHT:
{
int nX = 0;
while (raclInd.size() == 0)
{
for (unsigned long i = 0; i < _ulCtGridsY; i++)
{
for (unsigned long j = 0; j < _ulCtGridsZ; j++)
raclInd.insert(_aulGrid[nX][i][j].begin(), _aulGrid[nX][i][j].end());
}
nX++;
}
break;
}
case Base::BoundBox3f::LEFT:
{
int nX = _ulCtGridsX - 1;
while (raclInd.size() == 0)
{
for (unsigned long i = 0; i < _ulCtGridsY; i++)
{
for (unsigned long j = 0; j < _ulCtGridsZ; j++)
raclInd.insert(_aulGrid[nX][i][j].begin(), _aulGrid[nX][i][j].end());
}
nX++;
}
break;
}
case Base::BoundBox3f::TOP:
{
int nY = 0;
while (raclInd.size() == 0)
{
for (unsigned long i = 0; i < _ulCtGridsX; i++)
{
for (unsigned long j = 0; j < _ulCtGridsZ; j++)
raclInd.insert(_aulGrid[i][nY][j].begin(), _aulGrid[i][nY][j].end());
}
nY++;
}
break;
}
case Base::BoundBox3f::BOTTOM:
{
int nY = _ulCtGridsY - 1;
while (raclInd.size() == 0)
{
for (unsigned long i = 0; i < _ulCtGridsX; i++)
{
for (unsigned long j = 0; j < _ulCtGridsZ; j++)
raclInd.insert(_aulGrid[i][nY][j].begin(), _aulGrid[i][nY][j].end());
}
nY--;
}
break;
}
case Base::BoundBox3f::BACK:
{
int nZ = 0;
while (raclInd.size() == 0)
{
for (unsigned long i = 0; i < _ulCtGridsX; i++)
{
for (unsigned long j = 0; j < _ulCtGridsY; j++)
raclInd.insert(_aulGrid[i][j][nZ].begin(), _aulGrid[i][j][nZ].end());
}
nZ++;
}
break;
}
case Base::BoundBox3f::FRONT:
{
int nZ = _ulCtGridsZ - 1;
while (raclInd.size() == 0)
{
for (unsigned long i = 0; i < _ulCtGridsX; i++)
{
for (unsigned long j = 0; j < _ulCtGridsY; j++)
raclInd.insert(_aulGrid[i][j][nZ].begin(), _aulGrid[i][j][nZ].end());
}
nZ--;
}
break;
}
default:
break;
}
}
}
void MeshGrid::GetHull (unsigned long ulX, unsigned long ulY, unsigned long ulZ,
unsigned long ulDistance, std::set<unsigned long> &raclInd) const
{
int nX1 = std::max<int>(0, int(ulX) - int(ulDistance));
int nY1 = std::max<int>(0, int(ulY) - int(ulDistance));
int nZ1 = std::max<int>(0, int(ulZ) - int(ulDistance));
int nX2 = std::min<int>(int(_ulCtGridsX) - 1, int(ulX) + int(ulDistance));
int nY2 = std::min<int>(int(_ulCtGridsY) - 1, int(ulY) + int(ulDistance));
int nZ2 = std::min<int>(int(_ulCtGridsZ) - 1, int(ulZ) + int(ulDistance));
int i, j;
// top plane
for (i = nX1; i <= nX2; i++)
{
for (j = nY1; j <= nY2; j++)
GetElements(i, j, nZ1, raclInd);
}
// bottom plane
for (i = nX1; i <= nX2; i++)
{
for (j = nY1; j <= nY2; j++)
GetElements(i, j, nZ2, raclInd);
}
// left plane
for (i = nY1; i <= nY2; i++)
{
for (j = (nZ1+1); j <= (nZ2-1); j++)
GetElements(nX1, i, j, raclInd);
}
// right plane
for (i = nY1; i <= nY2; i++)
{
for (j = (nZ1+1); j <= (nZ2-1); j++)
GetElements(nX2, i, j, raclInd);
}
// front plane
for (i = (nX1+1); i <= (nX2-1); i++)
{
for (j = (nZ1+1); j <= (nZ2-1); j++)
GetElements(i, nY1, j, raclInd);
}
// back plane
for (i = (nX1+1); i <= (nX2-1); i++)
{
for (j = (nZ1+1); j <= (nZ2-1); j++)
GetElements(i, nY2, j, raclInd);
}
}
unsigned long MeshGrid::GetElements (unsigned long ulX, unsigned long ulY, unsigned long ulZ,
std::set<unsigned long> &raclInd) const
{
const std::set<unsigned long> &rclSet = _aulGrid[ulX][ulY][ulZ];
if (rclSet.size() > 0)
{
raclInd.insert(rclSet.begin(), rclSet.end());
return rclSet.size();
}
return 0;
}
unsigned long MeshGrid::GetElements(const Base::Vector3f &rclPoint, std::vector<unsigned long>& aulFacets) const
{
unsigned long ulX, ulY, ulZ;
if (!CheckPosition(rclPoint, ulX, ulY, ulZ))
return 0;
aulFacets.resize(_aulGrid[ulX][ulY][ulZ].size());
std::copy(_aulGrid[ulX][ulY][ulZ].begin(), _aulGrid[ulX][ulY][ulZ].end(), aulFacets.begin());
return aulFacets.size();
}
unsigned long MeshGrid::GetIndexToPosition(unsigned long ulX, unsigned long ulY, unsigned long ulZ) const
{
if ( !CheckPos(ulX, ulY, ulZ) )
return ULONG_MAX;
return (ulZ * _ulCtGridsY + ulY) * _ulCtGridsX + ulX;
}
bool MeshGrid::GetPositionToIndex(unsigned long id, unsigned long& ulX, unsigned long& ulY, unsigned long& ulZ) const
{
ulX = id % _ulCtGridsX;
ulY = (id/_ulCtGridsX)%_ulCtGridsY;
ulZ = id/(_ulCtGridsX*_ulCtGridsY);
if ( !CheckPos(ulX, ulY, ulZ) )
{
ulX = ULONG_MAX;
ulY = ULONG_MAX;
ulZ = ULONG_MAX;
return false;
}
return true;
}
// ----------------------------------------------------------------
MeshFacetGrid::MeshFacetGrid (const MeshKernel &rclM)
: MeshGrid(rclM)
{
RebuildGrid();
}
MeshFacetGrid::MeshFacetGrid (const MeshKernel &rclM, int iCtGridPerAxis)
: MeshGrid(rclM)
{
Rebuild(iCtGridPerAxis);
}
MeshFacetGrid::MeshFacetGrid (const MeshKernel &rclM, unsigned long ulX, unsigned long ulY, unsigned long ulZ)
: MeshGrid(rclM)
{
Rebuild(ulX, ulY, ulZ);
}
MeshFacetGrid::MeshFacetGrid (const MeshKernel &rclM, float fGridLen)
: MeshGrid(rclM)
{
Base::BoundBox3f clBBMesh = _pclMesh->GetBoundBox();
Rebuild(std::max<unsigned long>((unsigned long)(clBBMesh.LengthX() / fGridLen), 1),
std::max<unsigned long>((unsigned long)(clBBMesh.LengthY() / fGridLen), 1),
std::max<unsigned long>((unsigned long)(clBBMesh.LengthZ() / fGridLen), 1));
}
void MeshFacetGrid::Validate (const MeshKernel &rclMesh)
{
if (_pclMesh != &rclMesh)
Attach(rclMesh);
else if (rclMesh.CountFacets() != _ulCtElements)
RebuildGrid();
}
void MeshFacetGrid::Validate (void)
{
if (_pclMesh == NULL)
return;
if (_pclMesh->CountFacets() != _ulCtElements)
RebuildGrid();
}
bool MeshFacetGrid::Verify() const
{
if ( !_pclMesh )
return false; // no mesh attached
if (_pclMesh->CountFacets() != _ulCtElements)
return false; // not up-to-date
MeshGridIterator it(*this);
MeshFacetIterator cF(*_pclMesh);
for ( it.Init(); it.More(); it.Next() )
{
std::vector<unsigned long> aulElements;
it.GetElements( aulElements );
for ( std::vector<unsigned long>::iterator itF = aulElements.begin(); itF != aulElements.end(); ++itF )
{
cF.Set( *itF );
if ( cF->IntersectBoundingBox( it.GetBoundBox() ) == false )
return false; // no intersection between facet although the facet is in grid
}
}
return true;
}
void MeshFacetGrid::RebuildGrid (void)
{
_ulCtElements = _pclMesh->CountFacets();
InitGrid();
// Daten-Struktur fuellen
MeshFacetIterator clFIter(*_pclMesh);
unsigned long i = 0;
for (clFIter.Init(); clFIter.More(); clFIter.Next())
{
// AddFacet(*clFIter, i++, 2.0f);
AddFacet(*clFIter, i++);
}
}
unsigned long MeshFacetGrid::SearchNearestFromPoint (const Base::Vector3f &rclPt) const
{
unsigned long ulFacetInd = ULONG_MAX;
float fMinDist = FLOAT_MAX;
Base::BoundBox3f clBB = GetBoundBox();
if (clBB.IsInBox(rclPt) == true)
{ // Punkt liegt innerhalb
unsigned long ulX, ulY, ulZ;
Position(rclPt, ulX, ulY, ulZ);
float fMinGridDist = std::min<float>(std::min<float>(_fGridLenX, _fGridLenY), _fGridLenZ);
unsigned long ulDistance = 0;
while (fMinDist > (fMinGridDist * float(ulDistance)))
{
SearchNearestFacetInHull(ulX, ulY, ulZ, ulDistance, rclPt, ulFacetInd, fMinDist);
ulDistance++;
}
SearchNearestFacetInHull(ulX, ulY, ulZ, ulDistance, rclPt, ulFacetInd, fMinDist);
}
else
{ // Punkt ausserhalb
Base::BoundBox3f::SIDE tSide = clBB.GetSideFromRay(rclPt, clBB.CalcCenter() - rclPt);
switch (tSide)
{
case Base::BoundBox3f::RIGHT:
{
int nX = 0;
while ((fMinDist > ((clBB.MinX - rclPt.x) + ((float)(nX) * _fGridLenX))) && ((unsigned long)(nX) < _ulCtGridsX))
{
for (unsigned long i = 0; i < _ulCtGridsY; i++)
{
for (unsigned long j = 0; j < _ulCtGridsZ; j++)
SearchNearestFacetInGrid(nX, i, j, rclPt, fMinDist, ulFacetInd);
}
nX++;
}
break;
}
case Base::BoundBox3f::LEFT:
{
int nX = _ulCtGridsX - 1;
while ((fMinDist > ((rclPt.x - clBB.MinX) + (float(nX) * _fGridLenX))) && (nX >= 0))
{
for (unsigned long i = 0; i < _ulCtGridsY; i++)
{
for (unsigned long j = 0; j < _ulCtGridsZ; j++)
SearchNearestFacetInGrid(nX, i, j, rclPt, fMinDist, ulFacetInd);
}
nX--;
}
break;
}
case Base::BoundBox3f::TOP:
{
int nY = 0;
while ((fMinDist > ((clBB.MinY - rclPt.y) + ((float)(nY) * _fGridLenY))) && ((unsigned long)(nY) < _ulCtGridsY))
{
for (unsigned long i = 0; i < _ulCtGridsX; i++)
{
for (unsigned long j = 0; j < _ulCtGridsZ; j++)
SearchNearestFacetInGrid(i, nY, j, rclPt, fMinDist, ulFacetInd);
}
nY++;
}
break;
}
case Base::BoundBox3f::BOTTOM:
{
int nY = _ulCtGridsY - 1;
while ((fMinDist > ((rclPt.y - clBB.MinY) + (float(nY) * _fGridLenY))) && (nY >= 0))
{
for (unsigned long i = 0; i < _ulCtGridsX; i++)
{
for (unsigned long j = 0; j < _ulCtGridsZ; j++)
SearchNearestFacetInGrid(i, nY, j, rclPt, fMinDist, ulFacetInd);
}
nY--;
}
break;
}
case Base::BoundBox3f::BACK:
{
int nZ = 0;
while ((fMinDist > ((clBB.MinZ - rclPt.z) + ((float)(nZ) * _fGridLenZ))) && ((unsigned long)(nZ) < _ulCtGridsZ))
{
for (unsigned long i = 0; i < _ulCtGridsX; i++)
{
for (unsigned long j = 0; j < _ulCtGridsY; j++)
SearchNearestFacetInGrid(i, j, nZ, rclPt, fMinDist, ulFacetInd);
}
nZ++;
}
break;
}
case Base::BoundBox3f::FRONT:
{
int nZ = _ulCtGridsZ - 1;
while ((fMinDist > ((rclPt.z - clBB.MinZ) + ((float)(nZ) * _fGridLenZ))) && (nZ >= 0))
{
for (unsigned long i = 0; i < _ulCtGridsX; i++)
{
for (unsigned long j = 0; j < _ulCtGridsY; j++)
SearchNearestFacetInGrid(i, j, nZ, rclPt, fMinDist, ulFacetInd);
}
nZ--;
}
break;
}
default:
break;
}
}
return ulFacetInd;
}
unsigned long MeshFacetGrid::SearchNearestFromPoint (const Base::Vector3f &rclPt, float fMaxSearchArea) const
{
std::vector<unsigned long> aulFacets;
unsigned long ulFacetInd = ULONG_MAX;
float fMinDist = fMaxSearchArea;
MeshAlgorithm clFTool(*_pclMesh);
Base::BoundBox3f clBB(rclPt.x - fMaxSearchArea, rclPt.y - fMaxSearchArea, rclPt.z - fMaxSearchArea,
rclPt.x + fMaxSearchArea, rclPt.y + fMaxSearchArea, rclPt.z + fMaxSearchArea);
Inside(clBB, aulFacets, rclPt, fMaxSearchArea, true);
for (std::vector<unsigned long>::const_iterator pI = aulFacets.begin(); pI != aulFacets.end(); pI++)
{
float fDist;
if (clFTool.Distance(rclPt, *pI, fMinDist, fDist) == true)
{
fMinDist = fDist;
ulFacetInd = *pI;
}
}
return ulFacetInd;
}
void MeshFacetGrid::SearchNearestFacetInHull (unsigned long ulX, unsigned long ulY, unsigned long ulZ,
unsigned long ulDistance, const Base::Vector3f &rclPt,
unsigned long &rulFacetInd, float &rfMinDist) const
{
int nX1 = std::max<int>(0, int(ulX) - int(ulDistance));
int nY1 = std::max<int>(0, int(ulY) - int(ulDistance));
int nZ1 = std::max<int>(0, int(ulZ) - int(ulDistance));
int nX2 = std::min<int>(int(_ulCtGridsX) - 1, int(ulX) + int(ulDistance));
int nY2 = std::min<int>(int(_ulCtGridsY) - 1, int(ulY) + int(ulDistance));
int nZ2 = std::min<int>(int(_ulCtGridsZ) - 1, int(ulZ) + int(ulDistance));
int i, j;
// top plane
for (i = nX1; i <= nX2; i++)
{
for (j = nY1; j <= nY2; j++)
SearchNearestFacetInGrid(i, j, nZ1, rclPt, rfMinDist, rulFacetInd);
}
// bottom plane
for (i = nX1; i <= nX2; i++)
{
for (j = nY1; j <= nY2; j++)
SearchNearestFacetInGrid(i, j, nZ2, rclPt, rfMinDist, rulFacetInd);
}
// left plane
for (i = nY1; i <= nY2; i++)
{
for (j = (nZ1+1); j <= (nZ2-1); j++)
SearchNearestFacetInGrid(nX1, i, j, rclPt, rfMinDist, rulFacetInd);
}
// right plane
for (i = nY1; i <= nY2; i++)
{
for (j = (nZ1+1); j <= (nZ2-1); j++)
SearchNearestFacetInGrid(nX2, i, j, rclPt, rfMinDist, rulFacetInd);
}
// front plane
for (i = (nX1+1); i <= (nX2-1); i++)
{
for (j = (nZ1+1); j <= (nZ2-1); j++)
SearchNearestFacetInGrid(i, nY1, j, rclPt, rfMinDist, rulFacetInd);
}
// back plane
for (i = (nX1+1); i <= (nX2-1); i++)
{
for (j = (nZ1+1); j <= (nZ2-1); j++)
SearchNearestFacetInGrid(i, nY2, j, rclPt, rfMinDist, rulFacetInd);
}
}
void MeshFacetGrid::SearchNearestFacetInGrid(unsigned long ulX, unsigned long ulY, unsigned long ulZ,
const Base::Vector3f &rclPt, float &rfMinDist,
unsigned long &rulFacetInd) const
{
const std::set<unsigned long> &rclSet = _aulGrid[ulX][ulY][ulZ];
for (std::set<unsigned long>::const_iterator pI = rclSet.begin(); pI != rclSet.end(); pI++)
{
float fDist = _pclMesh->GetFacet(*pI).DistanceToPoint(rclPt);
if (fDist < rfMinDist)
{
rfMinDist = fDist;
rulFacetInd = *pI;
}
}
}
//----------------------------------------------------------------------------
MeshPointGrid::MeshPointGrid (const MeshKernel &rclM)
: MeshGrid(rclM)
{
RebuildGrid();
}
MeshPointGrid::MeshPointGrid (void)
: MeshGrid()
{
}
MeshPointGrid::MeshPointGrid (const MeshKernel &rclM, unsigned long ulX, unsigned long ulY, unsigned long ulZ)
: MeshGrid(rclM)
{
Rebuild(ulX, ulY, ulZ);
}
MeshPointGrid::MeshPointGrid (const MeshKernel &rclM, int iCtGridPerAxis)
: MeshGrid(rclM)
{
Rebuild(iCtGridPerAxis);
}
MeshPointGrid::MeshPointGrid (const MeshKernel &rclM, float fGridLen)
: MeshGrid(rclM)
{
Base::BoundBox3f clBBMesh = _pclMesh->GetBoundBox();
Rebuild(std::max<unsigned long>((unsigned long)(clBBMesh.LengthX() / fGridLen), 1),
std::max<unsigned long>((unsigned long)(clBBMesh.LengthY() / fGridLen), 1),
std::max<unsigned long>((unsigned long)(clBBMesh.LengthZ() / fGridLen), 1));
}
void MeshPointGrid::AddPoint (const MeshPoint &rclPt, unsigned long ulPtIndex, float fEpsilon)
{
unsigned long ulX, ulY, ulZ;
Pos(Base::Vector3f(rclPt.x, rclPt.y, rclPt.z), ulX, ulY, ulZ);
if ( (ulX < _ulCtGridsX) && (ulY < _ulCtGridsY) && (ulZ < _ulCtGridsZ) )
_aulGrid[ulX][ulY][ulZ].insert(ulPtIndex);
}
void MeshPointGrid::Validate (const MeshKernel &rclMesh)
{
if (_pclMesh != &rclMesh)
Attach(rclMesh);
else if (rclMesh.CountPoints() != _ulCtElements)
RebuildGrid();
}
void MeshPointGrid::Validate (void)
{
if (_pclMesh == NULL)
return;
if (_pclMesh->CountPoints() != _ulCtElements)
RebuildGrid();
}
bool MeshPointGrid::Verify() const
{
if ( !_pclMesh )
return false; // no mesh attached
if (_pclMesh->CountFacets() != _ulCtElements)
return false; // not up-to-date
MeshGridIterator it(*this);
MeshPointIterator cP(*_pclMesh);
for ( it.Init(); it.More(); it.Next() )
{
std::vector<unsigned long> aulElements;
it.GetElements( aulElements );
for ( std::vector<unsigned long>::iterator itP = aulElements.begin(); itP != aulElements.end(); ++itP )
{
cP.Set( *itP );
if ( it.GetBoundBox().IsInBox( *cP ) == false )
return false; // point doesn't lie inside the grid element
}
}
return true;
}
void MeshPointGrid::RebuildGrid (void)
{
_ulCtElements = _pclMesh->CountPoints();
InitGrid();
// Daten-Struktur fuellen
MeshPointIterator cPIter(*_pclMesh);
unsigned long i = 0;
for (cPIter.Init(); cPIter.More(); cPIter.Next())
{
AddPoint(*cPIter, i++);
}
}
void MeshPointGrid::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);
}
unsigned long MeshPointGrid::FindElements (const Base::Vector3f &rclPoint, std::set<unsigned long>& aulElements) const
{
unsigned long ulX, ulY, ulZ;
Pos(rclPoint, ulX, ulY, ulZ);
// check if the given point is inside the grid structure
if ( (ulX < _ulCtGridsX) && (ulY < _ulCtGridsY) && (ulZ < _ulCtGridsZ) )
{
return GetElements(ulX, ulY, ulZ, aulElements);
}
return 0;
}
// ----------------------------------------------------------------
MeshGridIterator::MeshGridIterator (const MeshGrid &rclG)
: _rclGrid(rclG),
_ulX(0), _ulY(0), _ulZ(0),
_clPt(0.0f, 0.0f, 0.0f), _clDir(0.0f, 0.0f, 0.0f),
_bValidRay(false),
_fMaxSearchArea (FLOAT_MAX)
{
}
bool MeshGridIterator::InitOnRay (const Base::Vector3f &rclPt, const Base::Vector3f &rclDir, float fMaxSearchArea,
std::vector<unsigned long> &raulElements)
{
bool ret = InitOnRay (rclPt, rclDir, raulElements);
_fMaxSearchArea = fMaxSearchArea;
return ret;
}
bool MeshGridIterator::InitOnRay (const Base::Vector3f &rclPt, const Base::Vector3f &rclDir,
std::vector<unsigned long> &raulElements)
{
// needed in NextOnRay() to avoid an infinite loop
_cSearchPositions.clear();
_fMaxSearchArea = FLOAT_MAX;
raulElements.clear();
_clPt = rclPt;
_clDir = rclDir;
_bValidRay = false;
// liegt Punkt innerhalb globalen BB
if ((_rclGrid.GetBoundBox().IsInBox(rclPt)) == true)
{ // Voxel bestimmen, indem der Startpunkt liegt
_rclGrid.Position(rclPt, _ulX, _ulY, _ulZ);
raulElements.insert(raulElements.end(), _rclGrid._aulGrid[_ulX][_ulY][_ulZ].begin(), _rclGrid._aulGrid[_ulX][_ulY][_ulZ].end());
_bValidRay = true;
}
else
{ // Startpunkt ausserhalb
Base::Vector3f cP0, cP1;
if (_rclGrid.GetBoundBox().IntersectWithLine(rclPt, rclDir, cP0, cP1) == true)
{ // naechsten Punkt bestimmen
if ((cP0 - rclPt).Length() < (cP1 - rclPt).Length())
_rclGrid.Position(cP0, _ulX, _ulY, _ulZ);
else
_rclGrid.Position(cP1, _ulX, _ulY, _ulZ);
raulElements.insert(raulElements.end(), _rclGrid._aulGrid[_ulX][_ulY][_ulZ].begin(), _rclGrid._aulGrid[_ulX][_ulY][_ulZ].end());
_bValidRay = true;
}
}
return _bValidRay;
}
bool MeshGridIterator::NextOnRay (std::vector<unsigned long> &raulElements)
{
if (_bValidRay == false)
return false; // nicht initialisiert oder Strahl ausgetreten
raulElements.clear();
Base::Vector3f clIntersectPoint;
// naechstes anliegende BB auf dem Suchstrahl suchen
Base::BoundBox3f::SIDE tSide = _rclGrid.GetBoundBox(_ulX, _ulY, _ulZ).GetSideFromRay(_clPt, _clDir, clIntersectPoint);
// Suchbereich
//
if ((_clPt-clIntersectPoint).Length() > _fMaxSearchArea)
{
_bValidRay = false;
}
else
{
switch (tSide)
{
case Base::BoundBox3f::LEFT: _ulX--; break;
case Base::BoundBox3f::RIGHT: _ulX++; break;
case Base::BoundBox3f::BOTTOM: _ulY--; break;
case Base::BoundBox3f::TOP: _ulY++; break;
case Base::BoundBox3f::FRONT: _ulZ--; break;
case Base::BoundBox3f::BACK: _ulZ++; break;
default:
case Base::BoundBox3f::INVALID:
_bValidRay = false;
break;
}
GridElement pos(_ulX, _ulY, _ulZ);
if ( _cSearchPositions.find( pos ) != _cSearchPositions.end() )
_bValidRay = false; // grid element already visited => result from GetSideFromRay invalid
}
if ((_bValidRay == true) && (_rclGrid.CheckPos(_ulX, _ulY, _ulZ) == true))
{
GridElement pos(_ulX, _ulY, _ulZ); _cSearchPositions.insert(pos);
raulElements.insert(raulElements.end(), _rclGrid._aulGrid[_ulX][_ulY][_ulZ].begin(), _rclGrid._aulGrid[_ulX][_ulY][_ulZ].end());
}
else
_bValidRay = false; // Strahl ausgetreten
return _bValidRay;
}