Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libslic3r/ExtrusionEntityCollection.cpp')
-rw-r--r--src/libslic3r/ExtrusionEntityCollection.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp
new file mode 100644
index 000000000..7a086bcbf
--- /dev/null
+++ b/src/libslic3r/ExtrusionEntityCollection.cpp
@@ -0,0 +1,220 @@
+#include "ExtrusionEntityCollection.hpp"
+#include <algorithm>
+#include <cmath>
+#include <map>
+
+namespace Slic3r {
+
+ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths)
+ : no_sort(false)
+{
+ this->append(paths);
+}
+
+ExtrusionEntityCollection& ExtrusionEntityCollection::operator= (const ExtrusionEntityCollection &other)
+{
+ this->entities = other.entities;
+ for (size_t i = 0; i < this->entities.size(); ++i)
+ this->entities[i] = this->entities[i]->clone();
+ this->orig_indices = other.orig_indices;
+ this->no_sort = other.no_sort;
+ return *this;
+}
+
+void
+ExtrusionEntityCollection::swap(ExtrusionEntityCollection &c)
+{
+ std::swap(this->entities, c.entities);
+ std::swap(this->orig_indices, c.orig_indices);
+ std::swap(this->no_sort, c.no_sort);
+}
+
+void ExtrusionEntityCollection::clear()
+{
+ for (size_t i = 0; i < this->entities.size(); ++i)
+ delete this->entities[i];
+ this->entities.clear();
+}
+
+ExtrusionEntityCollection::operator ExtrusionPaths() const
+{
+ ExtrusionPaths paths;
+ for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
+ if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(*it))
+ paths.push_back(*path);
+ }
+ return paths;
+}
+
+ExtrusionEntityCollection*
+ExtrusionEntityCollection::clone() const
+{
+ ExtrusionEntityCollection* coll = new ExtrusionEntityCollection(*this);
+ for (size_t i = 0; i < coll->entities.size(); ++i)
+ coll->entities[i] = this->entities[i]->clone();
+ return coll;
+}
+
+void
+ExtrusionEntityCollection::reverse()
+{
+ for (ExtrusionEntitiesPtr::iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
+ // Don't reverse it if it's a loop, as it doesn't change anything in terms of elements ordering
+ // and caller might rely on winding order
+ if (!(*it)->is_loop()) (*it)->reverse();
+ }
+ std::reverse(this->entities.begin(), this->entities.end());
+}
+
+void
+ExtrusionEntityCollection::replace(size_t i, const ExtrusionEntity &entity)
+{
+ delete this->entities[i];
+ this->entities[i] = entity.clone();
+}
+
+void
+ExtrusionEntityCollection::remove(size_t i)
+{
+ delete this->entities[i];
+ this->entities.erase(this->entities.begin() + i);
+}
+
+ExtrusionEntityCollection
+ExtrusionEntityCollection::chained_path(bool no_reverse, ExtrusionRole role) const
+{
+ ExtrusionEntityCollection coll;
+ this->chained_path(&coll, no_reverse, role);
+ return coll;
+}
+
+void
+ExtrusionEntityCollection::chained_path(ExtrusionEntityCollection* retval, bool no_reverse, ExtrusionRole role, std::vector<size_t>* orig_indices) const
+{
+ if (this->entities.empty()) return;
+ this->chained_path_from(this->entities.front()->first_point(), retval, no_reverse, role, orig_indices);
+}
+
+ExtrusionEntityCollection ExtrusionEntityCollection::chained_path_from(Point start_near, bool no_reverse, ExtrusionRole role) const
+{
+ ExtrusionEntityCollection coll;
+ this->chained_path_from(start_near, &coll, no_reverse, role);
+ return coll;
+}
+
+void ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse, ExtrusionRole role, std::vector<size_t>* orig_indices) const
+{
+ if (this->no_sort) {
+ *retval = *this;
+ return;
+ }
+ retval->entities.reserve(this->entities.size());
+ retval->orig_indices.reserve(this->entities.size());
+
+ // if we're asked to return the original indices, build a map
+ std::map<ExtrusionEntity*,size_t> indices_map;
+
+ ExtrusionEntitiesPtr my_paths;
+ for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
+ if (role != erMixed) {
+ // The caller wants only paths with a specific extrusion role.
+ auto role2 = (*it)->role();
+ if (role != role2) {
+ // This extrusion entity does not match the role asked.
+ assert(role2 != erMixed);
+ continue;
+ }
+ }
+
+ ExtrusionEntity* entity = (*it)->clone();
+ my_paths.push_back(entity);
+ if (orig_indices != NULL) indices_map[entity] = it - this->entities.begin();
+ }
+
+ Points endpoints;
+ for (ExtrusionEntitiesPtr::iterator it = my_paths.begin(); it != my_paths.end(); ++it) {
+ endpoints.push_back((*it)->first_point());
+ if (no_reverse || !(*it)->can_reverse()) {
+ endpoints.push_back((*it)->first_point());
+ } else {
+ endpoints.push_back((*it)->last_point());
+ }
+ }
+
+ while (!my_paths.empty()) {
+ // find nearest point
+ int start_index = start_near.nearest_point_index(endpoints);
+ int path_index = start_index/2;
+ ExtrusionEntity* entity = my_paths.at(path_index);
+ // never reverse loops, since it's pointless for chained path and callers might depend on orientation
+ if (start_index % 2 && !no_reverse && entity->can_reverse()) {
+ entity->reverse();
+ }
+ retval->entities.push_back(my_paths.at(path_index));
+ if (orig_indices != NULL) orig_indices->push_back(indices_map[entity]);
+ my_paths.erase(my_paths.begin() + path_index);
+ endpoints.erase(endpoints.begin() + 2*path_index, endpoints.begin() + 2*path_index + 2);
+ start_near = retval->entities.back()->last_point();
+ }
+}
+
+void ExtrusionEntityCollection::polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const
+{
+ for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it)
+ (*it)->polygons_covered_by_width(out, scaled_epsilon);
+}
+
+void ExtrusionEntityCollection::polygons_covered_by_spacing(Polygons &out, const float scaled_epsilon) const
+{
+ for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it)
+ (*it)->polygons_covered_by_spacing(out, scaled_epsilon);
+}
+
+/* Recursively count paths and loops contained in this collection */
+size_t
+ExtrusionEntityCollection::items_count() const
+{
+ size_t count = 0;
+ for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
+ if ((*it)->is_collection()) {
+ ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(*it);
+ count += collection->items_count();
+ } else {
+ ++count;
+ }
+ }
+ return count;
+}
+
+/* Returns a single vector of pointers to all non-collection items contained in this one */
+void
+ExtrusionEntityCollection::flatten(ExtrusionEntityCollection* retval) const
+{
+ for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
+ if ((*it)->is_collection()) {
+ ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(*it);
+ retval->append(collection->flatten().entities);
+ } else {
+ retval->append(**it);
+ }
+ }
+}
+
+ExtrusionEntityCollection
+ExtrusionEntityCollection::flatten() const
+{
+ ExtrusionEntityCollection coll;
+ this->flatten(&coll);
+ return coll;
+}
+
+double
+ExtrusionEntityCollection::min_mm3_per_mm() const
+{
+ double min_mm3_per_mm = std::numeric_limits<double>::max();
+ for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it)
+ min_mm3_per_mm = std::min(min_mm3_per_mm, (*it)->min_mm3_per_mm());
+ return min_mm3_per_mm;
+}
+
+}