mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-22 16:21:24 -06:00
New semantics for ExtrusionLoop objects. Early processing of perimeter overhangs for paralellizing such work and making G-code export lighter. Lots of refactoring. This should fix a number of minor bugs, including reversals of perimeter overhangs.
This commit is contained in:
parent
d2d885fc53
commit
c37ef2f18b
27 changed files with 618 additions and 423 deletions
|
@ -300,23 +300,24 @@ void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polygons &su
|
|||
}
|
||||
|
||||
void _clipper_do(const ClipperLib::ClipType clipType, const Slic3r::Polylines &subject,
|
||||
const Slic3r::Polygons &clip, ClipperLib::PolyTree &retval, const ClipperLib::PolyFillType fillType)
|
||||
const Slic3r::Polygons &clip, ClipperLib::PolyTree &retval, const ClipperLib::PolyFillType fillType,
|
||||
const bool safety_offset_)
|
||||
{
|
||||
// read input
|
||||
ClipperLib::Paths* input_subject = new ClipperLib::Paths();
|
||||
ClipperLib::Paths* input_clip = new ClipperLib::Paths();
|
||||
Slic3rMultiPoints_to_ClipperPaths(subject, *input_subject);
|
||||
Slic3rMultiPoints_to_ClipperPaths(clip, *input_clip);
|
||||
ClipperLib::Paths input_subject, input_clip;
|
||||
Slic3rMultiPoints_to_ClipperPaths(subject, input_subject);
|
||||
Slic3rMultiPoints_to_ClipperPaths(clip, input_clip);
|
||||
|
||||
// perform safety offset
|
||||
if (safety_offset_) safety_offset(&input_clip);
|
||||
|
||||
// init Clipper
|
||||
ClipperLib::Clipper clipper;
|
||||
clipper.Clear();
|
||||
|
||||
// add polygons
|
||||
clipper.AddPaths(*input_subject, ClipperLib::ptSubject, false);
|
||||
delete input_subject;
|
||||
clipper.AddPaths(*input_clip, ClipperLib::ptClip, true);
|
||||
delete input_clip;
|
||||
clipper.AddPaths(input_subject, ClipperLib::ptSubject, false);
|
||||
clipper.AddPaths(input_clip, ClipperLib::ptClip, true);
|
||||
|
||||
// perform operation
|
||||
clipper.Execute(clipType, retval, fillType, fillType);
|
||||
|
@ -338,52 +339,114 @@ void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
|
|||
const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_)
|
||||
{
|
||||
// perform operation
|
||||
ClipperLib::PolyTree* polytree = new ClipperLib::PolyTree();
|
||||
_clipper_do<ClipperLib::PolyTree>(clipType, subject, clip, *polytree, ClipperLib::pftNonZero, safety_offset_);
|
||||
ClipperLib::PolyTree polytree;
|
||||
_clipper_do<ClipperLib::PolyTree>(clipType, subject, clip, polytree, ClipperLib::pftNonZero, safety_offset_);
|
||||
|
||||
// convert into ExPolygons
|
||||
PolyTreeToExPolygons(*polytree, retval);
|
||||
delete polytree;
|
||||
PolyTreeToExPolygons(polytree, retval);
|
||||
}
|
||||
|
||||
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject,
|
||||
const Slic3r::Polygons &clip, Slic3r::Polylines &retval)
|
||||
const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_)
|
||||
{
|
||||
// perform operation
|
||||
ClipperLib::PolyTree polytree;
|
||||
_clipper_do(clipType, subject, clip, polytree, ClipperLib::pftNonZero);
|
||||
_clipper_do(clipType, subject, clip, polytree, ClipperLib::pftNonZero, safety_offset_);
|
||||
|
||||
// convert into Polygons
|
||||
// convert into Polylines
|
||||
ClipperLib::Paths output;
|
||||
ClipperLib::PolyTreeToPaths(polytree, output);
|
||||
ClipperPaths_to_Slic3rMultiPoints(output, retval);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, bool safety_offset_)
|
||||
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
|
||||
const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_)
|
||||
{
|
||||
// transform input polygons into polylines
|
||||
Slic3r::Polylines polylines;
|
||||
polylines.reserve(subject.size());
|
||||
for (Slic3r::Polygons::const_iterator polygon = subject.begin(); polygon != subject.end(); ++polygon)
|
||||
polylines.push_back(*polygon); // implicit call to split_at_first_point()
|
||||
|
||||
/* Clipper will remove a polyline segment if first point coincides with last one.
|
||||
Until that bug is not fixed upstream, we move one of those points slightly. */
|
||||
for (Slic3r::Polylines::iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline)
|
||||
polyline->points.front().translate(1, 0);
|
||||
|
||||
// perform clipping
|
||||
_clipper(clipType, polylines, clip, retval, safety_offset_);
|
||||
|
||||
// compensate for the above hack
|
||||
for (Slic3r::Polylines::iterator polyline = retval.begin(); polyline != retval.end(); ++polyline) {
|
||||
for (Slic3r::Polylines::iterator subj_polyline = polylines.begin(); subj_polyline != polylines.end(); ++subj_polyline) {
|
||||
// if first point of clipped line coincides with first point of subject line, compensate for hack
|
||||
if (polyline->points.front().coincides_with(subj_polyline->points.front())) {
|
||||
polyline->points.front().translate(-1, 0);
|
||||
break;
|
||||
}
|
||||
// since Clipper does not preserve orientation of polylines, check last point too
|
||||
if (polyline->points.back().coincides_with(subj_polyline->points.front())) {
|
||||
polyline->points.back().translate(-1, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the split_at_first_point() call above happens to split the polygon inside the clipping area
|
||||
we would get two consecutive polylines instead of a single one, so we go through them in order
|
||||
to recombine continuous polylines. */
|
||||
for (size_t i = 0; i < retval.size(); ++i) {
|
||||
for (size_t j = i+1; j < retval.size(); ++j) {
|
||||
if (retval[i].points.back().coincides_with(retval[j].points.front())) {
|
||||
/* If last point of i coincides with first point of j,
|
||||
append points of j to i and delete j */
|
||||
retval[i].points.insert(retval[i].points.end(), retval[j].points.begin()+1, retval[j].points.end());
|
||||
retval.erase(retval.begin() + j);
|
||||
--j;
|
||||
} else if (retval[i].points.front().coincides_with(retval[j].points.back())) {
|
||||
/* If first point of i coincides with last point of j,
|
||||
prepend points of j to i and delete j */
|
||||
retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1);
|
||||
retval.erase(retval.begin() + j);
|
||||
--j;
|
||||
} else if (retval[i].points.front().coincides_with(retval[j].points.front())) {
|
||||
/* Since Clipper does not preserve orientation of polylines,
|
||||
also check the case when first point of i coincides with first point of j. */
|
||||
retval[j].reverse();
|
||||
retval[i].points.insert(retval[i].points.begin(), retval[j].points.begin(), retval[j].points.end()-1);
|
||||
retval.erase(retval.begin() + j);
|
||||
--j;
|
||||
} else if (retval[i].points.back().coincides_with(retval[j].points.back())) {
|
||||
/* Since Clipper does not preserve orientation of polylines,
|
||||
also check the case when last point of i coincides with last point of j. */
|
||||
retval[j].reverse();
|
||||
retval[i].points.insert(retval[i].points.end(), retval[j].points.begin()+1, retval[j].points.end());
|
||||
retval.erase(retval.begin() + j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class SubjectType, class ResultType>
|
||||
void diff(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType &retval, bool safety_offset_)
|
||||
{
|
||||
_clipper(ClipperLib::ctDifference, subject, clip, retval, safety_offset_);
|
||||
}
|
||||
template void diff<Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_);
|
||||
template void diff<Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
|
||||
template void diff<Slic3r::Polygons, Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_);
|
||||
template void diff<Slic3r::Polygons, Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
|
||||
template void diff<Slic3r::Polygons, Slic3r::Polylines>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_);
|
||||
template void diff<Slic3r::Polylines, Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_);
|
||||
|
||||
void diff(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval)
|
||||
{
|
||||
_clipper(ClipperLib::ctDifference, subject, clip, retval);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, bool safety_offset_)
|
||||
template <class SubjectType, class ResultType>
|
||||
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType &retval, bool safety_offset_)
|
||||
{
|
||||
_clipper(ClipperLib::ctIntersection, subject, clip, retval, safety_offset_);
|
||||
}
|
||||
template void intersection<Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_);
|
||||
template void intersection<Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
|
||||
|
||||
void intersection(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval)
|
||||
{
|
||||
_clipper(ClipperLib::ctIntersection, subject, clip, retval);
|
||||
}
|
||||
template void intersection<Slic3r::Polygons, Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval, bool safety_offset_);
|
||||
template void intersection<Slic3r::Polygons, Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
|
||||
template void intersection<Slic3r::Polygons, Slic3r::Polylines>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_);
|
||||
template void intersection<Slic3r::Polylines, Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval, bool safety_offset_);
|
||||
|
||||
void xor_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval,
|
||||
bool safety_offset_)
|
||||
|
@ -492,24 +555,19 @@ void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::ExPolygons &retv
|
|||
PolyTreeToExPolygons(polytree, retval);
|
||||
}
|
||||
|
||||
void safety_offset(ClipperLib::Paths* &subject)
|
||||
void safety_offset(ClipperLib::Paths* paths)
|
||||
{
|
||||
// scale input
|
||||
scaleClipperPolygons(*subject, CLIPPER_OFFSET_SCALE);
|
||||
scaleClipperPolygons(*paths, CLIPPER_OFFSET_SCALE);
|
||||
|
||||
// perform offset (delta = scale 1e-05)
|
||||
ClipperLib::Paths* retval = new ClipperLib::Paths();
|
||||
ClipperLib::ClipperOffset co;
|
||||
co.MiterLimit = 2;
|
||||
co.AddPaths(*subject, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
|
||||
co.Execute(*retval, 10.0 * CLIPPER_OFFSET_SCALE);
|
||||
co.AddPaths(*paths, ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
|
||||
co.Execute(*paths, 10.0 * CLIPPER_OFFSET_SCALE);
|
||||
|
||||
// unscale output
|
||||
scaleClipperPolygons(*retval, 1.0/CLIPPER_OFFSET_SCALE);
|
||||
|
||||
// delete original data and switch pointer
|
||||
delete subject;
|
||||
subject = retval;
|
||||
scaleClipperPolygons(*paths, 1.0/CLIPPER_OFFSET_SCALE);
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
|
|
@ -70,7 +70,7 @@ template <class T>
|
|||
void _clipper_do(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
|
||||
const Slic3r::Polygons &clip, T &retval, bool safety_offset_);
|
||||
void _clipper_do(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject,
|
||||
const Slic3r::Polygons &clip, ClipperLib::Paths &retval);
|
||||
const Slic3r::Polygons &clip, ClipperLib::Paths &retval, bool safety_offset_);
|
||||
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
|
||||
const Slic3r::Polygons &clip, Slic3r::Polygons &retval, bool safety_offset_);
|
||||
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
|
||||
|
@ -78,15 +78,11 @@ void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
|
|||
void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polylines &subject,
|
||||
const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
||||
|
||||
template <class T>
|
||||
void diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, bool safety_offset_ = false);
|
||||
template <class SubjectType, class ResultType>
|
||||
void diff(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType &retval, bool safety_offset_ = false);
|
||||
|
||||
void diff(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
||||
|
||||
template <class T>
|
||||
void intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, T &retval, bool safety_offset_ = false);
|
||||
|
||||
void intersection(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines &retval);
|
||||
template <class SubjectType, class ResultType>
|
||||
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType &retval, bool safety_offset_ = false);
|
||||
|
||||
void xor_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, Slic3r::ExPolygons &retval,
|
||||
bool safety_offset_ = false);
|
||||
|
@ -101,7 +97,7 @@ static void traverse_pt(ClipperLib::PolyNodes &nodes, Slic3r::Polygons &retval);
|
|||
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::Polygons &retval, bool preserve_collinear = false);
|
||||
void simplify_polygons(const Slic3r::Polygons &subject, Slic3r::ExPolygons &retval, bool preserve_collinear = false);
|
||||
|
||||
void safety_offset(ClipperLib::Paths* &subject);
|
||||
void safety_offset(ClipperLib::Paths* paths);
|
||||
|
||||
/////////////////
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ ExPolygon::get_trapezoids2(Polygons* polygons) const
|
|||
|
||||
// intersect with this expolygon
|
||||
Polygons trapezoids;
|
||||
intersection(poly, *this, trapezoids);
|
||||
intersection<Polygons,Polygons>(poly, *this, trapezoids);
|
||||
|
||||
// append results to return value
|
||||
polygons->insert(polygons->end(), trapezoids.begin(), trapezoids.end());
|
||||
|
|
|
@ -10,31 +10,6 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
bool
|
||||
ExtrusionEntity::is_perimeter() const
|
||||
{
|
||||
return this->role == erPerimeter
|
||||
|| this->role == erExternalPerimeter
|
||||
|| this->role == erOverhangPerimeter
|
||||
|| this->role == erContourInternalPerimeter;
|
||||
}
|
||||
|
||||
bool
|
||||
ExtrusionEntity::is_fill() const
|
||||
{
|
||||
return this->role == erFill
|
||||
|| this->role == erSolidFill
|
||||
|| this->role == erTopSolidFill;
|
||||
}
|
||||
|
||||
bool
|
||||
ExtrusionEntity::is_bridge() const
|
||||
{
|
||||
return this->role == erBrige
|
||||
|| this->role == erInternalBridge
|
||||
|| this->role == erOverhangPerimeter;
|
||||
}
|
||||
|
||||
ExtrusionPath*
|
||||
ExtrusionPath::clone() const
|
||||
{
|
||||
|
@ -64,7 +39,7 @@ ExtrusionPath::intersect_expolygons(const ExPolygonCollection &collection, Extru
|
|||
{
|
||||
// perform clipping
|
||||
Polylines clipped;
|
||||
intersection(this->polyline, collection, clipped);
|
||||
intersection<Polylines,Polylines>(this->polyline, collection, clipped);
|
||||
return this->_inflate_collection(clipped, retval);
|
||||
}
|
||||
|
||||
|
@ -73,7 +48,7 @@ ExtrusionPath::subtract_expolygons(const ExPolygonCollection &collection, Extrus
|
|||
{
|
||||
// perform clipping
|
||||
Polylines clipped;
|
||||
diff(this->polyline, collection, clipped);
|
||||
diff<Polylines,Polylines>(this->polyline, collection, clipped);
|
||||
return this->_inflate_collection(clipped, retval);
|
||||
}
|
||||
|
||||
|
@ -95,6 +70,31 @@ ExtrusionPath::length() const
|
|||
return this->polyline.length();
|
||||
}
|
||||
|
||||
bool
|
||||
ExtrusionPath::is_perimeter() const
|
||||
{
|
||||
return this->role == erPerimeter
|
||||
|| this->role == erExternalPerimeter
|
||||
|| this->role == erOverhangPerimeter
|
||||
|| this->role == erContourInternalPerimeter;
|
||||
}
|
||||
|
||||
bool
|
||||
ExtrusionPath::is_fill() const
|
||||
{
|
||||
return this->role == erFill
|
||||
|| this->role == erSolidFill
|
||||
|| this->role == erTopSolidFill;
|
||||
}
|
||||
|
||||
bool
|
||||
ExtrusionPath::is_bridge() const
|
||||
{
|
||||
return this->role == erBridge
|
||||
|| this->role == erInternalBridge
|
||||
|| this->role == erOverhangPerimeter;
|
||||
}
|
||||
|
||||
void
|
||||
ExtrusionPath::_inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const
|
||||
{
|
||||
|
@ -106,8 +106,22 @@ ExtrusionPath::_inflate_collection(const Polylines &polylines, ExtrusionEntityCo
|
|||
}
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
SV*
|
||||
ExtrusionPath::to_SV_ref() {
|
||||
SV* sv = newSV(0);
|
||||
sv_setref_pv( sv, perl_class_name_ref(this), this );
|
||||
return sv;
|
||||
}
|
||||
|
||||
SV*
|
||||
ExtrusionPath::to_SV_clone_ref() const {
|
||||
SV* sv = newSV(0);
|
||||
sv_setref_pv( sv, perl_class_name(this), new ExtrusionPath(*this) );
|
||||
return sv;
|
||||
}
|
||||
|
||||
REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
|
||||
#endif
|
||||
|
||||
std::string
|
||||
ExtrusionPath::gcode(Extruder* extruder, double e, double F,
|
||||
|
@ -155,12 +169,12 @@ ExtrusionPath::gcode(Extruder* extruder, double e, double F,
|
|||
|
||||
return stream.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
ExtrusionLoop::ExtrusionLoop(const Polygon &polygon, ExtrusionRole role)
|
||||
ExtrusionLoop::operator Polygon() const
|
||||
{
|
||||
this->role = role;
|
||||
this->set_polygon(polygon);
|
||||
Polygon polygon;
|
||||
this->polygon(&polygon);
|
||||
return polygon;
|
||||
}
|
||||
|
||||
ExtrusionLoop*
|
||||
|
@ -169,32 +183,19 @@ ExtrusionLoop::clone() const
|
|||
return new ExtrusionLoop (*this);
|
||||
}
|
||||
|
||||
void
|
||||
ExtrusionLoop::split_at_index(int index, ExtrusionPath* path) const
|
||||
bool
|
||||
ExtrusionLoop::make_clockwise()
|
||||
{
|
||||
Polygon polygon;
|
||||
this->polygon(&polygon);
|
||||
|
||||
polygon.split_at_index(index, &path->polyline);
|
||||
|
||||
path->role = this->role;
|
||||
path->mm3_per_mm = this->mm3_per_mm;
|
||||
path->width = this->width;
|
||||
path->height = this->height;
|
||||
}
|
||||
|
||||
void
|
||||
ExtrusionLoop::split_at_first_point(ExtrusionPath* path) const
|
||||
{
|
||||
return this->split_at_index(0, path);
|
||||
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->polygon(&polygon);
|
||||
|
||||
Polygon polygon = *this;
|
||||
bool was_cw = polygon.is_clockwise();
|
||||
if (was_cw) this->reverse();
|
||||
return was_cw;
|
||||
|
@ -203,41 +204,116 @@ ExtrusionLoop::make_counter_clockwise()
|
|||
void
|
||||
ExtrusionLoop::reverse()
|
||||
{
|
||||
for (Polylines::iterator polyline = this->polylines.begin(); polyline != this->polylines.end(); ++polyline)
|
||||
polyline->reverse();
|
||||
std::reverse(this->polylines.begin(), this->polylines.end());
|
||||
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->polylines.front().points.front();
|
||||
return this->paths.front().polyline.points.front();
|
||||
}
|
||||
|
||||
Point
|
||||
ExtrusionLoop::last_point() const
|
||||
{
|
||||
return this->polylines.back().points.back(); // which coincides with first_point(), by the way
|
||||
}
|
||||
|
||||
void
|
||||
ExtrusionLoop::set_polygon(const Polygon &polygon)
|
||||
{
|
||||
Polyline polyline;
|
||||
polygon.split_at_first_point(&polyline);
|
||||
this->polylines.clear();
|
||||
this->polylines.push_back(polyline);
|
||||
return this->paths.back().polyline.points.back(); // which coincides with first_point(), by the way
|
||||
}
|
||||
|
||||
void
|
||||
ExtrusionLoop::polygon(Polygon* polygon) const
|
||||
{
|
||||
for (Polylines::const_iterator polyline = this->polylines.begin(); polyline != this->polylines.end(); ++polyline) {
|
||||
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(), polyline->points.begin(), polyline->points.end()-1);
|
||||
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(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.points.empty()) 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.points.empty()) 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::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
|
||||
|
|
|
@ -19,7 +19,7 @@ enum ExtrusionRole {
|
|||
erFill,
|
||||
erSolidFill,
|
||||
erTopSolidFill,
|
||||
erBrige,
|
||||
erBridge,
|
||||
erInternalBridge,
|
||||
erSkirt,
|
||||
erSupportMaterial,
|
||||
|
@ -29,19 +29,11 @@ enum ExtrusionRole {
|
|||
class ExtrusionEntity
|
||||
{
|
||||
public:
|
||||
ExtrusionEntity() : mm3_per_mm(-1), width(-1), height(-1) {};
|
||||
virtual ExtrusionEntity* clone() const = 0;
|
||||
virtual ~ExtrusionEntity() {};
|
||||
ExtrusionRole role;
|
||||
double mm3_per_mm; // mm^3 of plastic per mm of linear head motion
|
||||
float width;
|
||||
float height;
|
||||
virtual void reverse() = 0;
|
||||
virtual Point first_point() const = 0;
|
||||
virtual Point last_point() const = 0;
|
||||
bool is_perimeter() const;
|
||||
bool is_fill() const;
|
||||
bool is_bridge() const;
|
||||
};
|
||||
|
||||
typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
|
||||
|
@ -49,8 +41,14 @@ typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
|
|||
class ExtrusionPath : public ExtrusionEntity
|
||||
{
|
||||
public:
|
||||
ExtrusionPath* clone() const;
|
||||
Polyline polyline;
|
||||
ExtrusionRole role;
|
||||
double mm3_per_mm; // mm^3 of plastic per mm of linear head motion
|
||||
float width;
|
||||
float height;
|
||||
|
||||
ExtrusionPath() : mm3_per_mm(-1), width(-1), height(-1) {};
|
||||
ExtrusionPath* clone() const;
|
||||
void reverse();
|
||||
Point first_point() const;
|
||||
Point last_point() const;
|
||||
|
@ -59,32 +57,41 @@ class ExtrusionPath : public ExtrusionEntity
|
|||
void clip_end(double distance);
|
||||
void simplify(double tolerance);
|
||||
double length() const;
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
bool is_perimeter() const;
|
||||
bool is_fill() const;
|
||||
bool is_bridge() const;
|
||||
std::string gcode(Extruder* extruder, double e, double F,
|
||||
double xofs, double yofs, std::string extrusion_axis,
|
||||
std::string gcode_line_suffix) const;
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
SV* to_SV_ref();
|
||||
SV* to_SV_clone_ref() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const;
|
||||
};
|
||||
|
||||
typedef std::vector<ExtrusionPath> ExtrusionPaths;
|
||||
|
||||
class ExtrusionLoop : public ExtrusionEntity
|
||||
{
|
||||
public:
|
||||
Polylines polylines;
|
||||
ExtrusionPaths paths;
|
||||
|
||||
ExtrusionLoop(const Polygon &polygon, ExtrusionRole role);
|
||||
operator Polygon() const;
|
||||
ExtrusionLoop* clone() const;
|
||||
void split_at_index(int index, ExtrusionPath* path) const;
|
||||
void split_at_first_point(ExtrusionPath* path) const;
|
||||
bool make_clockwise();
|
||||
bool make_counter_clockwise();
|
||||
void reverse();
|
||||
Point first_point() const;
|
||||
Point last_point() const;
|
||||
void set_polygon(const Polygon &polygon);
|
||||
void polygon(Polygon* polygon) const;
|
||||
double length() const;
|
||||
void split_at(const Point &point);
|
||||
void clip_end(double distance, ExtrusionPaths* paths) const;
|
||||
bool has_overhang_point(const Point &point) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -55,6 +55,15 @@ MultiPoint::is_valid() const
|
|||
return this->points.size() >= 2;
|
||||
}
|
||||
|
||||
int
|
||||
MultiPoint::find_point(const Point &point) const
|
||||
{
|
||||
for (Points::const_iterator it = this->points.begin(); it != this->points.end(); ++it) {
|
||||
if (it->coincides_with(point)) return it - this->points.begin();
|
||||
}
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
Points
|
||||
MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@ class MultiPoint
|
|||
virtual Lines lines() const = 0;
|
||||
double length() const;
|
||||
bool is_valid() const;
|
||||
int find_point(const Point &point) const;
|
||||
static Points _douglas_peucker(const Points &points, const double tolerance);
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
|
|
|
@ -15,6 +15,13 @@ Polygon::operator Polygons() const
|
|||
return pp;
|
||||
}
|
||||
|
||||
Polygon::operator Polyline() const
|
||||
{
|
||||
Polyline polyline;
|
||||
this->split_at_first_point(&polyline);
|
||||
return polyline;
|
||||
}
|
||||
|
||||
Point&
|
||||
Polygon::operator[](Points::size_type idx)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ typedef std::vector<Polygon> Polygons;
|
|||
class Polygon : public MultiPoint {
|
||||
public:
|
||||
operator Polygons() const;
|
||||
operator Polyline() const;
|
||||
Point& operator[](Points::size_type idx);
|
||||
const Point& operator[](Points::size_type idx) const;
|
||||
Point last_point() const;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue