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

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'xs/src/libslic3r/ExtrusionEntity.cpp')
-rw-r--r--xs/src/libslic3r/ExtrusionEntity.cpp335
1 files changed, 335 insertions, 0 deletions
diff --git a/xs/src/libslic3r/ExtrusionEntity.cpp b/xs/src/libslic3r/ExtrusionEntity.cpp
new file mode 100644
index 000000000..fd39fdc9f
--- /dev/null
+++ b/xs/src/libslic3r/ExtrusionEntity.cpp
@@ -0,0 +1,335 @@
+#include "ExtrusionEntity.hpp"
+#include "ExtrusionEntityCollection.hpp"
+#include "ExPolygonCollection.hpp"
+#include "ClipperUtils.hpp"
+#include "Extruder.hpp"
+#include <sstream>
+
+namespace Slic3r {
+
+ExtrusionPath*
+ExtrusionPath::clone() const
+{
+ return new ExtrusionPath (*this);
+}
+
+void
+ExtrusionPath::reverse()
+{
+ this->polyline.reverse();
+}
+
+Point
+ExtrusionPath::first_point() const
+{
+ return this->polyline.points.front();
+}
+
+Point
+ExtrusionPath::last_point() const
+{
+ return this->polyline.points.back();
+}
+
+void
+ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
+{
+ // perform clipping
+ Polylines clipped;
+ intersection<Polylines,Polylines>(this->polyline, collection, clipped);
+ return this->_inflate_collection(clipped, retval);
+}
+
+void
+ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, ExtrusionEntityCollection* retval) const
+{
+ // perform clipping
+ Polylines clipped;
+ diff<Polylines,Polylines>(this->polyline, collection, clipped);
+ return this->_inflate_collection(clipped, retval);
+}
+
+void
+ExtrusionPath::clip_end(double distance)
+{
+ this->polyline.clip_end(distance);
+}
+
+void
+ExtrusionPath::simplify(double tolerance)
+{
+ this->polyline.simplify(tolerance);
+}
+
+double
+ExtrusionPath::length() const
+{
+ return this->polyline.length();
+}
+
+bool
+ExtrusionPath::is_perimeter() const
+{
+ return this->role == erPerimeter
+ || this->role == erExternalPerimeter
+ || this->role == erOverhangPerimeter;
+}
+
+bool
+ExtrusionPath::is_fill() const
+{
+ return this->role == erInternalInfill
+ || this->role == erSolidInfill
+ || this->role == erTopSolidInfill;
+}
+
+bool
+ExtrusionPath::is_bridge() const
+{
+ return this->role == erBridgeInfill
+ || this->role == erOverhangPerimeter;
+}
+
+void
+ExtrusionPath::_inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const
+{
+ for (Polylines::const_iterator it = polylines.begin(); it != polylines.end(); ++it) {
+ ExtrusionPath* path = this->clone();
+ path->polyline = *it;
+ collection->entities.push_back(path);
+ }
+}
+
+#ifdef SLIC3RXS
+REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
+#endif
+
+std::string
+ExtrusionPath::gcode(Extruder* extruder, double e, double F,
+ double xofs, double yofs, std::string extrusion_axis,
+ std::string gcode_line_suffix) const
+{
+ dSP;
+
+ std::stringstream stream;
+ stream.setf(std::ios::fixed);
+
+ double local_F = F;
+
+ Lines lines = this->polyline.lines();
+ for (Lines::const_iterator line_it = lines.begin();
+ line_it != lines.end(); ++line_it)
+ {
+ const double line_length = line_it->length() * SCALING_FACTOR;
+
+ // calculate extrusion length for this line
+ double E = (e == 0) ? 0 : extruder->extrude(e * line_length);
+
+ // compose G-code line
+
+ Point point = line_it->b;
+ const double x = point.x * SCALING_FACTOR + xofs;
+ const double y = point.y * SCALING_FACTOR + yofs;
+ stream.precision(3);
+ stream << "G1 X" << x << " Y" << y;
+
+ if (E != 0) {
+ stream.precision(5);
+ stream << " " << extrusion_axis << E;
+ }
+
+ if (local_F != 0) {
+ stream.precision(3);
+ stream << " F" << local_F;
+ local_F = 0;
+ }
+
+ stream << gcode_line_suffix;
+ stream << "\n";
+ }
+
+ return stream.str();
+}
+
+ExtrusionLoop::operator Polygon() const
+{
+ Polygon polygon;
+ this->polygon(&polygon);
+ return polygon;
+}
+
+ExtrusionLoop*
+ExtrusionLoop::clone() const
+{
+ return new ExtrusionLoop (*this);
+}
+
+bool
+ExtrusionLoop::make_clockwise()
+{
+ Polygon polygon = *this;
+ bool was_ccw = polygon.is_counter_clockwise();
+ if (was_ccw) this->reverse();
+ return was_ccw;
+}
+
+bool
+ExtrusionLoop::make_counter_clockwise()
+{
+ Polygon polygon = *this;
+ bool was_cw = polygon.is_clockwise();
+ if (was_cw) this->reverse();
+ return was_cw;
+}
+
+void
+ExtrusionLoop::reverse()
+{
+ for (ExtrusionPaths::iterator path = this->paths.begin(); path != this->paths.end(); ++path)
+ path->reverse();
+ std::reverse(this->paths.begin(), this->paths.end());
+}
+
+Point
+ExtrusionLoop::first_point() const
+{
+ return this->paths.front().polyline.points.front();
+}
+
+Point
+ExtrusionLoop::last_point() const
+{
+ return this->paths.back().polyline.points.back(); // which coincides with first_point(), by the way
+}
+
+void
+ExtrusionLoop::polygon(Polygon* polygon) const
+{
+ for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
+ // for each polyline, append all points except the last one (because it coincides with the first one of the next polyline)
+ polygon->points.insert(polygon->points.end(), path->polyline.points.begin(), path->polyline.points.end()-1);
+ }
+}
+
+double
+ExtrusionLoop::length() const
+{
+ double len = 0;
+ for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
+ len += path->polyline.length();
+ return len;
+}
+
+void
+ExtrusionLoop::split_at_vertex(const Point &point)
+{
+ for (ExtrusionPaths::iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
+ int idx = path->polyline.find_point(point);
+ if (idx != -1) {
+ if (this->paths.size() == 1) {
+ // just change the order of points
+ path->polyline.points.insert(path->polyline.points.end(), path->polyline.points.begin() + 1, path->polyline.points.begin() + idx + 1);
+ path->polyline.points.erase(path->polyline.points.begin(), path->polyline.points.begin() + idx);
+ } else {
+ // if we have multiple paths we assume they have different types, so no need to
+ // check for continuity as we do for the single path case above
+
+ // new paths list starts with the second half of current path
+ ExtrusionPaths new_paths;
+ {
+ ExtrusionPath p = *path;
+ p.polyline.points.erase(p.polyline.points.begin(), p.polyline.points.begin() + idx);
+ if (p.polyline.is_valid()) new_paths.push_back(p);
+ }
+
+ // then we add all paths until the end of current path list
+ new_paths.insert(new_paths.end(), this->paths.begin(), path); // not including this path
+
+ // then we add all paths since the beginning of current list up to the previous one
+ new_paths.insert(new_paths.end(), path+1, this->paths.end()); // not including this path
+
+ // finally we add the first half of current path
+ {
+ ExtrusionPath p = *path;
+ p.polyline.points.erase(p.polyline.points.begin() + idx + 1, p.polyline.points.end());
+ if (p.polyline.is_valid()) new_paths.push_back(p);
+ }
+ // we can now override the old path list with the new one and stop looping
+ this->paths = new_paths;
+ }
+ return;
+ }
+ }
+ CONFESS("Point not found");
+}
+
+void
+ExtrusionLoop::split_at(const Point &point)
+{
+ if (this->paths.empty()) return;
+
+ // find the closest path and closest point
+ size_t path_idx = 0;
+ Point p = this->paths.front().first_point();
+ double min = point.distance_to(p);
+ for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
+ Point p_tmp = point.projection_onto(path->polyline);
+ double dist = point.distance_to(p_tmp);
+ if (dist < min) {
+ p = p_tmp;
+ min = dist;
+ path_idx = path - this->paths.begin();
+ }
+ }
+
+ // now split path_idx in two parts
+ ExtrusionPath p1 = this->paths[path_idx];
+ ExtrusionPath p2 = p1;
+ this->paths[path_idx].polyline.split_at(p, &p1.polyline, &p2.polyline);
+
+ // install the two paths
+ this->paths.erase(this->paths.begin() + path_idx);
+ if (p2.polyline.is_valid()) this->paths.insert(this->paths.begin() + path_idx, p2);
+ if (p1.polyline.is_valid()) this->paths.insert(this->paths.begin() + path_idx, p1);
+
+ // split at the new vertex
+ this->split_at_vertex(p);
+}
+
+void
+ExtrusionLoop::clip_end(double distance, ExtrusionPaths* paths) const
+{
+ *paths = this->paths;
+
+ while (distance > 0 && !paths->empty()) {
+ ExtrusionPath &last = paths->back();
+ double len = last.length();
+ if (len <= distance) {
+ paths->pop_back();
+ distance -= len;
+ } else {
+ last.polyline.clip_end(distance);
+ break;
+ }
+ }
+}
+
+bool
+ExtrusionLoop::has_overhang_point(const Point &point) const
+{
+ for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
+ int pos = path->polyline.find_point(point);
+ if (pos != -1) {
+ // point belongs to this path
+ // we consider it overhang only if it's not an endpoint
+ return (path->is_bridge() && pos > 0 && pos != path->polyline.points.size()-1);
+ }
+ }
+ return false;
+}
+
+#ifdef SLIC3RXS
+REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
+#endif
+
+}