Files
create/src/Mod/Mesh/App/Core/Builder.cpp
2011-10-10 13:44:52 +00:00

252 lines
9.8 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 <Base/Sequencer.h>
#include <Base/Exception.h>
#include "Builder.h"
#include "MeshKernel.h"
using namespace MeshCore;
MeshBuilder::MeshBuilder (MeshKernel& kernel) : _meshKernel(kernel), _seq(0)
{
_fSaveTolerance = MeshDefinitions::_fMinPointDistanceD1;
}
MeshBuilder::~MeshBuilder (void)
{
MeshDefinitions::_fMinPointDistanceD1 = _fSaveTolerance;
delete this->_seq;
}
void MeshBuilder::SetTolerance(float fTol)
{
MeshDefinitions::_fMinPointDistanceD1 = fTol;
}
void MeshBuilder::Initialize (unsigned long ctFacets, bool deletion)
{
if (deletion)
{
// Clear the mesh structure and free all memory
_meshKernel.Clear();
// Allocate new memory that is needed later on. If AddFacet() gets called exactly ctFacets times there is no wastage of memory
// otherwise the vector reallocates ~50% of its future memory usage.
// Note: A feature of the std::vector implementation is that it can hold more memory (capacity) than it actually needs (size).
// This usually happens if its elements are added without specifying its final size. Later on it's a bit tricky to free the wasted
// memory. So we're strived to avoid the wastage of memory.
_meshKernel._aclFacetArray.reserve(ctFacets);
// Usually the number of vertices is the half of the number of facets. So we reserve this memory with 10% surcharge
// To save memory we hold an array with iterators that point to the right vertex (insertion order) in the set, instead of
// holding the vertex array twice.
unsigned long ctPoints = ctFacets / 2;
_pointsIterator.reserve((unsigned long)(float(ctPoints)*1.10f));
_ptIdx = 0;
}
else
{
for (MeshPointArray::_TConstIterator it1 = _meshKernel._aclPointArray.begin(); it1 != _meshKernel._aclPointArray.end(); it1++)
{
MeshPointIterator pit = _points.insert(*it1);
_pointsIterator.push_back(pit);
}
_ptIdx = _points.size();
// As we have a copy of our vertices in the set we must clear them from our array now But we can keep its
// memory as we reuse it later on anyway.
_meshKernel._aclPointArray.clear();
// additional memory
unsigned long newCtFacets = _meshKernel._aclFacetArray.size()+ctFacets;
_meshKernel._aclFacetArray.reserve(newCtFacets);
unsigned long ctPoints = newCtFacets / 2;
_pointsIterator.reserve((unsigned long)(float(ctPoints)*1.10f));
}
this->_seq = new Base::SequencerLauncher("create mesh structure...", ctFacets * 2);
}
void MeshBuilder::AddFacet (const MeshGeomFacet& facet, bool takeFlag, bool takeProperty)
{
unsigned char flag = 0;
unsigned long prop = 0;
if (takeFlag)
flag = facet._ucFlag;
if (takeProperty)
prop = facet._ulProp;
AddFacet(facet._aclPoints[0], facet._aclPoints[1], facet._aclPoints[2], facet.GetNormal(), flag, prop);
}
void MeshBuilder::AddFacet (const Base::Vector3f& pt1, const Base::Vector3f& pt2, const Base::Vector3f& pt3, const Base::Vector3f& normal, unsigned char flag, unsigned long prop)
{
Base::Vector3f facetPoints[4] = { pt1, pt2, pt3, normal };
AddFacet(facetPoints, flag, prop);
}
void MeshBuilder::AddFacet (Base::Vector3f* facetPoints, unsigned char flag, unsigned long prop)
{
this->_seq->next(true); // allow to cancel
// adjust circulation direction
if ((((facetPoints[1] - facetPoints[0]) % (facetPoints[2] - facetPoints[0])) * facetPoints[3]) < 0.0f)
{
std::swap(facetPoints[1], facetPoints[2]);
}
MeshFacet mf;
mf._ucFlag = flag;
mf._ulProp = prop;
int i = 0;
for (i = 0; i < 3; i++)
{
MeshPoint pt(facetPoints[i]);
std::set<MeshPoint>::iterator p = _points.find(pt);
if (p == _points.end())
{
mf._aulPoints[i] = _ptIdx;
pt._ulProp = _ptIdx++;
// keep an iterator to the right vertex
MeshPointIterator it = _points.insert(pt);
_pointsIterator.push_back(it);
}
else
mf._aulPoints[i] = p->_ulProp;
}
// check for degenerated facet (one edge has length 0)
if ((mf._aulPoints[0] == mf._aulPoints[1]) || (mf._aulPoints[0] == mf._aulPoints[2]) || (mf._aulPoints[1] == mf._aulPoints[2]))
return;
_meshKernel._aclFacetArray.push_back(mf);
}
void MeshBuilder::SetNeighbourhood ()
{
std::set<Edge> edges;
int facetIdx = 0;
for (MeshFacetArray::_TIterator it = _meshKernel._aclFacetArray.begin(); it != _meshKernel._aclFacetArray.end(); it++)
{
this->_seq->next(true); // allow to cancel
MeshFacet& mf = *it;
for (int i = 0; i < 3; i++)
{
Edge edge(mf._aulPoints[i], mf._aulPoints[(i+1)%3], facetIdx);
std::set<Edge>::iterator e = edges.find(edge);
if (e != edges.end())
{ // edge exists, set neighbourhood
MeshFacet& mf1 = _meshKernel._aclFacetArray[e->facetIdx];
if (mf1._aulPoints[0] == edge.pt1)
{
if (mf1._aulPoints[1] == edge.pt2)
mf1._aulNeighbours[0] = facetIdx;
else
mf1._aulNeighbours[2] = facetIdx;
}
else if (mf1._aulPoints[0] == edge.pt2)
{
if (mf1._aulPoints[1] == edge.pt1)
mf1._aulNeighbours[0] = facetIdx;
else
mf1._aulNeighbours[2] = facetIdx;
}
else
mf1._aulNeighbours[1] = facetIdx;
mf._aulNeighbours[i] = e->facetIdx;
}
else
{ // new edge
edges.insert(edge);
}
}
facetIdx++;
}
}
void MeshBuilder::RemoveUnreferencedPoints()
{
_meshKernel._aclPointArray.SetFlag(MeshPoint::INVALID);
for ( MeshFacetArray::_TConstIterator it = _meshKernel._aclFacetArray.begin(); it != _meshKernel._aclFacetArray.end(); ++it )
{
for ( int i=0; i<3; i++ )
_meshKernel._aclPointArray[it->_aulPoints[i]].ResetInvalid();
}
unsigned long uValidPts = std::count_if(_meshKernel._aclPointArray.begin(), _meshKernel._aclPointArray.end(), std::mem_fun_ref(&MeshPoint::IsValid));
if ( uValidPts < _meshKernel.CountPoints() )
_meshKernel.RemoveInvalids();
}
void MeshBuilder::Finish (bool freeMemory)
{
// now we can resize the vertex array to the exact size and copy the vertices with their correct positions in the array
unsigned long i=0;
_meshKernel._aclPointArray.resize(_pointsIterator.size());
for ( std::vector<MeshPointIterator>::iterator it = _pointsIterator.begin(); it != _pointsIterator.end(); ++it)
_meshKernel._aclPointArray[i++] = *(it->first);
// free all memory of the internal structures
// Note: this scope is needed to free memory immediately
{ std::vector<MeshPointIterator>().swap(_pointsIterator); }
_points.clear();
SetNeighbourhood();
RemoveUnreferencedPoints();
// if AddFacet() has been called more often (or even less) as specified in Initialize() we have a wastage of memory
if ( freeMemory )
{
unsigned long cap = _meshKernel._aclFacetArray.capacity();
unsigned long siz = _meshKernel._aclFacetArray.size();
// wastage of more than 5%
if ( cap > siz+siz/20 )
{
try {
unsigned long i=0;
MeshFacetArray faces(siz);
for ( MeshFacetArray::_TIterator it = _meshKernel._aclFacetArray.begin(); it != _meshKernel._aclFacetArray.end(); ++it )
faces[i++]=*it;
_meshKernel._aclFacetArray.swap(faces);
} catch ( const Base::MemoryException&) {
// sorry, we cannot reduce the memory
}
}
}
_meshKernel.RecalcBoundBox();
}