Skip to content

Commit 9bb6e8a

Browse files
authored
VertexIdentifier class extracted from fromBinaryStl (#150)
* VertexIdentifier class extracted from fromBinaryStl * fix memcpy * #include "MRphmap.h" moved in the header * fromPointTriples function added
1 parent e04b543 commit 9bb6e8a

File tree

9 files changed

+221
-105
lines changed

9 files changed

+221
-105
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include "MRIdentifyVertices.h"
2+
#include "MRTimer.h"
3+
#include "MRPch/MRTBB.h"
4+
5+
namespace MR
6+
{
7+
8+
namespace MeshBuilder
9+
{
10+
11+
void VertexIdentifier::reserve( size_t numTris )
12+
{
13+
hmap_.reserve( numTris / 2 ); // there should be about twice more triangles than vertices
14+
tris_.reserve( numTris );
15+
}
16+
17+
void VertexIdentifier::addTriangles( const std::vector<ThreePoints> & buffer )
18+
{
19+
MR_TIMER
20+
assert ( tris_.size() + buffer.size() <= tris_.capacity() );
21+
vertsInHMap_.resize( buffer.size() );
22+
23+
for (;;)
24+
{
25+
auto buckets0 = hmap_.bucket_count();
26+
27+
const auto subcnt = hmap_.subcnt();
28+
tbb::parallel_for( tbb::blocked_range<size_t>( 0, subcnt, 1 ), [&]( const tbb::blocked_range<size_t> & range )
29+
{
30+
assert( range.begin() + 1 == range.end() );
31+
for ( size_t myPartId = range.begin(); myPartId < range.end(); ++myPartId )
32+
{
33+
for ( size_t j = 0; j < buffer.size(); ++j )
34+
{
35+
const auto & st = buffer[j];
36+
auto & it = vertsInHMap_[j];
37+
for ( int k = 0; k < 3; ++k )
38+
{
39+
const auto & p = st[k];
40+
auto hashval = hmap_.hash( p );
41+
auto idx = hmap_.subidx( hashval );
42+
if ( idx != myPartId )
43+
continue;
44+
it[k] = &hmap_[ p ];
45+
}
46+
}
47+
}
48+
} );
49+
50+
if ( buckets0 == hmap_.bucket_count() )
51+
break; // the number of buckets has not changed - all pointers are valid
52+
}
53+
54+
for ( size_t j = 0; j < buffer.size(); ++j )
55+
{
56+
const auto & st = buffer[j];
57+
const auto & it = vertsInHMap_[j];
58+
for ( int k = 0; k < 3; ++k )
59+
{
60+
if ( !it[k]->valid() )
61+
{
62+
*it[k] = VertId( (int)points_.size() );
63+
points_.push_back( st[k] );
64+
}
65+
}
66+
tris_.emplace_back( *it[0], *it[1], *it[2], FaceId( int( tris_.size() ) ) );
67+
}
68+
}
69+
70+
} //namespace MeshBuilder
71+
72+
} //namespace MR

source/MRMesh/MRIdentifyVertices.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#pragma once
2+
3+
#include "MRMeshBuilderTypes.h"
4+
#include "MRVector3.h"
5+
#include "MRVector.h"
6+
#include "MRphmap.h"
7+
#include <cstring>
8+
9+
namespace MR
10+
{
11+
12+
namespace MeshBuilder
13+
{
14+
15+
/// this makes bit-wise comparison of two Vector3f's thus making two NaNs equal
16+
struct equalVector3f
17+
{
18+
bool operator() ( const Vector3f & a, const Vector3f & b ) const
19+
{
20+
static_assert( sizeof( Vector3f ) == 12 );
21+
char ax[12], bx[12];
22+
std::memcpy( ax, &a, 12 );
23+
std::memcpy( bx, &b, 12 );
24+
return std::memcmp( ax, bx, 12 ) == 0;
25+
}
26+
};
27+
28+
/// this class is responsible for giving a unique id to each vertex with distinct coordinates
29+
class VertexIdentifier
30+
{
31+
public:
32+
/// prepare identification of vertices from given this number of triangles
33+
MRMESH_API void reserve( size_t numTris );
34+
/// identifies vertices from a chunk of triangles
35+
MRMESH_API void addTriangles( const std::vector<ThreePoints> & buffer );
36+
/// returns the number of triangles added so far
37+
size_t numTris() const { return tris_.size(); }
38+
/// obtains triangles with vertex ids
39+
std::vector<MeshBuilder::Triangle> takeTris() { return std::move( tris_ ); }
40+
/// obtains coordinates of unique points in the order of vertex ids
41+
VertCoords takePoints() { return std::move( points_ ); }
42+
43+
private:
44+
using VertInHMap = std::array<VertId*, 3>;
45+
std::vector<VertInHMap> vertsInHMap_;
46+
using HMap = phmap::parallel_flat_hash_map<Vector3f, VertId, phmap::priv::hash_default_hash<Vector3f>, equalVector3f>;
47+
HMap hmap_;
48+
std::vector<MeshBuilder::Triangle> tris_;
49+
VertCoords points_;
50+
};
51+
52+
} //namespace MeshBuilder
53+
54+
} //namespace MR

source/MRMesh/MRMesh.vcxproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
<ClInclude Include="MRHeapBytes.h" />
5656
<ClInclude Include="MRHistoryAction.h" />
5757
<ClInclude Include="MRHistoryStore.h" />
58+
<ClInclude Include="MRIdentifyVertices.h" />
5859
<ClInclude Include="MRImage.h" />
5960
<ClInclude Include="MRImageLoad.h" />
6061
<ClInclude Include="MRImageSave.h" />
@@ -71,6 +72,7 @@
7172
<ClInclude Include="MRMatrix.h" />
7273
<ClInclude Include="MRMatrix2.h" />
7374
<ClInclude Include="MRMatrix4.h" />
75+
<ClInclude Include="MRMeshBuilderTypes.h" />
7476
<ClInclude Include="MRMeshCollidePrecise.h" />
7577
<ClInclude Include="MRObjectLinesHolder.h" />
7678
<ClInclude Include="MRObjectMeshHolder.h" />
@@ -287,6 +289,7 @@
287289
<ClCompile Include="MRFloatGridComponents.cpp" />
288290
<ClCompile Include="MRGridSampling.cpp" />
289291
<ClCompile Include="MRHistoryStore.cpp" />
292+
<ClCompile Include="MRIdentifyVertices.cpp" />
290293
<ClCompile Include="MRImageLoad.cpp" />
291294
<ClCompile Include="MRImageSave.cpp" />
292295
<ClCompile Include="MRIntersection.cpp" />

source/MRMesh/MRMesh.vcxproj.filters

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@
7676
<Filter Include="Source Files\DataModel\ModelHolder">
7777
<UniqueIdentifier>{2e5c8a08-b968-4732-be0c-9b07bb4b051e}</UniqueIdentifier>
7878
</Filter>
79+
<Filter Include="Source Files\MeshBuilder">
80+
<UniqueIdentifier>{c83e4212-7072-40c2-8354-827c896c1628}</UniqueIdentifier>
81+
</Filter>
7982
</ItemGroup>
8083
<ItemGroup>
8184
<ClInclude Include="MRMeshFwd.h">
@@ -84,9 +87,6 @@
8487
<ClInclude Include="MRId.h">
8588
<Filter>Source Files</Filter>
8689
</ClInclude>
87-
<ClInclude Include="MRMeshBuilder.h">
88-
<Filter>Source Files</Filter>
89-
</ClInclude>
9090
<ClInclude Include="MRMeshTopology.h">
9191
<Filter>Source Files</Filter>
9292
</ClInclude>
@@ -753,14 +753,20 @@
753753
<ClInclude Include="MRPointObject.h">
754754
<Filter>Source Files\DataModel\Features</Filter>
755755
</ClInclude>
756+
<ClInclude Include="MRMeshBuilder.h">
757+
<Filter>Source Files\MeshBuilder</Filter>
758+
</ClInclude>
759+
<ClInclude Include="MRIdentifyVertices.h">
760+
<Filter>Source Files\MeshBuilder</Filter>
761+
</ClInclude>
762+
<ClInclude Include="MRMeshBuilderTypes.h">
763+
<Filter>Source Files\MeshBuilder</Filter>
764+
</ClInclude>
756765
</ItemGroup>
757766
<ItemGroup>
758767
<ClCompile Include="MRId.cpp">
759768
<Filter>Source Files</Filter>
760769
</ClCompile>
761-
<ClCompile Include="MRMeshBuilder.cpp">
762-
<Filter>Source Files</Filter>
763-
</ClCompile>
764770
<ClCompile Include="MRMeshTopology.cpp">
765771
<Filter>Source Files</Filter>
766772
</ClCompile>
@@ -776,9 +782,6 @@
776782
<ClCompile Include="MRMeshDelete.cpp">
777783
<Filter>Source Files</Filter>
778784
</ClCompile>
779-
<ClCompile Include="MRMeshBuildDeleteTest.cpp">
780-
<Filter>Source Files</Filter>
781-
</ClCompile>
782785
<ClCompile Include="MRObject.cpp">
783786
<Filter>Source Files\DataModel</Filter>
784787
</ClCompile>
@@ -1271,6 +1274,15 @@
12711274
<ClCompile Include="MRPointObject.cpp">
12721275
<Filter>Source Files\DataModel\Features</Filter>
12731276
</ClCompile>
1277+
<ClCompile Include="MRMeshBuilder.cpp">
1278+
<Filter>Source Files\MeshBuilder</Filter>
1279+
</ClCompile>
1280+
<ClCompile Include="MRMeshBuildDeleteTest.cpp">
1281+
<Filter>Source Files\MeshBuilder</Filter>
1282+
</ClCompile>
1283+
<ClCompile Include="MRIdentifyVertices.cpp">
1284+
<Filter>Source Files\MeshBuilder</Filter>
1285+
</ClCompile>
12741286
</ItemGroup>
12751287
<ItemGroup>
12761288
<None Include="..\.editorconfig" />

source/MRMesh/MRMeshBuilder.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "MRMeshBuilder.h"
2+
#include "MRIdentifyVertices.h"
23
#include "MRMeshDelete.h"
34
#include "MRRingIterator.h"
45
#include "MRTimer.h"
@@ -815,6 +816,18 @@ MeshTopology fromVertexTriples( const std::vector<VertId> & vertTriples )
815816
return fromTriangles( tris );
816817
}
817818

