1+ #include " ../voxelizer.h"
2+ #include " ../volume.h"
3+ #include " ../traversal.h"
4+
5+
6+ #include < gp_Pln.hxx>
7+ #include < Bnd_Box.hxx>
8+ #include < BRepBndLib.hxx>
9+ #include < BRepBuilderAPI_MakeFace.hxx>
10+ #include < BRepMesh_IncrementalMesh.hxx>
11+
12+ #include < Eigen/Dense>
13+
14+ #include < gtest/gtest.h>
15+
16+ TEST (NormalEstimation, EigenPCA) {
17+ static Eigen::Vector3f Z (0 , 0 , 1 );
18+ Eigen::MatrixXf points (10 , 3 );
19+ points.setRandom ();
20+ points.col (2 ).setZero ();
21+
22+ Eigen::MatrixXf centered = points.rowwise () - points.colwise ().mean ();
23+ Eigen::MatrixXf cov = centered.adjoint () * centered;
24+ Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig (cov);
25+
26+ ASSERT_FLOAT_EQ (std::abs (eig.eigenvectors ().col (0 ).dot (Z)), 1 .);
27+ }
28+
29+
30+ TEST (NormalEstimation, OCC) {
31+ gp_Pln p (1 , 2 , 3 , 4 );
32+ auto face = BRepBuilderAPI_MakeFace (p, -1 , 1 , -1 , 1 ).Face ();
33+ BRepMesh_IncrementalMesh (face, 0.1 );
34+
35+ auto surf = BRep_Tool::Surface (face);
36+ auto dir = Handle_Geom_Plane::DownCast (surf)->Position ().Direction ();
37+
38+ Eigen::Vector3f norm (dir.X (), dir.Y (), dir.Z ());
39+ std::cout << " Face normal " << norm << std::endl;
40+
41+ Bnd_Box B;
42+ BRepBndLib::AddClose (face, B);
43+
44+ double d = 0.05 ;
45+ double x0, y0, z0, x1, y1, z1;
46+ B.Get (x0, y0, z0, x1, y1, z1);
47+
48+ auto storage = new chunked_voxel_storage<bit_t >(
49+ x0 - d,
50+ y0 - d,
51+ z0 - d, d,
52+ (x1 - x0) / d + 2 ,
53+ (y1 - y0) / d + 2 ,
54+ (z1 - z0) / d + 2 ,
55+ 64 );
56+ auto vox = voxelizer (face, storage);
57+ vox.Convert ();
58+
59+ std::cout << " count " << storage->count () << std::endl;
60+
61+ auto it = storage->begin ();
62+ std::advance (it, storage->count () / 2 );
63+
64+ std::cout << " center " << (*it).format () << std::endl;
65+
66+ for (int i = 1 ; i <= 10 ; i += 2 ) {
67+
68+ visitor<26 > vis;
69+ vis.max_depth = 0.1 * i / d;
70+
71+ std::cout << " md " << (0.1 * i) << std::endl;
72+
73+ std::vector<float > coords;
74+
75+ auto selection = storage->empty_copy ();
76+
77+ vis ([&coords, &selection](const tagged_index& pos) {
78+ if (pos.which == tagged_index::VOXEL) {
79+ coords.push_back (pos.pos .get (0 ));
80+ coords.push_back (pos.pos .get (1 ));
81+ coords.push_back (pos.pos .get (2 ));
82+ selection->Set (pos.pos );
83+ }
84+ else {
85+ throw std::runtime_error (" Unexpected" );
86+ }
87+ }, storage, *it);
88+
89+ /* {
90+ std::ofstream ofs("m2.obj");
91+ ((chunked_voxel_storage<bit_t>*)selection)->obj_export(ofs);
92+ }
93+
94+ storage->boolean_subtraction_inplace(selection);
95+
96+ {
97+ std::ofstream ofs("m1.obj");
98+ storage->obj_export(ofs);
99+ }*/
100+
101+ std::cout << " neighbours " << (coords.size () / 3 ) << std::endl;
102+
103+ Eigen::MatrixXf points = Eigen::Map<Eigen::MatrixXf>(coords.data (), 3 , coords.size () / 3 ).transpose ();
104+
105+ Eigen::MatrixXf centered = points.rowwise () - points.colwise ().mean ();
106+ Eigen::MatrixXf cov = centered.adjoint () * centered;
107+ Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig (cov);
108+
109+ auto estimated = eig.eigenvectors ().col (0 );
110+
111+ std::cout << estimated << std::endl;
112+
113+ auto angle = std::acos (estimated.dot (norm));
114+ if (angle > M_PI / 2 ) {
115+ angle = M_PI - angle;
116+ }
117+ auto angle_degrees = angle / M_PI * 180 .;
118+
119+ std::cout << " angle " << angle_degrees << " d" << std::endl;
120+
121+ ASSERT_LT (angle_degrees, 90 .);
122+ }
123+ }
0 commit comments