ExtrusionEntityCollection.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #ifndef slic3r_ExtrusionEntityCollection_hpp_
  2. #define slic3r_ExtrusionEntityCollection_hpp_
  3. #include "libslic3r.h"
  4. #include "Exception.hpp"
  5. #include "ExtrusionEntity.hpp"
  6. namespace Slic3r {
  7. // Remove those items from extrusion_entities, that do not match role.
  8. // Do nothing if role is mixed.
  9. // Removed elements are NOT being deleted.
  10. void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role);
  11. // Return new vector of ExtrusionEntities* with only those items from input extrusion_entities, that match role.
  12. // Return all extrusion entities if role is mixed.
  13. // Returned extrusion entities are shared with the source vector, they are NOT cloned, they are considered to be owned by extrusion_entities.
  14. inline ExtrusionEntitiesPtr filter_by_extrusion_role(const ExtrusionEntitiesPtr &extrusion_entities, ExtrusionRole role)
  15. {
  16. ExtrusionEntitiesPtr out { extrusion_entities };
  17. filter_by_extrusion_role_in_place(out, role);
  18. return out;
  19. }
  20. class ExtrusionEntityCollection : public ExtrusionEntity
  21. {
  22. private:
  23. // set to tru to forbit to reorder and reverse all entities indie us.
  24. bool no_sort;
  25. // even if no_sort, allow to reverse() us (and our entities if they allow it, but they should)
  26. bool no_reverse;
  27. ExtrusionEntitiesPtr m_entities; // we own these entities
  28. public:
  29. virtual ExtrusionEntityCollection* clone() const override { return new ExtrusionEntityCollection(*this); }
  30. // Create a new object, initialize it with this object using the move semantics.
  31. virtual ExtrusionEntityCollection* clone_move() override { return new ExtrusionEntityCollection(std::move(*this)); }
  32. /// Owned ExtrusionEntities and descendent ExtrusionEntityCollections.
  33. /// Iterating over this needs to check each child to see if it, too is a collection.
  34. const ExtrusionEntitiesPtr& entities() const { return m_entities; }
  35. ExtrusionEntitiesPtr& set_entities() { return m_entities; }
  36. ExtrusionEntityCollection(): no_sort(false), no_reverse(false) {}
  37. ExtrusionEntityCollection(const ExtrusionEntityCollection &other) : no_sort(other.no_sort), no_reverse(other.no_reverse) { this->append(other.entities()); }
  38. ExtrusionEntityCollection(ExtrusionEntityCollection &&other) : m_entities(std::move(other.m_entities)), no_sort(other.no_sort), no_reverse(other.no_reverse) {}
  39. explicit ExtrusionEntityCollection(const ExtrusionPaths &paths);
  40. ExtrusionEntityCollection& operator=(const ExtrusionEntityCollection &other);
  41. ExtrusionEntityCollection& operator=(ExtrusionEntityCollection &&other)
  42. { this->m_entities = std::move(other.m_entities); this->no_sort = other.no_sort; this->no_reverse = other.no_reverse; return *this; }
  43. ~ExtrusionEntityCollection() { clear(); }
  44. /// Operator to convert and flatten this collection to a single vector of ExtrusionPaths.
  45. explicit operator ExtrusionPaths() const;
  46. bool is_collection() const override { return true; }
  47. ExtrusionRole role() const override {
  48. ExtrusionRole out = erNone;
  49. for (const ExtrusionEntity *ee : m_entities) {
  50. ExtrusionRole er = ee->role();
  51. out = (out == erNone || out == er) ? er : erMixed;
  52. }
  53. return out;
  54. }
  55. void set_can_sort_reverse(bool sort, bool reverse) { this->no_sort = !sort; this->no_reverse = !reverse; }
  56. bool can_sort() const { return !this->no_sort; }
  57. bool can_reverse() const override { return can_sort() || !this->no_reverse; }
  58. bool empty() const { return this->m_entities.empty(); }
  59. void clear();
  60. void swap (ExtrusionEntityCollection &c);
  61. void append(const ExtrusionEntity &entity) { this->m_entities.emplace_back(entity.clone()); }
  62. void append(ExtrusionEntity &&entity) { this->m_entities.emplace_back(entity.clone_move()); }
  63. void append(const ExtrusionEntitiesPtr &entities) {
  64. this->m_entities.reserve(this->m_entities.size() + entities.size());
  65. for (const ExtrusionEntity *ptr : entities)
  66. this->m_entities.emplace_back(ptr->clone());
  67. }
  68. void append(ExtrusionEntitiesPtr &&src) {
  69. if (m_entities.empty())
  70. m_entities = std::move(src);
  71. else {
  72. std::move(std::begin(src), std::end(src), std::back_inserter(m_entities));
  73. src.clear();
  74. }
  75. }
  76. void append(const ExtrusionPaths &paths) {
  77. this->m_entities.reserve(this->m_entities.size() + paths.size());
  78. for (const ExtrusionPath &path : paths)
  79. this->m_entities.emplace_back(path.clone());
  80. }
  81. void append(ExtrusionPaths &&paths) {
  82. this->m_entities.reserve(this->m_entities.size() + paths.size());
  83. for (ExtrusionPath &path : paths)
  84. this->m_entities.emplace_back(new ExtrusionPath(std::move(path)));
  85. }
  86. void replace(size_t i, const ExtrusionEntity &entity);
  87. void remove(size_t i);
  88. static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed);
  89. ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erNone) const {
  90. if (role == erNone) role = this->role();
  91. if( this->no_sort || (role == erMixed) )
  92. return *this;
  93. else
  94. return chained_path_from(this->m_entities, start_near, role);
  95. }
  96. void reverse() override;
  97. const Point& first_point() const override { return this->entities().front()->first_point(); }
  98. const Point& last_point() const override { return this->entities().back()->last_point(); }
  99. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
  100. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
  101. void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override;
  102. // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion spacing.
  103. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
  104. // Useful to calculate area of an infill, which has been really filled in by a 100% rectilinear infill.
  105. void polygons_covered_by_spacing(Polygons &out, const float spacing_ratio, const float scaled_epsilon) const override;
  106. Polygons polygons_covered_by_width(const float scaled_epsilon = 0.f) const
  107. { Polygons out; this->polygons_covered_by_width(out, scaled_epsilon); return out; }
  108. Polygons polygons_covered_by_spacing(const float spacing_ratio, const float scaled_epsilon) const
  109. { Polygons out; this->polygons_covered_by_spacing(out, spacing_ratio, scaled_epsilon); return out; }
  110. /// Recursively count paths and loops contained in this collection
  111. size_t items_count() const;
  112. /// Returns a flattened copy of this ExtrusionEntityCollection. That is, all of the items in its entities() vector are not collections.
  113. /// You should be iterating over flatten().entities() if you are interested in the underlying ExtrusionEntities (and don't care about hierarchy).
  114. /// \param preserve_ordering Flag to method that will flatten if and only if the underlying collection is sortable when True (default: False).
  115. ExtrusionEntityCollection flatten(bool preserve_ordering = false) const;
  116. double total_volume() const override { double volume=0.; for (const auto& ent : entities()) volume+=ent->total_volume(); return volume; }
  117. // Following methods shall never be called on an ExtrusionEntityCollection.
  118. Polyline as_polyline() const override {
  119. throw Slic3r::RuntimeError("Calling as_polyline() on a ExtrusionEntityCollection");
  120. return Polyline();
  121. };
  122. void collect_polylines(Polylines &dst) const override {
  123. for (const ExtrusionEntity* extrusion_entity : this->entities())
  124. extrusion_entity->collect_polylines(dst);
  125. }
  126. double length() const override {
  127. throw Slic3r::RuntimeError("Calling length() on a ExtrusionEntityCollection");
  128. return 0.;
  129. }
  130. virtual void visit(ExtrusionVisitor &visitor) { visitor.use(*this); };
  131. virtual void visit(ExtrusionVisitorConst &visitor) const { visitor.use(*this); };
  132. };
  133. //// visitors /////
  134. class CountEntities : public ExtrusionVisitorConst {
  135. public:
  136. size_t count(const ExtrusionEntity &coll) { coll.visit(*this); return leaf_number; }
  137. size_t leaf_number = 0;
  138. virtual void default_use(const ExtrusionEntity &entity) override { ++leaf_number; }
  139. virtual void use(const ExtrusionEntityCollection &coll) override;
  140. };
  141. class FlatenEntities : public ExtrusionVisitorConst {
  142. ExtrusionEntityCollection to_fill;
  143. bool preserve_ordering;
  144. public:
  145. FlatenEntities(bool preserve_ordering) : preserve_ordering(preserve_ordering) {}
  146. FlatenEntities(ExtrusionEntityCollection pattern, bool preserve_ordering) : preserve_ordering(preserve_ordering) {
  147. to_fill.set_can_sort_reverse(pattern.can_sort(), pattern.can_reverse());
  148. }
  149. ExtrusionEntityCollection get() {
  150. return to_fill;
  151. };
  152. ExtrusionEntityCollection&& flatten(const ExtrusionEntityCollection &to_flatten) &&;
  153. virtual void default_use(const ExtrusionEntity &entity) override { to_fill.append(entity); }
  154. virtual void use(const ExtrusionEntityCollection &coll) override;
  155. };
  156. } // namespace Slic3r
  157. #endif