819+
Mesh fromPointTriples( const std::vector<ThreePoints> & posTriples )
820+
{
821+
MR_TIMER
822+
VertexIdentifier vi;
823+
vi.reserve( posTriples.size() );
824+
vi.addTriangles( posTriples );
825+
Mesh res;
826+
res.points = vi.takePoints();
827+
res.topology = fromTriangles( vi.takeTris() );
828+
return res;
829+
}
830+
818831
// check non-manifold vertices resolving
819832
TEST( MRMesh, duplicateNonManifoldVertices )
820833
{

source/MRMesh/MRMeshBuilder.h

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
#pragma once
22

3-
#include "MRMeshFwd.h"
4-
#include "MRId.h"
5-
#include "MRMeshTopology.h"
6-
#include "MRVector.h"
7-
#include <vector>
3+
#include "MRMeshBuilderTypes.h"
4+
#include "MRMesh.h"
85

96
namespace MR
107
{
@@ -34,20 +31,7 @@ namespace MR
3431
namespace MeshBuilder
3532
{
3633

37-
struct Triangle
38-
{
39-
Triangle() noexcept = default;
40-
Triangle( VertId a, VertId b, VertId c, FaceId f ) : f(f) { v[0] = a; v[1] = b; v[2] = c; }
41-
VertId v[3];
42-
FaceId f;
43-
44-
bool operator==( const Triangle& other )const
45-
{
46-
return f == other.f && v[0] == other.v[0] && v[1] == other.v[1] && v[2] == other.v[2];
47-
}
48-
};
49-
50-
// construct mesh from a set of triangles with given ids;
34+
// construct mesh topology from a set of triangles with given ids;
5135
// if skippedTris is given then it receives all input triangles not added in the resulting topology
5236
MRMESH_API MeshTopology fromTriangles( const std::vector<Triangle> & tris, std::vector<Triangle> * skippedTris = nullptr );
5337

@@ -62,15 +46,19 @@ struct VertDuplication
6246
MRMESH_API size_t duplicateNonManifoldVertices( std::vector<Triangle>& tris,
6347
std::vector<VertDuplication>* dups = nullptr );
6448

65-
// construct mesh from a set of triangles with given ids;
49+
// construct mesh topology from a set of triangles with given ids;
6650
// unlike simple fromTriangles() it tries to resolve non-manifold vertices by creating duplicate vertices
6751
MRMESH_API MeshTopology fromTrianglesDuplicatingNonManifoldVertices( const std::vector<Triangle> & tris,
6852
std::vector<VertDuplication> * dups = nullptr,
6953
std::vector<Triangle> * skippedTris = nullptr );
7054

71-
// construct mesh from vertex-index triples
55+
// construct mesh topology from vertex-index triples
7256
MRMESH_API MeshTopology fromVertexTriples( const std::vector<VertId> & vertTriples );
7357

58+
// construct mesh from point triples;
59+
// all coinciding points are given the same VertId in the result
60+
MRMESH_API Mesh fromPointTriples( const std::vector<ThreePoints> & posTriples );
61+
7462
// a part of a whole mesh to be constructed
7563
struct MeshPiece
7664
{
@@ -80,7 +68,7 @@ struct MeshPiece
8068
std::vector<Triangle> tris; // remaining triangles, not in topology
8169
};
8270

83-
// construct mesh in parallel from given disjoint mesh pieces (which do not have any shared vertex)
71+
// construct mesh topology in parallel from given disjoint mesh pieces (which do not have any shared vertex)
8472
// and some additional triangles that join the pieces
8573
MRMESH_API MeshTopology fromDisjointMeshPieces( const std::vector<MeshPiece> & pieces, VertId maxVertId, FaceId maxFaceId,
8674
std::vector<Triangle> & borderTris ); //< on output borderTris will contain not added triangles
@@ -102,7 +90,7 @@ struct FaceRecord
10290
int lastVertex = 0;
10391
};
10492

105-
// construct mesh from face soup, where each face can have arbitrary degree (not only triangles)
93+
// construct mesh topology from face soup, where each face can have arbitrary degree (not only triangles)
10694
MRMESH_API MeshTopology fromFaceSoup( const std::vector<VertId> & verts, std::vector<FaceRecord> & faces );
10795

10896
} //namespace MeshBuilder

source/MRMesh/MRMeshBuilderTypes.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#include "MRId.h"
4+
#include <array>
5+
6+
namespace MR
7+
{
8+
9+
namespace MeshBuilder
10+
{
11+
12+
/// three vector3-coordinates describing a triangle
13+
using ThreePoints = std::array<Vector3f, 3>;
14+
15+
/// mesh triangle represented by its three vertices and by its face ID
16+
struct Triangle
17+
{
18+
Triangle() noexcept = default;
19+
Triangle( VertId a, VertId b, VertId c, FaceId f ) : f(f) { v[0] = a; v[1] = b; v[2] = c; }
20+
VertId v[3];
21+
FaceId f;
22+
23+
bool operator==( const Triangle& other )const
24+
{
25+
return f == other.f && v[0] == other.v[0] && v[1] == other.v[1] && v[2] == other.v[2];
26+
}
27+
};
28+
29+
} //namespace MeshBuilder
30+
31+
} //namespace MR

0 commit comments

Comments
 (0)