@@ -2448,48 +2448,95 @@ class op_normal_estimate : public voxel_operation {
24482448 auto result = voxels->empty_copy_as (&fmt);
24492449
24502450 const int max_depth = scope.get_value <int >(" max_depth" );
2451- auto box_dim = 1 + max_depth * 2 ;
24522451
2453- std::vector<float > coords;
2454- coords.reserve (box_dim * box_dim * box_dim);
2452+ // scoped lock around setting result values
2453+ auto result_set = [result](const vec_n<3 >& ijk, normal_and_curvature<int16_t >* v) {
2454+ static std::mutex m;
2455+ std::lock_guard<std::mutex> lock{ m };
2456+ result->Set (ijk, v);
2457+ };
24552458
2456- for (auto it = voxels->begin (); it != voxels->end (); ++it) {
2457- visitor<26 > vis;
2458- vis.max_depth = max_depth;
2459+ // lambda wrapper around the 3-dim loop to
2460+ // either call directly or invoke from worker
2461+ // threads. In the last case the z-coord
2462+ // of the voxel will be used to skip processing
2463+ // within a thread based on the modelo with the
2464+ // thread count.
2465+ auto process = [
2466+ &result_set, voxels, max_depth
2467+ ](const boost::optional<size_t >& num_threads = boost::none, const boost::optional<size_t >& thread_id = boost::none)
2468+ {
2469+ uint32_t u32 ;
2470+ normal_and_curvature<int16_t > v;
24592471
2460- coords.clear ();
2461-
2462- vis ([&coords](const tagged_index& pos) {
2463- if (pos.which == tagged_index::VOXEL) {
2464- coords.push_back (pos.pos .get (0 ));
2465- coords.push_back (pos.pos .get (1 ));
2466- coords.push_back (pos.pos .get (2 ));
2467- } else {
2468- throw std::runtime_error (" Unexpected" );
2472+ std::vector<float > coords;
2473+ auto box_dim = 1 + max_depth * 2 ;
2474+ coords.reserve (box_dim * box_dim * box_dim);
2475+
2476+ for (auto it = voxels->begin (); it != voxels->end (); ++it) {
2477+ if (num_threads && thread_id && ((*it).get <2 >() % *num_threads) != *thread_id) {
2478+ continue ;
24692479 }
2470- }, voxels, *it);
24712480
2472- Eigen::MatrixXf points = Eigen::Map<Eigen::MatrixXf>(coords.data (), 3 , coords.size () / 3 ).transpose ();
2481+ visitor<26 > vis;
2482+ vis.max_depth = max_depth;
24732483
2474- // Eigen::RowVector3f it_as_vec((*it).get(0), (*it).get(1), (*it).get(2));
2475- // Eigen::MatrixXf centered = points.rowwise() - it_as_vec;
2476-
2477- Eigen::MatrixXf centered = points.rowwise () - points.colwise ().mean ();
2478- Eigen::MatrixXf cov = centered.adjoint () * centered;
2479- Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig (cov);
2480-
2481- auto vec = eig.eigenvectors ().col (0 );
2482- auto norm = vec.normalized ();
2483- auto curv = eig.eigenvalues ().col (0 ).value () / eig.eigenvalues ().sum ();
2484-
2485- v.nxyz_curv = {
2486- (int16_t ) (norm.x () * (float ) (std::numeric_limits<int16_t >::max ()-1 )),
2487- (int16_t ) (norm.y () * (float ) (std::numeric_limits<int16_t >::max ()-1 )),
2488- (int16_t ) (norm.z () * (float ) (std::numeric_limits<int16_t >::max ()-1 )),
2489- (int16_t ) (curv * (float ) (std::numeric_limits<int16_t >::max ()-1 ))
2490- };
2484+ coords.clear ();
24912485
2492- result->Set (*it, &v);
2486+ vis ([&coords](const tagged_index& pos) {
2487+ if (pos.which == tagged_index::VOXEL) {
2488+ coords.push_back (pos.pos .get (0 ));
2489+ coords.push_back (pos.pos .get (1 ));
2490+ coords.push_back (pos.pos .get (2 ));
2491+ } else {
2492+ throw std::runtime_error (" Unexpected" );
2493+ }
2494+ }, voxels, *it);
2495+
2496+ Eigen::MatrixXf points = Eigen::Map<Eigen::MatrixXf>(coords.data (), 3 , coords.size () / 3 ).transpose ();
2497+
2498+ // Eigen::RowVector3f it_as_vec((*it).get(0), (*it).get(1), (*it).get(2));
2499+ // Eigen::MatrixXf centered = points.rowwise() - it_as_vec;
2500+
2501+ Eigen::MatrixXf centered = points.rowwise () - points.colwise ().mean ();
2502+ Eigen::MatrixXf cov = centered.adjoint () * centered;
2503+ Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig (cov);
2504+
2505+ auto vec = eig.eigenvectors ().col (0 );
2506+ auto norm = vec.normalized ();
2507+ auto curv = eig.eigenvalues ().col (0 ).value () / eig.eigenvalues ().sum ();
2508+
2509+ v.nxyz_curv = {
2510+ (int16_t )(norm.x () * (float )(std::numeric_limits<int16_t >::max () - 1 )),
2511+ (int16_t )(norm.y () * (float )(std::numeric_limits<int16_t >::max () - 1 )),
2512+ (int16_t )(norm.z () * (float )(std::numeric_limits<int16_t >::max () - 1 )),
2513+ (int16_t )(curv * (float )(std::numeric_limits<int16_t >::max () - 1 ))
2514+ };
2515+
2516+ result_set (*it, &v);
2517+ }
2518+ };
2519+
2520+ boost::optional<size_t > threads;
2521+ if (scope.has (" THREADS" )) {
2522+ int t = scope.get_value <int >(" THREADS" );
2523+ if (t > 1 ) {
2524+ threads = (size_t )t;
2525+ }
2526+ }
2527+ if (threads) {
2528+ std::vector<std::thread> ts;
2529+ ts.reserve (*threads);
2530+ for (size_t i = 0 ; i < *threads; ++i) {
2531+ ts.emplace_back (std::thread ([&process, threads, i]() {
2532+ process (threads, i);
2533+ }));
2534+ }
2535+ for (auto jt = ts.begin (); jt != ts.end (); ++jt) {
2536+ jt->join ();
2537+ }
2538+ } else {
2539+ process ();
24932540 }
24942541
24952542 return result;
0 commit comments