Parallelize TriangleMeshSlicer::slice(), cherry picked from @alexrj 83ad123d951c6ee663d2f3b02e095c203ca794e7

This commit is contained in:
Alessandro Ranellucci 2016-11-26 13:45:58 +01:00 committed by bubnikv
parent e9290252d6
commit 70a9de085b
2 changed files with 116 additions and 41 deletions

View file

@ -2,7 +2,6 @@
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
#include "Geometry.hpp" #include "Geometry.hpp"
#include <cmath> #include <cmath>
#include <queue>
#include <deque> #include <deque>
#include <set> #include <set>
#include <vector> #include <vector>
@ -403,7 +402,7 @@ TriangleMesh::require_shared_vertices()
} }
void void
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
{ {
/* /*
This method gets called with a list of unscaled Z coordinates and outputs This method gets called with a list of unscaled Z coordinates and outputs
@ -427,7 +426,6 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
At the end, we free the tables generated by analyze() as we don't At the end, we free the tables generated by analyze() as we don't
need them anymore. need them anymore.
FUTURE: parallelize slice_facet() and make_loops()
NOTE: this method accepts a vector of floats because the mesh coordinate NOTE: this method accepts a vector of floats because the mesh coordinate
type is float. type is float.
@ -435,18 +433,66 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
std::vector<IntersectionLines> lines(z.size()); std::vector<IntersectionLines> lines(z.size());
for (int facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; facet_idx++) { {
stl_facet* facet = &this->mesh->stl.facet_start[facet_idx]; // queue all the facet indices
std::queue<size_t> queue;
boost::mutex queue_mutex, lines_mutex;
for (size_t i = 0; i < this->mesh->stl.stats.number_of_facets; ++i) queue.push(i);
boost::thread_group workers;
for (int i = 0; i < boost::thread::hardware_concurrency(); i++)
workers.add_thread(new boost::thread(&TriangleMeshSlicer::_slice_do, this,
&queue, &queue_mutex, &lines, &lines_mutex, z));
workers.join_all();
}
// v_scaled_shared could be freed here
// build loops
layers->resize(z.size());
{
// queue all the layer numbers
std::queue<size_t> queue;
boost::mutex queue_mutex;
for (size_t i = 0; i < lines.size(); ++i) queue.push(i);
// We don't use a mutex for lines because workers are only writing the skip property
// and no workers work on the same layer (i.e. item of 'lines').
boost::thread_group workers;
for (int i = 0; i < boost::thread::hardware_concurrency(); i++)
workers.add_thread(new boost::thread(&TriangleMeshSlicer::_make_loops_do, this,
&queue, &queue_mutex, &lines, layers));
workers.join_all();
}
}
void
TriangleMeshSlicer::_slice_do(std::queue<size_t>* queue, boost::mutex* queue_mutex,
std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const
{
//std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl;
while (true) {
int facet_idx;
{
boost::lock_guard<boost::mutex> l(*queue_mutex);
if (queue->empty()) return;
facet_idx = queue->front();
queue->pop();
}
//std::cout << " Facet " << facet_idx << " (" << boost::this_thread::get_id() << ")" << std::endl;
const stl_facet &facet = this->mesh->stl.facet_start[facet_idx];
// find facet extents // find facet extents
float min_z = fminf(facet->vertex[0].z, fminf(facet->vertex[1].z, facet->vertex[2].z)); const float min_z = fminf(facet.vertex[0].z, fminf(facet.vertex[1].z, facet.vertex[2].z));
float max_z = fmaxf(facet->vertex[0].z, fmaxf(facet->vertex[1].z, facet->vertex[2].z)); const float max_z = fmaxf(facet.vertex[0].z, fmaxf(facet.vertex[1].z, facet.vertex[2].z));
#ifdef SLIC3R_TRIANGLEMESH_DEBUG #ifdef SLIC3R_TRIANGLEMESH_DEBUG
printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx, printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
facet->vertex[0].x, facet->vertex[0].y, facet->vertex[0].z, facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z,
facet->vertex[1].x, facet->vertex[1].y, facet->vertex[1].z, facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z,
facet->vertex[2].x, facet->vertex[2].y, facet->vertex[2].z); facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z);
printf("z: min = %.2f, max = %.2f\n", min_z, max_z); printf("z: min = %.2f, max = %.2f\n", min_z, max_z);
#endif #endif
@ -460,25 +506,14 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* la
for (std::vector<float>::const_iterator it = min_layer; it != max_layer + 1; ++it) { for (std::vector<float>::const_iterator it = min_layer; it != max_layer + 1; ++it) {
std::vector<float>::size_type layer_idx = it - z.begin(); std::vector<float>::size_type layer_idx = it - z.begin();
this->slice_facet(*it / SCALING_FACTOR, *facet, facet_idx, min_z, max_z, &lines[layer_idx]); this->slice_facet(*it / SCALING_FACTOR, facet, facet_idx, min_z, max_z, &(*lines)[layer_idx], lines_mutex);
} }
} boost::this_thread::interruption_point();
// v_scaled_shared could be freed here
// build loops
layers->resize(z.size());
for (std::vector<IntersectionLines>::iterator it = lines.begin(); it != lines.end(); ++it) {
size_t layer_idx = it - lines.begin();
#ifdef SLIC3R_TRIANGLEMESH_DEBUG
printf("Layer " PRINTF_ZU ":\n", layer_idx);
#endif
this->make_loops(*it, &(*layers)[layer_idx]);
} }
} }
void void
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) const
{ {
std::vector<Polygons> layers_p; std::vector<Polygons> layers_p;
this->slice(z, &layers_p); this->slice(z, &layers_p);
@ -495,7 +530,9 @@ TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<ExPolygons>*
} }
void void
TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int &facet_idx, const float &min_z, const float &max_z, std::vector<IntersectionLine>* lines) const TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int &facet_idx,
const float &min_z, const float &max_z, std::vector<IntersectionLine>* lines,
boost::mutex* lines_mutex) const
{ {
std::vector<IntersectionPoint> points; std::vector<IntersectionPoint> points;
std::vector< std::vector<IntersectionPoint>::size_type > points_on_layer; std::vector< std::vector<IntersectionPoint>::size_type > points_on_layer;
@ -547,7 +584,12 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int
line.b.y = b->y; line.b.y = b->y;
line.a_id = a_id; line.a_id = a_id;
line.b_id = b_id; line.b_id = b_id;
lines->push_back(line); if (lines_mutex != NULL) {
boost::lock_guard<boost::mutex> l(*lines_mutex);
lines->push_back(line);
} else {
lines->push_back(line);
}
found_horizontal_edge = true; found_horizontal_edge = true;
@ -600,13 +642,38 @@ TriangleMeshSlicer::slice_facet(float slice_z, const stl_facet &facet, const int
line.b_id = points[0].point_id; line.b_id = points[0].point_id;
line.edge_a_id = points[1].edge_id; line.edge_a_id = points[1].edge_id;
line.edge_b_id = points[0].edge_id; line.edge_b_id = points[0].edge_id;
lines->push_back(line); if (lines_mutex != NULL) {
boost::lock_guard<boost::mutex> l(*lines_mutex);
lines->push_back(line);
} else {
lines->push_back(line);
}
return; return;
} }
} }
void void
TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) TriangleMeshSlicer::_make_loops_do(std::queue<size_t>* queue, boost::mutex* queue_mutex,
std::vector<IntersectionLines>* lines, std::vector<Polygons>* layers) const
{
//std::cout << "THREAD STARTED: " << boost::this_thread::get_id() << std::endl;
while (true) {
size_t layer_id;
{
boost::lock_guard<boost::mutex> l(*queue_mutex);
if (queue->empty()) return;
layer_id = queue->front();
queue->pop();
}
//std::cout << " Layer " << layer_id << " (" << boost::this_thread::get_id() << ")" << std::endl;
this->make_loops((*lines)[layer_id], &(*layers)[layer_id]);
boost::this_thread::interruption_point();
}
}
void
TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const
{ {
/* /*
SVG svg("lines.svg"); SVG svg("lines.svg");
@ -707,6 +774,7 @@ TriangleMeshSlicer::make_loops(std::vector<IntersectionLine> &lines, Polygons* l
for (IntersectionLinePtrs::const_iterator lineptr = loop.begin(); lineptr != loop.end(); ++lineptr) { for (IntersectionLinePtrs::const_iterator lineptr = loop.begin(); lineptr != loop.end(); ++lineptr) {
p.points.push_back((*lineptr)->a); p.points.push_back((*lineptr)->a);
} }
loops->push_back(p); loops->push_back(p);
#ifdef SLIC3R_TRIANGLEMESH_DEBUG #ifdef SLIC3R_TRIANGLEMESH_DEBUG
@ -746,7 +814,7 @@ class _area_comp {
}; };
void void
TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const
{ {
Polygons loops; Polygons loops;
this->make_loops(lines, &loops); this->make_loops(lines, &loops);
@ -780,7 +848,7 @@ TriangleMeshSlicer::make_expolygons_simple(std::vector<IntersectionLine> &lines,
} }
void void
TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) const
{ {
/* /*
Input loops are not suitable for evenodd nor nonzero fill types, as we might get Input loops are not suitable for evenodd nor nonzero fill types, as we might get
@ -844,7 +912,7 @@ TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices)
} }
void void
TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const
{ {
Polygons pp; Polygons pp;
this->make_loops(lines, &pp); this->make_loops(lines, &pp);
@ -852,7 +920,7 @@ TriangleMeshSlicer::make_expolygons(std::vector<IntersectionLine> &lines, ExPoly
} }
void void
TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) const
{ {
IntersectionLines upper_lines, lower_lines; IntersectionLines upper_lines, lower_lines;
@ -1004,7 +1072,6 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
stl_get_size(&(upper->stl)); stl_get_size(&(upper->stl));
stl_get_size(&(lower->stl)); stl_get_size(&(lower->stl));
} }
TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) : mesh(_mesh), v_scaled_shared(NULL) TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) : mesh(_mesh), v_scaled_shared(NULL)

View file

@ -3,7 +3,9 @@
#include "libslic3r.h" #include "libslic3r.h"
#include <admesh/stl.h> #include <admesh/stl.h>
#include <queue>
#include <vector> #include <vector>
#include <boost/thread.hpp>
#include "BoundingBox.hpp" #include "BoundingBox.hpp"
#include "Line.hpp" #include "Line.hpp"
#include "Point.hpp" #include "Point.hpp"
@ -88,19 +90,25 @@ class TriangleMeshSlicer
TriangleMesh* mesh; TriangleMesh* mesh;
TriangleMeshSlicer(TriangleMesh* _mesh); TriangleMeshSlicer(TriangleMesh* _mesh);
~TriangleMeshSlicer(); ~TriangleMeshSlicer();
void slice(const std::vector<float> &z, std::vector<Polygons>* layers); void slice(const std::vector<float> &z, std::vector<Polygons>* layers) const;
void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers); void slice(const std::vector<float> &z, std::vector<ExPolygons>* layers) const;
void slice_facet(float slice_z, const stl_facet &facet, const int &facet_idx, const float &min_z, const float &max_z, std::vector<IntersectionLine>* lines) const; void slice_facet(float slice_z, const stl_facet &facet, const int &facet_idx,
void cut(float z, TriangleMesh* upper, TriangleMesh* lower); const float &min_z, const float &max_z, std::vector<IntersectionLine>* lines,
boost::mutex* lines_mutex = NULL) const;
void cut(float z, TriangleMesh* upper, TriangleMesh* lower) const;
private: private:
typedef std::vector< std::vector<int> > t_facets_edges; typedef std::vector< std::vector<int> > t_facets_edges;
t_facets_edges facets_edges; t_facets_edges facets_edges;
stl_vertex* v_scaled_shared; stl_vertex* v_scaled_shared;
void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops); void _slice_do(std::queue<size_t>* queue, boost::mutex* queue_mutex,
void make_expolygons(const Polygons &loops, ExPolygons* slices); std::vector<IntersectionLines>* lines, boost::mutex* lines_mutex, const std::vector<float> &z) const;
void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices); void _make_loops_do(std::queue<size_t>* queue, boost::mutex* queue_mutex,
void make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices); std::vector<IntersectionLines>* lines, std::vector<Polygons>* layers) const;
void make_loops(std::vector<IntersectionLine> &lines, Polygons* loops) const;
void make_expolygons(const Polygons &loops, ExPolygons* slices) const;
void make_expolygons_simple(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
void make_expolygons(std::vector<IntersectionLine> &lines, ExPolygons* slices) const;
}; };
} }