ENH: readSTLASCII: single precision point merging

This commit is contained in:
mattijs
2011-12-08 16:23:09 +00:00
parent 523f8d6915
commit d21091c788
6 changed files with 340 additions and 95 deletions

View File

@ -23,25 +23,25 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "mergePoints.H"
#include "SortableList.H"
#include "ListOps.H" #include "ListOps.H"
#include "point.H"
#include "Field.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::mergePoints template<class Type>
Foam::label Foam::mergePoints
( (
const UList<point>& points, const UList<Type>& points,
const scalar mergeTol, const scalar mergeTol,
const bool verbose, const bool verbose,
labelList& pointMap, labelList& pointMap,
List<point>& newPoints, const Type& origin
const point& origin
) )
{ {
point compareOrigin = origin; Type compareOrigin = origin;
if (origin == point(VGREAT, VGREAT, VGREAT)) if (origin == Type::max)
{ {
if (points.size()) if (points.size())
{ {
@ -53,12 +53,9 @@ bool Foam::mergePoints
pointMap.setSize(points.size()); pointMap.setSize(points.size());
pointMap = -1; pointMap = -1;
// Storage for merged points
newPoints.setSize(points.size());
if (points.empty()) if (points.empty())
{ {
return false; return points.size();
} }
// We're comparing distance squared to origin first. // We're comparing distance squared to origin first.
@ -70,33 +67,56 @@ bool Foam::mergePoints
// x^2+y^2+z^2 + 2*mergeTol*(x+z+y) + mergeTol^2*... // x^2+y^2+z^2 + 2*mergeTol*(x+z+y) + mergeTol^2*...
// so the difference will be 2*mergeTol*(x+y+z) // so the difference will be 2*mergeTol*(x+y+z)
const scalar mergeTolSqr = sqr(mergeTol); const scalar mergeTolSqr = Foam::sqr(scalar(mergeTol));
// Sort points by magSqr // Sort points by magSqr
const pointField d(points - compareOrigin); const Field<Type> d(points - compareOrigin);
SortableList<scalar> sortedMagSqr(magSqr(d));
scalarField sortedTol(points.size()); List<scalar> magSqrD(d.size());
forAll(sortedMagSqr.indices(), sortI) forAll(d, pointI)
{ {
const point& pt = d[sortedMagSqr.indices()[sortI]]; magSqrD[pointI] = magSqr(d[pointI]);
}
labelList order;
sortedOrder(magSqrD, order);
Field<scalar> sortedTol(points.size());
forAll(order, sortI)
{
label pointI = order[sortI];
// Convert to scalar precision
const point pt
(
scalar(d[pointI].x()),
scalar(d[pointI].y()),
scalar(d[pointI].z())
);
sortedTol[sortI] = 2*mergeTol*(mag(pt.x())+mag(pt.y())+mag(pt.z())); sortedTol[sortI] = 2*mergeTol*(mag(pt.x())+mag(pt.y())+mag(pt.z()));
} }
bool hasMerged = false;
label newPointI = 0; label newPointI = 0;
// Handle 0th point separately (is always unique) // Handle 0th point separately (is always unique)
label pointI = sortedMagSqr.indices()[0]; label pointI = order[0];
pointMap[pointI] = newPointI; pointMap[pointI] = newPointI++;
newPoints[newPointI++] = points[pointI];
for (label sortI = 1; sortI < sortedMagSqr.size(); sortI++) for (label sortI = 1; sortI < order.size(); sortI++)
{ {
// Get original point index // Get original point index
label pointI = sortedMagSqr.indices()[sortI]; label pointI = order[sortI];
const scalar mag2 = magSqrD[order[sortI]];
// Convert to scalar precision
const point pt
(
scalar(points[pointI].x()),
scalar(points[pointI].y()),
scalar(points[pointI].z())
);
// Compare to previous points to find equal one. // Compare to previous points to find equal one.
label equalPointI = -1; label equalPointI = -1;
@ -105,17 +125,19 @@ bool Foam::mergePoints
( (
label prevSortI = sortI - 1; label prevSortI = sortI - 1;
prevSortI >= 0 prevSortI >= 0
&& mag && (mag(magSqrD[order[prevSortI]] - mag2) <= sortedTol[sortI]);
(
sortedMagSqr[prevSortI]
- sortedMagSqr[sortI]
) <= sortedTol[sortI];
prevSortI-- prevSortI--
) )
{ {
label prevPointI = sortedMagSqr.indices()[prevSortI]; label prevPointI = order[prevSortI];
const point prevPt
(
scalar(points[prevPointI].x()),
scalar(points[prevPointI].y()),
scalar(points[prevPointI].z())
);
if (magSqr(points[pointI] - points[prevPointI]) <= mergeTolSqr) if (magSqr(pt - prevPt) <= mergeTolSqr)
{ {
// Found match. // Found match.
equalPointI = prevPointI; equalPointI = prevPointI;
@ -130,8 +152,6 @@ bool Foam::mergePoints
// Same coordinate as equalPointI. Map to same new point. // Same coordinate as equalPointI. Map to same new point.
pointMap[pointI] = pointMap[equalPointI]; pointMap[pointI] = pointMap[equalPointI];
hasMerged = true;
if (verbose) if (verbose)
{ {
Pout<< "Foam::mergePoints : Merging points " Pout<< "Foam::mergePoints : Merging points "
@ -144,14 +164,41 @@ bool Foam::mergePoints
else else
{ {
// Differs. Store new point. // Differs. Store new point.
pointMap[pointI] = newPointI; pointMap[pointI] = newPointI++;
newPoints[newPointI++] = points[pointI];
} }
} }
newPoints.setSize(newPointI); return newPointI;
}
return hasMerged;
template<class Type>
bool Foam::mergePoints
(
const UList<Type>& points,
const scalar mergeTol,
const bool verbose,
labelList& pointMap,
List<Type>& newPoints,
const Type& origin = Type::zero
)
{
label nUnique = mergePoints
(
points,
mergeTol,
verbose,
pointMap,
origin
);
newPoints.setSize(nUnique);
forAll(pointMap, pointI)
{
newPoints[pointMap[pointI]] = points[pointI];
}
return (nUnique != points.size());
} }

View File

@ -32,8 +32,8 @@ SourceFiles
#ifndef mergePoints_H #ifndef mergePoints_H
#define mergePoints_H #define mergePoints_H
#include "scalarField.H" #include "scalar.H"
#include "pointField.H" #include "labelList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -44,23 +44,41 @@ namespace Foam
Function mergePoints Declaration Function mergePoints Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
//- Sort & merge points. All points closer than/equal mergeTol get merged. //- Sorts and merges points. All points closer than/equal mergeTol get merged.
// Outputs the new unique points and a map from old to new. Returns // Returns the number of unique points and a map from old to new.
// true if anything merged, false otherwise. template<class Type>
bool mergePoints label mergePoints
( (
const UList<point>& points, const UList<Type>& points,
const scalar mergeTol, const scalar mergeTol,
const bool verbose, const bool verbose,
labelList& pointMap, labelList& pointMap,
List<point>& newPoints, const Type& origin = Type::zero
const point& origin = point::zero );
//- Sorts and merges points. Determines new points. Returns true if anything
// merged (though newPoints still sorted even if not merged).
template<class Type>
bool mergePoints
(
const UList<Type>& points,
const scalar mergeTol,
const bool verbose,
labelList& pointMap,
List<Type>& newPoints,
const Type& origin = Type::zero
); );
} // End namespace Foam } // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
# include "mergePoints.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif #endif
// ************************************************************************* // // ************************************************************************* //

View File

@ -0,0 +1,70 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Vector of floats.
\*---------------------------------------------------------------------------*/
#include "floatVector.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
template<>
const char* const floatVector::typeName = "floatVector";
template<>
const char* floatVector::componentNames[] = {"x", "y", "z"};
template<>
const floatVector floatVector::zero(0, 0, 0);
template<>
const floatVector floatVector::one(1, 1, 1);
template<>
const floatVector floatVector::max
(
floatScalarVGREAT,
floatScalarVGREAT,
floatScalarVGREAT
);
template<>
const floatVector floatVector::min
(
-floatScalarVGREAT,
-floatScalarVGREAT,
-floatScalarVGREAT
);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -0,0 +1,64 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM 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 General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Typedef
Foam::floatVector
Description
A float version of vector
SourceFiles
floatVector.C
\*---------------------------------------------------------------------------*/
#ifndef floatVector_H
#define floatVector_H
#include "Vector.H"
#include "contiguous.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
typedef Vector<float> floatVector;
//- Data associated with floatVector type are contiguous
template<>
inline bool contiguous<floatVector>() {return true;}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -33,8 +33,10 @@ License
#include "IFstream.H" #include "IFstream.H"
#include "triSurface.H" #include "triSurface.H"
#include "STLpoint.H" #include "floatVector.H"
#include "OSspecific.H" #include "OSspecific.H"
#include "mergePoints.H"
//#include "memInfo.H"
using namespace Foam; using namespace Foam;
@ -77,8 +79,8 @@ class STLLexer
label lineNo_; label lineNo_;
word startError_; word startError_;
DynamicList<STLpoint> STLpoints_; DynamicList<floatVector> STLpoints_;
//DynamicList<STLpoint> STLnormals_; //DynamicList<floatVector > STLnormals_;
DynamicList<label> STLlabels_; DynamicList<label> STLlabels_;
HashTable<label, word> STLsolidNames_; HashTable<label, word> STLsolidNames_;
@ -103,12 +105,12 @@ public:
return nTriangles_; return nTriangles_;
} }
DynamicList<STLpoint>& STLpoints() DynamicList<floatVector>& STLpoints()
{ {
return STLpoints_; return STLpoints_;
} }
//DynamicList<STLpoint>& STLnormals() //DynamicList<floatVector>& STLnormals()
//{ //{
// return STLnormals_; // return STLnormals_;
//} //}
@ -202,8 +204,8 @@ endsolid {space}("endsolid"|"ENDSOLID")({some_space}{word})*
// End of read character pointer returned by strtof // End of read character pointer returned by strtof
// char* endPtr; // char* endPtr;
STLpoint normal; floatVector normal;
STLpoint vertex; floatVector vertex;
label cmpt = 0; // component index used for reading vertex label cmpt = 0; // component index used for reading vertex
static const char* stateNames[7] = static const char* stateNames[7] =
@ -387,16 +389,25 @@ bool triSurface::readSTLASCII(const fileName& STLfileName)
<< exit(FatalError); << exit(FatalError);
} }
//memInfo memStat;
//memStat.update();
//Pout<< "At start:" << memStat.rss() << endl;
// Create the lexer obtaining the approximate number of vertices in the STL // Create the lexer obtaining the approximate number of vertices in the STL
// from the file size // from the file size
STLLexer lexer(&STLstream.stdStream(), Foam::fileSize(STLfileName)/400); STLLexer lexer(&STLstream.stdStream(), Foam::fileSize(STLfileName)/400);
while (lexer.lex() != 0) while (lexer.lex() != 0)
{} {}
DynamicList<STLpoint>& STLpoints = lexer.STLpoints(); //memStat.update();
//Pout<< "After lexing:" << memStat.rss() << endl;
DynamicList<floatVector>& STLpoints = lexer.STLpoints();
DynamicList<label>& STLlabels = lexer.STLlabels();
/* /*
DynamicList<STLpoint>& STLnormals = lexer.STLnormals(); DynamicList<floatVector>& STLnormals = lexer.STLnormals();
if (STLpoints.size() != 3*STLnormals.size()) if (STLpoints.size() != 3*STLnormals.size())
{ {
@ -410,35 +421,51 @@ bool triSurface::readSTLASCII(const fileName& STLfileName)
} }
*/ */
pointField rawPoints(STLpoints.size()); labelList pointMap;
label nUniquePoints = mergePoints
(
STLpoints,
100*SMALL, // merge distance
false, // verbose
pointMap
);
forAll(rawPoints, i) //memStat.update();
{ //Pout<< "After merging:" << memStat.rss() << endl;
rawPoints[i] = STLpoints[i];
}
STLpoints.clear();
pointField& sp = storedPoints();
setSize(lexer.nTriangles()); setSize(lexer.nTriangles());
DynamicList<label>& STLlabels = lexer.STLlabels(); sp.setSize(nUniquePoints);
forAll(STLpoints, pointI)
{
const floatVector& pt = STLpoints[pointI];
sp[pointMap[pointI]] = vector
(
scalar(pt.x()),
scalar(pt.y()),
scalar(pt.z())
);
}
// Assign triangles // Assign triangles
label pointi = 0; label pointI = 0;
forAll(*this, i) forAll(*this, i)
{ {
operator[](i)[0] = pointi++; operator[](i)[0] = pointMap[pointI++];
operator[](i)[1] = pointi++; operator[](i)[1] = pointMap[pointI++];
operator[](i)[2] = pointi++; operator[](i)[2] = pointMap[pointI++];
operator[](i).region() = STLlabels[i]; operator[](i).region() = STLlabels[i];
} }
//memStat.update();
//Pout<< "After assigning:" << memStat.rss() << endl;
STLpoints.clear();
STLlabels.clear(); STLlabels.clear();
// Assign coordinates
storedPoints().transfer(rawPoints);
// Stitch all points within SMALL meters.
stitchTriangles();
// Convert solidNames into regionNames // Convert solidNames into regionNames
patches_.setSize(lexer.STLsolidNames().size()); patches_.setSize(lexer.STLsolidNames().size());
@ -457,6 +484,9 @@ bool triSurface::readSTLASCII(const fileName& STLfileName)
// Fill in the missing information in the patches // Fill in the missing information in the patches
setDefaultPatches(); setDefaultPatches();
//memStat.update();
//Pout<< "After patchifying:" << memStat.rss() << endl;
return true; return true;
} }

View File

@ -28,7 +28,8 @@ License
#include "IFstream.H" #include "IFstream.H"
#include "OSspecific.H" #include "OSspecific.H"
#include "gzstream.h" #include "gzstream.h"
#include "floatVector.H"
#include "mergePoints.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
@ -94,40 +95,55 @@ bool Foam::triSurface::readSTLBINARY(const fileName& STLfileName)
// Everything OK so go ahead and read the triangles. // Everything OK so go ahead and read the triangles.
// Allocate storage for raw points // Allocate storage for raw points
pointField rawPoints(3*nTris); List<floatVector> STLpoints(3*nTris);
// Allocate storage for triangles
setSize(nTris); setSize(nTris);
label rawPointI = 0; label pointI = 0;
// Read the triangles for (label i = 0; i < nTris; i++)
forAll(*this, i)
{ {
// Read an STL triangle // Read an STL triangle
STLtriangle stlTri(STLfile); STLtriangle stlTri(STLfile);
// Set the rawPoints to the vertices of the STL triangle // Set the STLpoints to the vertices of the STL triangle
// and set the point labels of the labelledTri STLpoints[pointI++] = stlTri.a();
rawPoints[rawPointI] = stlTri.a(); STLpoints[pointI++] = stlTri.b();
operator[](i)[0] = rawPointI++; STLpoints[pointI++] = stlTri.c();
rawPoints[rawPointI] = stlTri.b();
operator[](i)[1] = rawPointI++;
rawPoints[rawPointI] = stlTri.c();
operator[](i)[2] = rawPointI++;
operator[](i).region() = stlTri.region(); operator[](i).region() = stlTri.region();
} }
//STLfile.close(); // Stitch points
labelList pointMap;
label nUniquePoints = mergePoints
(
STLpoints,
10*SMALL, // merge distance
false, // verbose
pointMap // old to new
);
// Assign coordinates pointField& sp = storedPoints();
storedPoints().transfer(rawPoints);
// Stitch all points within SMALL meters. sp.setSize(nUniquePoints);
stitchTriangles(); forAll(STLpoints, pointI)
{
const floatVector& pt = STLpoints[pointI];
sp[pointMap[pointI]] = vector
(
scalar(pt.x()),
scalar(pt.y()),
scalar(pt.z())
);
}
// Assign triangles
pointI = 0;
forAll(*this, i)
{
operator[](i)[0] = pointMap[pointI++];
operator[](i)[1] = pointMap[pointI++];
operator[](i)[2] = pointMap[pointI++];
}
return true; return true;
} }