mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-22 08:11:11 -06:00
Merge branch 'master' into visilibity
Conflicts: lib/Slic3r/GCode.pm xs/MANIFEST
This commit is contained in:
commit
7215e66a6a
68 changed files with 1258 additions and 825 deletions
|
|
@ -358,30 +358,9 @@ void _clipper(ClipperLib::ClipType clipType, const Slic3r::Polygons &subject,
|
|||
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. */
|
||||
|
|
|
|||
|
|
@ -320,6 +320,15 @@ DynamicConfig::option(const t_config_option_key opt_key, bool create) {
|
|||
return this->options[opt_key];
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T*
|
||||
DynamicConfig::opt(const t_config_option_key opt_key, bool create) {
|
||||
return dynamic_cast<T*>(this->option(opt_key, create));
|
||||
}
|
||||
template ConfigOptionInt* DynamicConfig::opt<ConfigOptionInt>(const t_config_option_key opt_key, bool create);
|
||||
template ConfigOptionBool* DynamicConfig::opt<ConfigOptionBool>(const t_config_option_key opt_key, bool create);
|
||||
template ConfigOptionBools* DynamicConfig::opt<ConfigOptionBools>(const t_config_option_key opt_key, bool create);
|
||||
|
||||
const ConfigOption*
|
||||
DynamicConfig::option(const t_config_option_key opt_key) const {
|
||||
return const_cast<DynamicConfig*>(this)->option(opt_key, false);
|
||||
|
|
|
|||
|
|
@ -491,6 +491,7 @@ class DynamicConfig : public ConfigBase
|
|||
DynamicConfig& operator= (DynamicConfig other);
|
||||
void swap(DynamicConfig &other);
|
||||
~DynamicConfig();
|
||||
template<class T> T* opt(const t_config_option_key opt_key, bool create = false);
|
||||
ConfigOption* option(const t_config_option_key opt_key, bool create = false);
|
||||
const ConfigOption* option(const t_config_option_key opt_key) const;
|
||||
void keys(t_config_option_keys *keys) const;
|
||||
|
|
|
|||
|
|
@ -158,7 +158,9 @@ ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines)
|
|||
ma.build(polylines);
|
||||
|
||||
// extend initial and final segments of each polyline (they will be clipped)
|
||||
// unless they represent closed loops
|
||||
for (Polylines::iterator polyline = polylines->begin(); polyline != polylines->end(); ++polyline) {
|
||||
if (polyline->points.front().coincides_with(polyline->points.back())) continue;
|
||||
polyline->extend_start(max_width);
|
||||
polyline->extend_end(max_width);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,23 +72,21 @@ ExtrusionPath::is_perimeter() const
|
|||
{
|
||||
return this->role == erPerimeter
|
||||
|| this->role == erExternalPerimeter
|
||||
|| this->role == erOverhangPerimeter
|
||||
|| this->role == erContourInternalPerimeter;
|
||||
|| this->role == erOverhangPerimeter;
|
||||
}
|
||||
|
||||
bool
|
||||
ExtrusionPath::is_fill() const
|
||||
{
|
||||
return this->role == erFill
|
||||
|| this->role == erSolidFill
|
||||
|| this->role == erTopSolidFill;
|
||||
return this->role == erInternalInfill
|
||||
|| this->role == erSolidInfill
|
||||
|| this->role == erTopSolidInfill;
|
||||
}
|
||||
|
||||
bool
|
||||
ExtrusionPath::is_bridge() const
|
||||
{
|
||||
return this->role == erBridge
|
||||
|| this->role == erInternalBridge
|
||||
return this->role == erBridgeInfill
|
||||
|| this->role == erOverhangPerimeter;
|
||||
}
|
||||
|
||||
|
|
@ -223,7 +221,7 @@ ExtrusionLoop::length() const
|
|||
}
|
||||
|
||||
void
|
||||
ExtrusionLoop::split_at(const Point &point)
|
||||
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);
|
||||
|
|
@ -241,7 +239,7 @@ ExtrusionLoop::split_at(const Point &point)
|
|||
{
|
||||
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);
|
||||
if (p.polyline.is_valid()) new_paths.push_back(p);
|
||||
}
|
||||
|
||||
// then we add all paths until the end of current path list
|
||||
|
|
@ -254,7 +252,7 @@ ExtrusionLoop::split_at(const Point &point)
|
|||
{
|
||||
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);
|
||||
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;
|
||||
|
|
@ -265,6 +263,39 @@ ExtrusionLoop::split_at(const Point &point)
|
|||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,19 +11,26 @@ class ExPolygonCollection;
|
|||
class ExtrusionEntityCollection;
|
||||
class Extruder;
|
||||
|
||||
/* Each ExtrusionRole value identifies a distinct set of { extruder, speed } */
|
||||
enum ExtrusionRole {
|
||||
erPerimeter,
|
||||
erExternalPerimeter,
|
||||
erOverhangPerimeter,
|
||||
erContourInternalPerimeter,
|
||||
erFill,
|
||||
erSolidFill,
|
||||
erTopSolidFill,
|
||||
erBridge,
|
||||
erInternalBridge,
|
||||
erInternalInfill,
|
||||
erSolidInfill,
|
||||
erTopSolidInfill,
|
||||
erBridgeInfill,
|
||||
erGapFill,
|
||||
erSkirt,
|
||||
erSupportMaterial,
|
||||
erGapFill,
|
||||
erSupportMaterialInterface,
|
||||
};
|
||||
|
||||
/* Special flags describing loop */
|
||||
enum ExtrusionLoopRole {
|
||||
elrDefault,
|
||||
elrExternalPerimeter,
|
||||
elrContourInternalPerimeter,
|
||||
};
|
||||
|
||||
class ExtrusionEntity
|
||||
|
|
@ -47,7 +54,7 @@ class ExtrusionPath : public ExtrusionEntity
|
|||
float width;
|
||||
float height;
|
||||
|
||||
ExtrusionPath() : mm3_per_mm(-1), width(-1), height(-1) {};
|
||||
ExtrusionPath(ExtrusionRole role) : role(role), mm3_per_mm(-1), width(-1), height(-1) {};
|
||||
ExtrusionPath* clone() const;
|
||||
void reverse();
|
||||
Point first_point() const;
|
||||
|
|
@ -74,7 +81,9 @@ class ExtrusionLoop : public ExtrusionEntity
|
|||
{
|
||||
public:
|
||||
ExtrusionPaths paths;
|
||||
ExtrusionLoopRole role;
|
||||
|
||||
ExtrusionLoop(ExtrusionLoopRole role = elrDefault) : role(role) {};
|
||||
operator Polygon() const;
|
||||
ExtrusionLoop* clone() const;
|
||||
bool make_clockwise();
|
||||
|
|
@ -84,6 +93,7 @@ class ExtrusionLoop : public ExtrusionEntity
|
|||
Point last_point() const;
|
||||
void polygon(Polygon* polygon) const;
|
||||
double length() const;
|
||||
void split_at_vertex(const Point &point);
|
||||
void split_at(const Point &point);
|
||||
void clip_end(double distance, ExtrusionPaths* paths) const;
|
||||
bool has_overhang_point(const Point &point) const;
|
||||
|
|
|
|||
|
|
@ -123,6 +123,21 @@ MedialAxis::build(Polylines* polylines)
|
|||
|
||||
construct_voronoi(this->lines.begin(), this->lines.end(), &this->vd);
|
||||
|
||||
/*
|
||||
// DEBUG: dump all Voronoi edges
|
||||
{
|
||||
for (VD::const_edge_iterator edge = this->vd.edges().begin(); edge != this->vd.edges().end(); ++edge) {
|
||||
if (edge->is_infinite()) continue;
|
||||
|
||||
Polyline polyline;
|
||||
polyline.points.push_back(Point( edge->vertex0()->x(), edge->vertex0()->y() ));
|
||||
polyline.points.push_back(Point( edge->vertex1()->x(), edge->vertex1()->y() ));
|
||||
polylines->push_back(polyline);
|
||||
}
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// collect valid edges (i.e. prune those not belonging to MAT)
|
||||
// note: this keeps twins, so it contains twice the number of the valid edges
|
||||
this->edges.clear();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
#include "MultiPoint.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
MultiPoint::operator Points() const
|
||||
{
|
||||
return this->points;
|
||||
}
|
||||
|
||||
void
|
||||
MultiPoint::scale(double factor)
|
||||
{
|
||||
|
|
@ -64,6 +70,12 @@ MultiPoint::find_point(const Point &point) const
|
|||
return -1; // not found
|
||||
}
|
||||
|
||||
void
|
||||
MultiPoint::bounding_box(BoundingBox* bb) const
|
||||
{
|
||||
*bb = BoundingBox(this->points);
|
||||
}
|
||||
|
||||
Points
|
||||
MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,17 +2,21 @@
|
|||
#define slic3r_MultiPoint_hpp_
|
||||
|
||||
#include <myinit.h>
|
||||
#include "Line.hpp"
|
||||
#include "Point.hpp"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "Line.hpp"
|
||||
#include "Point.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class BoundingBox;
|
||||
|
||||
class MultiPoint
|
||||
{
|
||||
public:
|
||||
Points points;
|
||||
|
||||
operator Points() const;
|
||||
void scale(double factor);
|
||||
void translate(double x, double y);
|
||||
void rotate(double angle, const Point ¢er);
|
||||
|
|
@ -23,6 +27,8 @@ class MultiPoint
|
|||
double length() const;
|
||||
bool is_valid() const;
|
||||
int find_point(const Point &point) const;
|
||||
void bounding_box(BoundingBox* bb) const;
|
||||
|
||||
static Points _douglas_peucker(const Points &points, const double tolerance);
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
#include "Point.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "MultiPoint.hpp"
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
Point::Point(double x, double y)
|
||||
{
|
||||
this->x = lrint(x);
|
||||
this->y = lrint(y);
|
||||
}
|
||||
|
||||
bool
|
||||
Point::operator==(const Point& rhs) const
|
||||
{
|
||||
|
|
@ -138,6 +145,69 @@ Point::ccw(const Line &line) const
|
|||
return this->ccw(line.a, line.b);
|
||||
}
|
||||
|
||||
Point
|
||||
Point::projection_onto(const MultiPoint &poly) const
|
||||
{
|
||||
Point running_projection = poly.first_point();
|
||||
double running_min = this->distance_to(running_projection);
|
||||
|
||||
Lines lines = poly.lines();
|
||||
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
|
||||
Point point_temp = this->projection_onto(*line);
|
||||
if (this->distance_to(point_temp) < running_min) {
|
||||
running_projection = point_temp;
|
||||
running_min = this->distance_to(running_projection);
|
||||
}
|
||||
}
|
||||
return running_projection;
|
||||
}
|
||||
|
||||
Point
|
||||
Point::projection_onto(const Line &line) const
|
||||
{
|
||||
if (line.a.coincides_with(line.b)) return line.a;
|
||||
|
||||
/*
|
||||
(Ported from VisiLibity by Karl J. Obermeyer)
|
||||
The projection of point_temp onto the line determined by
|
||||
line_segment_temp can be represented as an affine combination
|
||||
expressed in the form projection of
|
||||
Point = theta*line_segment_temp.first + (1.0-theta)*line_segment_temp.second.
|
||||
If theta is outside the interval [0,1], then one of the Line_Segment's endpoints
|
||||
must be closest to calling Point.
|
||||
*/
|
||||
double theta = ( (double)(line.b.x - this->x)*(double)(line.b.x - line.a.x) + (double)(line.b.y- this->y)*(double)(line.b.y - line.a.y) )
|
||||
/ ( (double)pow(line.b.x - line.a.x, 2) + (double)pow(line.b.y - line.a.y, 2) );
|
||||
|
||||
if (0.0 <= theta && theta <= 1.0)
|
||||
return theta * line.a + (1.0-theta) * line.b;
|
||||
|
||||
// Else pick closest endpoint.
|
||||
if (this->distance_to(line.a) < this->distance_to(line.b)) {
|
||||
return line.a;
|
||||
} else {
|
||||
return line.b;
|
||||
}
|
||||
}
|
||||
|
||||
Point
|
||||
Point::negative() const
|
||||
{
|
||||
return Point(-this->x, -this->y);
|
||||
}
|
||||
|
||||
Point
|
||||
operator+(const Point& point1, const Point& point2)
|
||||
{
|
||||
return Point(point1.x + point2.x, point1.y + point2.y);
|
||||
}
|
||||
|
||||
Point
|
||||
operator*(double scalar, const Point& point2)
|
||||
{
|
||||
return Point(scalar * point2.x, scalar * point2.y);
|
||||
}
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
|
||||
REGISTER_CLASS(Point, "Point");
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
namespace Slic3r {
|
||||
|
||||
class Line;
|
||||
class MultiPoint;
|
||||
class Point;
|
||||
class Pointf;
|
||||
typedef Point Vector;
|
||||
|
|
@ -22,7 +23,10 @@ class Point
|
|||
public:
|
||||
coord_t x;
|
||||
coord_t y;
|
||||
explicit Point(coord_t _x = 0, coord_t _y = 0): x(_x), y(_y) {};
|
||||
Point(coord_t _x = 0, coord_t _y = 0): x(_x), y(_y) {};
|
||||
Point(int _x, int _y): x(_x), y(_y) {};
|
||||
Point(long long _x, long long _y): x(_x), y(_y) {}; // for Clipper
|
||||
Point(double x, double y);
|
||||
bool operator==(const Point& rhs) const;
|
||||
std::string wkt() const;
|
||||
void scale(double factor);
|
||||
|
|
@ -37,6 +41,9 @@ class Point
|
|||
double distance_to(const Line &line) const;
|
||||
double ccw(const Point &p1, const Point &p2) const;
|
||||
double ccw(const Line &line) const;
|
||||
Point projection_onto(const MultiPoint &poly) const;
|
||||
Point projection_onto(const Line &line) const;
|
||||
Point negative() const;
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
void from_SV(SV* point_sv);
|
||||
|
|
@ -45,6 +52,9 @@ class Point
|
|||
#endif
|
||||
};
|
||||
|
||||
Point operator+(const Point& point1, const Point& point2);
|
||||
Point operator*(double scalar, const Point& point2);
|
||||
|
||||
class Point3 : public Point
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ Polygon::lines(Lines* lines) const
|
|||
}
|
||||
|
||||
void
|
||||
Polygon::split_at(const Point &point, Polyline* polyline) const
|
||||
Polygon::split_at_vertex(const Point &point, Polyline* polyline) const
|
||||
{
|
||||
// find index of point
|
||||
for (Points::const_iterator it = this->points.begin(); it != this->points.end(); ++it) {
|
||||
|
|
@ -191,6 +191,24 @@ Polygon::triangulate_convex(Polygons* polygons) const
|
|||
}
|
||||
}
|
||||
|
||||
// center of mass
|
||||
Point
|
||||
Polygon::centroid() const
|
||||
{
|
||||
double area_temp = this->area();
|
||||
double x_temp = 0;
|
||||
double y_temp = 0;
|
||||
|
||||
Polyline polyline;
|
||||
this->split_at_first_point(&polyline);
|
||||
for (Points::const_iterator point = polyline.points.begin(); point != polyline.points.end() - 1; ++point) {
|
||||
x_temp += (double)( point->x + (point+1)->x ) * ( (double)point->x*(point+1)->y - (double)(point+1)->x*point->y );
|
||||
y_temp += (double)( point->y + (point+1)->y ) * ( (double)point->x*(point+1)->y - (double)(point+1)->x*point->y );
|
||||
}
|
||||
|
||||
return Point(x_temp/(6*area_temp), y_temp/(6*area_temp));
|
||||
}
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
REGISTER_CLASS(Polygon, "Polygon");
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class Polygon : public MultiPoint {
|
|||
Point last_point() const;
|
||||
Lines lines() const;
|
||||
void lines(Lines* lines) const;
|
||||
void split_at(const Point &point, Polyline* polyline) const;
|
||||
void split_at_vertex(const Point &point, Polyline* polyline) const;
|
||||
void split_at_index(int index, Polyline* polyline) const;
|
||||
void split_at_first_point(Polyline* polyline) const;
|
||||
void equally_spaced_points(double distance, Points* points) const;
|
||||
|
|
@ -35,6 +35,7 @@ class Polygon : public MultiPoint {
|
|||
Polygons simplify(double tolerance) const;
|
||||
void simplify(double tolerance, Polygons &polygons) const;
|
||||
void triangulate_convex(Polygons* polygons) const;
|
||||
Point centroid() const;
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
void from_SV_check(SV* poly_sv);
|
||||
|
|
|
|||
|
|
@ -119,6 +119,42 @@ Polyline::simplify(double tolerance)
|
|||
this->points = MultiPoint::_douglas_peucker(this->points, tolerance);
|
||||
}
|
||||
|
||||
void
|
||||
Polyline::split_at(const Point &point, Polyline* p1, Polyline* p2) const
|
||||
{
|
||||
if (this->points.empty()) return;
|
||||
|
||||
// find the line to split at
|
||||
size_t line_idx = 0;
|
||||
Point p = this->first_point();
|
||||
double min = point.distance_to(p);
|
||||
Lines lines = this->lines();
|
||||
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
|
||||
Point p_tmp = point.projection_onto(*line);
|
||||
if (point.distance_to(p_tmp) < min) {
|
||||
p = p_tmp;
|
||||
min = point.distance_to(p);
|
||||
line_idx = line - lines.begin();
|
||||
}
|
||||
}
|
||||
|
||||
// create first half
|
||||
p1->points.clear();
|
||||
for (Lines::const_iterator line = lines.begin(); line != lines.begin() + line_idx + 1; ++line) {
|
||||
if (!line->a.coincides_with(p)) p1->points.push_back(line->a);
|
||||
}
|
||||
// we add point instead of p because they might differ because of numerical issues
|
||||
// and caller might want to rely on point belonging to result polylines
|
||||
p1->points.push_back(point);
|
||||
|
||||
// create second half
|
||||
p2->points.clear();
|
||||
p2->points.push_back(point);
|
||||
for (Lines::const_iterator line = lines.begin() + line_idx; line != lines.end(); ++line) {
|
||||
if (!line->b.coincides_with(p)) p2->points.push_back(line->b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
REGISTER_CLASS(Polyline, "Polyline");
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ class Polyline : public MultiPoint {
|
|||
void extend_start(double distance);
|
||||
void equally_spaced_points(double distance, Points* points) const;
|
||||
void simplify(double tolerance);
|
||||
void split_at(const Point &point, Polyline* p1, Polyline* p2) const;
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
void from_SV_check(SV* poly_sv);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ enum SupportMaterialPattern {
|
|||
smpRectilinear, smpRectilinearGrid, smpHoneycomb, smpPillars,
|
||||
};
|
||||
|
||||
enum SeamPosition {
|
||||
spRandom, spNearest, spAligned
|
||||
};
|
||||
|
||||
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
||||
t_config_enum_values keys_map;
|
||||
keys_map["reprap"] = gcfRepRap;
|
||||
|
|
@ -50,6 +54,14 @@ template<> inline t_config_enum_values ConfigOptionEnum<SupportMaterialPattern>:
|
|||
return keys_map;
|
||||
}
|
||||
|
||||
template<> inline t_config_enum_values ConfigOptionEnum<SeamPosition>::get_enum_values() {
|
||||
t_config_enum_values keys_map;
|
||||
keys_map["random"] = spRandom;
|
||||
keys_map["nearest"] = spNearest;
|
||||
keys_map["aligned"] = spAligned;
|
||||
return keys_map;
|
||||
}
|
||||
|
||||
class PrintConfigDef
|
||||
{
|
||||
public:
|
||||
|
|
@ -105,6 +117,7 @@ class PrintConfigDef
|
|||
|
||||
Options["bridge_speed"].type = coFloat;
|
||||
Options["bridge_speed"].label = "Bridges";
|
||||
Options["bridge_speed"].category = "Speed";
|
||||
Options["bridge_speed"].tooltip = "Speed for printing bridges.";
|
||||
Options["bridge_speed"].sidetext = "mm/s";
|
||||
Options["bridge_speed"].cli = "bridge-speed=f";
|
||||
|
|
@ -161,6 +174,7 @@ class PrintConfigDef
|
|||
|
||||
Options["external_perimeter_speed"].type = coFloatOrPercent;
|
||||
Options["external_perimeter_speed"].label = "External perimeters";
|
||||
Options["external_perimeter_speed"].category = "Speed";
|
||||
Options["external_perimeter_speed"].tooltip = "This separate setting will affect the speed of external perimeters (the visible ones). If expressed as percentage (for example: 80%) it will be calculated on the perimeters speed setting above.";
|
||||
Options["external_perimeter_speed"].sidetext = "mm/s or %";
|
||||
Options["external_perimeter_speed"].cli = "external-perimeter-speed=s";
|
||||
|
|
@ -357,6 +371,7 @@ class PrintConfigDef
|
|||
|
||||
Options["gap_fill_speed"].type = coFloat;
|
||||
Options["gap_fill_speed"].label = "Gap fill";
|
||||
Options["gap_fill_speed"].category = "Speed";
|
||||
Options["gap_fill_speed"].tooltip = "Speed for filling small gaps using short zigzag moves. Keep this reasonably low to avoid too much shaking and resonance issues. Set zero to disable gaps filling.";
|
||||
Options["gap_fill_speed"].sidetext = "mm/s";
|
||||
Options["gap_fill_speed"].cli = "gap-fill-speed=f";
|
||||
|
|
@ -431,6 +446,7 @@ class PrintConfigDef
|
|||
|
||||
Options["infill_speed"].type = coFloat;
|
||||
Options["infill_speed"].label = "Infill";
|
||||
Options["infill_speed"].category = "Speed";
|
||||
Options["infill_speed"].tooltip = "Speed for printing the internal fill.";
|
||||
Options["infill_speed"].sidetext = "mm/s";
|
||||
Options["infill_speed"].cli = "infill-speed=f";
|
||||
|
|
@ -546,6 +562,7 @@ class PrintConfigDef
|
|||
|
||||
Options["perimeter_speed"].type = coFloat;
|
||||
Options["perimeter_speed"].label = "Perimeters";
|
||||
Options["perimeter_speed"].category = "Speed";
|
||||
Options["perimeter_speed"].tooltip = "Speed for perimeters (contours, aka vertical shells).";
|
||||
Options["perimeter_speed"].sidetext = "mm/s";
|
||||
Options["perimeter_speed"].cli = "perimeter-speed=f";
|
||||
|
|
@ -579,11 +596,6 @@ class PrintConfigDef
|
|||
Options["raft_layers"].sidetext = "layers";
|
||||
Options["raft_layers"].cli = "raft-layers=i";
|
||||
|
||||
Options["randomize_start"].type = coBool;
|
||||
Options["randomize_start"].label = "Randomize starting points";
|
||||
Options["randomize_start"].tooltip = "Start each layer from a different vertex to prevent plastic build-up on the same corner.";
|
||||
Options["randomize_start"].cli = "randomize-start!";
|
||||
|
||||
Options["resolution"].type = coFloat;
|
||||
Options["resolution"].label = "Resolution";
|
||||
Options["resolution"].tooltip = "Minimum detail resolution, used to simplify the input file for speeding up the slicing job and reducing memory usage. High-resolution models often carry more detail than printers can render. Set to zero to disable any simplification and use full resolution from input.";
|
||||
|
|
@ -639,6 +651,19 @@ class PrintConfigDef
|
|||
Options["retract_speed"].cli = "retract-speed=f@";
|
||||
Options["retract_speed"].max = 1000;
|
||||
|
||||
Options["seam_position"].type = coEnum;
|
||||
Options["seam_position"].label = "Seam position";
|
||||
Options["seam_position"].category = "Layers and perimeters";
|
||||
Options["seam_position"].tooltip = "Position of perimeters starting points.";
|
||||
Options["seam_position"].cli = "seam-position=s";
|
||||
Options["seam_position"].enum_keys_map = ConfigOptionEnum<SeamPosition>::get_enum_values();
|
||||
Options["seam_position"].enum_values.push_back("random");
|
||||
Options["seam_position"].enum_values.push_back("nearest");
|
||||
Options["seam_position"].enum_values.push_back("aligned");
|
||||
Options["seam_position"].enum_labels.push_back("Random");
|
||||
Options["seam_position"].enum_labels.push_back("Nearest");
|
||||
Options["seam_position"].enum_labels.push_back("Aligned");
|
||||
|
||||
Options["skirt_distance"].type = coFloat;
|
||||
Options["skirt_distance"].label = "Distance from object";
|
||||
Options["skirt_distance"].tooltip = "Distance between skirt and object(s). Set this to zero to attach the skirt to the object(s) and get a brim for better adhesion.";
|
||||
|
|
@ -666,6 +691,7 @@ class PrintConfigDef
|
|||
|
||||
Options["small_perimeter_speed"].type = coFloatOrPercent;
|
||||
Options["small_perimeter_speed"].label = "Small perimeters";
|
||||
Options["small_perimeter_speed"].category = "Speed";
|
||||
Options["small_perimeter_speed"].tooltip = "This separate setting will affect the speed of perimeters having radius <= 6.5mm (usually holes). If expressed as percentage (for example: 80%) it will be calculated on the perimeters speed setting above.";
|
||||
Options["small_perimeter_speed"].sidetext = "mm/s or %";
|
||||
Options["small_perimeter_speed"].cli = "small-perimeter-speed=s";
|
||||
|
|
@ -712,6 +738,7 @@ class PrintConfigDef
|
|||
|
||||
Options["solid_infill_speed"].type = coFloatOrPercent;
|
||||
Options["solid_infill_speed"].label = "Solid infill";
|
||||
Options["solid_infill_speed"].category = "Speed";
|
||||
Options["solid_infill_speed"].tooltip = "Speed for printing solid regions (top/bottom/internal horizontal shells). This can be expressed as a percentage (for example: 80%) over the default infill speed above.";
|
||||
Options["solid_infill_speed"].sidetext = "mm/s or %";
|
||||
Options["solid_infill_speed"].cli = "solid-infill-speed=s";
|
||||
|
|
@ -746,16 +773,6 @@ class PrintConfigDef
|
|||
Options["start_gcode"].full_width = true;
|
||||
Options["start_gcode"].height = 120;
|
||||
|
||||
Options["start_perimeters_at_concave_points"].type = coBool;
|
||||
Options["start_perimeters_at_concave_points"].label = "Concave points";
|
||||
Options["start_perimeters_at_concave_points"].tooltip = "Prefer to start perimeters at a concave point.";
|
||||
Options["start_perimeters_at_concave_points"].cli = "start-perimeters-at-concave-points!";
|
||||
|
||||
Options["start_perimeters_at_non_overhang"].type = coBool;
|
||||
Options["start_perimeters_at_non_overhang"].label = "Non-overhang points";
|
||||
Options["start_perimeters_at_non_overhang"].tooltip = "Prefer to start perimeters at non-overhanging points.";
|
||||
Options["start_perimeters_at_non_overhang"].cli = "start-perimeters-at-non-overhang!";
|
||||
|
||||
Options["support_material"].type = coBool;
|
||||
Options["support_material"].label = "Generate support material";
|
||||
Options["support_material"].category = "Support material";
|
||||
|
|
@ -812,6 +829,14 @@ class PrintConfigDef
|
|||
Options["support_material_interface_spacing"].sidetext = "mm";
|
||||
Options["support_material_interface_spacing"].cli = "support-material-interface-spacing=f";
|
||||
|
||||
Options["support_material_interface_speed"].type = coFloatOrPercent;
|
||||
Options["support_material_interface_speed"].label = "Support material interface";
|
||||
Options["support_material_interface_speed"].category = "Support material";
|
||||
Options["support_material_interface_speed"].tooltip = "Speed for printing support material interface layers. If expressed as percentage (for example 50%) it will be calculated over support material speed.";
|
||||
Options["support_material_interface_speed"].sidetext = "mm/s or %";
|
||||
Options["support_material_interface_speed"].cli = "support-material-interface-speed=s";
|
||||
Options["support_material_interface_speed"].ratio_over = "support_material_speed";
|
||||
|
||||
Options["support_material_pattern"].type = coEnum;
|
||||
Options["support_material_pattern"].label = "Pattern";
|
||||
Options["support_material_pattern"].category = "Support material";
|
||||
|
|
@ -889,6 +914,7 @@ class PrintConfigDef
|
|||
|
||||
Options["top_solid_infill_speed"].type = coFloatOrPercent;
|
||||
Options["top_solid_infill_speed"].label = "Top solid infill";
|
||||
Options["top_solid_infill_speed"].category = "Speed";
|
||||
Options["top_solid_infill_speed"].tooltip = "Speed for printing top solid layers (it only applies to the uppermost external layers and not to their internal solid layers). You may want to slow down this to get a nicer surface finish. This can be expressed as a percentage (for example: 80%) over the solid infill speed above.";
|
||||
Options["top_solid_infill_speed"].sidetext = "mm/s or %";
|
||||
Options["top_solid_infill_speed"].cli = "top-solid-infill-speed=s";
|
||||
|
|
@ -959,6 +985,13 @@ class DynamicPrintConfig : public DynamicConfig
|
|||
if (!this->has("support_material_interface_extruder"))
|
||||
this->option("support_material_interface_extruder", true)->setInt(extruder);
|
||||
}
|
||||
if (this->has("spiral_vase") && this->opt<ConfigOptionBool>("spiral_vase", true)->value) {
|
||||
{
|
||||
// this should be actually done only on the spiral layers instead of all
|
||||
ConfigOptionBools* opt = this->opt<ConfigOptionBools>("retract_layer_change", true);
|
||||
opt->values.assign(opt->values.size(), false); // set all values to false
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -980,6 +1013,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||
ConfigOptionBool interface_shells;
|
||||
ConfigOptionFloat layer_height;
|
||||
ConfigOptionInt raft_layers;
|
||||
ConfigOptionEnum<SeamPosition> seam_position;
|
||||
ConfigOptionBool support_material;
|
||||
ConfigOptionInt support_material_angle;
|
||||
ConfigOptionInt support_material_enforce_layers;
|
||||
|
|
@ -988,6 +1022,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||
ConfigOptionInt support_material_interface_extruder;
|
||||
ConfigOptionInt support_material_interface_layers;
|
||||
ConfigOptionFloat support_material_interface_spacing;
|
||||
ConfigOptionFloatOrPercent support_material_interface_speed;
|
||||
ConfigOptionEnum<SupportMaterialPattern> support_material_pattern;
|
||||
ConfigOptionFloat support_material_spacing;
|
||||
ConfigOptionFloat support_material_speed;
|
||||
|
|
@ -1003,6 +1038,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||
this->interface_shells.value = false;
|
||||
this->layer_height.value = 0.4;
|
||||
this->raft_layers.value = 0;
|
||||
this->seam_position.value = spAligned;
|
||||
this->support_material.value = false;
|
||||
this->support_material_angle.value = 0;
|
||||
this->support_material_enforce_layers.value = 0;
|
||||
|
|
@ -1012,6 +1048,8 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||
this->support_material_interface_extruder.value = 1;
|
||||
this->support_material_interface_layers.value = 3;
|
||||
this->support_material_interface_spacing.value = 0;
|
||||
this->support_material_interface_speed.value = 100;
|
||||
this->support_material_interface_speed.percent = true;
|
||||
this->support_material_pattern.value = smpPillars;
|
||||
this->support_material_spacing.value = 2.5;
|
||||
this->support_material_speed.value = 60;
|
||||
|
|
@ -1026,6 +1064,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||
if (opt_key == "interface_shells") return &this->interface_shells;
|
||||
if (opt_key == "layer_height") return &this->layer_height;
|
||||
if (opt_key == "raft_layers") return &this->raft_layers;
|
||||
if (opt_key == "seam_position") return &this->seam_position;
|
||||
if (opt_key == "support_material") return &this->support_material;
|
||||
if (opt_key == "support_material_angle") return &this->support_material_angle;
|
||||
if (opt_key == "support_material_enforce_layers") return &this->support_material_enforce_layers;
|
||||
|
|
@ -1034,6 +1073,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||
if (opt_key == "support_material_interface_extruder") return &this->support_material_interface_extruder;
|
||||
if (opt_key == "support_material_interface_layers") return &this->support_material_interface_layers;
|
||||
if (opt_key == "support_material_interface_spacing") return &this->support_material_interface_spacing;
|
||||
if (opt_key == "support_material_interface_speed") return &this->support_material_interface_speed;
|
||||
if (opt_key == "support_material_pattern") return &this->support_material_pattern;
|
||||
if (opt_key == "support_material_spacing") return &this->support_material_spacing;
|
||||
if (opt_key == "support_material_speed") return &this->support_material_speed;
|
||||
|
|
@ -1047,67 +1087,98 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
|||
{
|
||||
public:
|
||||
ConfigOptionInt bottom_solid_layers;
|
||||
ConfigOptionFloat bridge_speed;
|
||||
ConfigOptionFloatOrPercent external_perimeter_speed;
|
||||
ConfigOptionBool extra_perimeters;
|
||||
ConfigOptionInt fill_angle;
|
||||
ConfigOptionPercent fill_density;
|
||||
ConfigOptionEnum<InfillPattern> fill_pattern;
|
||||
ConfigOptionFloat gap_fill_speed;
|
||||
ConfigOptionInt infill_extruder;
|
||||
ConfigOptionFloatOrPercent infill_extrusion_width;
|
||||
ConfigOptionInt infill_every_layers;
|
||||
ConfigOptionFloat infill_speed;
|
||||
ConfigOptionBool overhangs;
|
||||
ConfigOptionInt perimeter_extruder;
|
||||
ConfigOptionFloatOrPercent perimeter_extrusion_width;
|
||||
ConfigOptionFloat perimeter_speed;
|
||||
ConfigOptionInt perimeters;
|
||||
ConfigOptionFloatOrPercent small_perimeter_speed;
|
||||
ConfigOptionEnum<InfillPattern> solid_fill_pattern;
|
||||
ConfigOptionFloat solid_infill_below_area;
|
||||
ConfigOptionFloatOrPercent solid_infill_extrusion_width;
|
||||
ConfigOptionInt solid_infill_every_layers;
|
||||
ConfigOptionFloatOrPercent solid_infill_speed;
|
||||
ConfigOptionBool thin_walls;
|
||||
ConfigOptionFloatOrPercent top_infill_extrusion_width;
|
||||
ConfigOptionInt top_solid_layers;
|
||||
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
||||
|
||||
PrintRegionConfig() : StaticPrintConfig() {
|
||||
this->bottom_solid_layers.value = 3;
|
||||
this->bridge_speed.value = 60;
|
||||
this->external_perimeter_speed.value = 70;
|
||||
this->external_perimeter_speed.percent = true;
|
||||
this->extra_perimeters.value = true;
|
||||
this->fill_angle.value = 45;
|
||||
this->fill_density.value = 40;
|
||||
this->fill_pattern.value = ipHoneycomb;
|
||||
this->gap_fill_speed.value = 20;
|
||||
this->infill_extruder.value = 1;
|
||||
this->infill_extrusion_width.value = 0;
|
||||
this->infill_extrusion_width.percent = false;
|
||||
this->infill_every_layers.value = 1;
|
||||
this->infill_speed.value = 60;
|
||||
this->overhangs.value = true;
|
||||
this->perimeter_extruder.value = 1;
|
||||
this->perimeter_extrusion_width.value = 0;
|
||||
this->perimeter_extrusion_width.percent = false;
|
||||
this->perimeter_speed.value = 30;
|
||||
this->perimeters.value = 3;
|
||||
this->small_perimeter_speed.value = 30;
|
||||
this->small_perimeter_speed.percent = false;
|
||||
this->solid_fill_pattern.value = ipRectilinear;
|
||||
this->solid_infill_below_area.value = 70;
|
||||
this->solid_infill_extrusion_width.value = 0;
|
||||
this->solid_infill_extrusion_width.percent = false;
|
||||
this->solid_infill_every_layers.value = 0;
|
||||
this->solid_infill_speed.value = 60;
|
||||
this->solid_infill_speed.percent = false;
|
||||
this->thin_walls.value = true;
|
||||
this->top_infill_extrusion_width.value = 0;
|
||||
this->top_infill_extrusion_width.percent = false;
|
||||
this->top_solid_infill_speed.value = 50;
|
||||
this->top_solid_infill_speed.percent = false;
|
||||
this->top_solid_layers.value = 3;
|
||||
};
|
||||
|
||||
ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
|
||||
if (opt_key == "bottom_solid_layers") return &this->bottom_solid_layers;
|
||||
if (opt_key == "bridge_speed") return &this->bridge_speed;
|
||||
if (opt_key == "external_perimeter_speed") return &this->external_perimeter_speed;
|
||||
if (opt_key == "extra_perimeters") return &this->extra_perimeters;
|
||||
if (opt_key == "fill_angle") return &this->fill_angle;
|
||||
if (opt_key == "fill_density") return &this->fill_density;
|
||||
if (opt_key == "fill_pattern") return &this->fill_pattern;
|
||||
if (opt_key == "gap_fill_speed") return &this->gap_fill_speed;
|
||||
if (opt_key == "infill_extruder") return &this->infill_extruder;
|
||||
if (opt_key == "infill_extrusion_width") return &this->infill_extrusion_width;
|
||||
if (opt_key == "infill_every_layers") return &this->infill_every_layers;
|
||||
if (opt_key == "infill_speed") return &this->infill_speed;
|
||||
if (opt_key == "overhangs") return &this->overhangs;
|
||||
if (opt_key == "perimeter_extruder") return &this->perimeter_extruder;
|
||||
if (opt_key == "perimeter_extrusion_width") return &this->perimeter_extrusion_width;
|
||||
if (opt_key == "perimeter_speed") return &this->perimeter_speed;
|
||||
if (opt_key == "perimeters") return &this->perimeters;
|
||||
if (opt_key == "small_perimeter_speed") return &this->small_perimeter_speed;
|
||||
if (opt_key == "solid_fill_pattern") return &this->solid_fill_pattern;
|
||||
if (opt_key == "solid_infill_below_area") return &this->solid_infill_below_area;
|
||||
if (opt_key == "solid_infill_extrusion_width") return &this->solid_infill_extrusion_width;
|
||||
if (opt_key == "solid_infill_every_layers") return &this->solid_infill_every_layers;
|
||||
if (opt_key == "solid_infill_speed") return &this->solid_infill_speed;
|
||||
if (opt_key == "thin_walls") return &this->thin_walls;
|
||||
if (opt_key == "top_infill_extrusion_width") return &this->top_infill_extrusion_width;
|
||||
if (opt_key == "top_solid_infill_speed") return &this->top_solid_infill_speed;
|
||||
if (opt_key == "top_solid_layers") return &this->top_solid_layers;
|
||||
|
||||
return NULL;
|
||||
|
|
@ -1123,7 +1194,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
ConfigOptionFloat bridge_acceleration;
|
||||
ConfigOptionInt bridge_fan_speed;
|
||||
ConfigOptionFloat bridge_flow_ratio;
|
||||
ConfigOptionFloat bridge_speed;
|
||||
ConfigOptionFloat brim_width;
|
||||
ConfigOptionBool complete_objects;
|
||||
ConfigOptionBool cooling;
|
||||
|
|
@ -1131,7 +1201,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
ConfigOptionInt disable_fan_first_layers;
|
||||
ConfigOptionFloat duplicate_distance;
|
||||
ConfigOptionString end_gcode;
|
||||
ConfigOptionFloatOrPercent external_perimeter_speed;
|
||||
ConfigOptionBool external_perimeters_first;
|
||||
ConfigOptionFloat extruder_clearance_height;
|
||||
ConfigOptionFloat extruder_clearance_radius;
|
||||
|
|
@ -1147,13 +1216,11 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
ConfigOptionFloatOrPercent first_layer_speed;
|
||||
ConfigOptionInts first_layer_temperature;
|
||||
ConfigOptionBool g0;
|
||||
ConfigOptionFloat gap_fill_speed;
|
||||
ConfigOptionBool gcode_arcs;
|
||||
ConfigOptionBool gcode_comments;
|
||||
ConfigOptionEnum<GCodeFlavor> gcode_flavor;
|
||||
ConfigOptionFloat infill_acceleration;
|
||||
ConfigOptionBool infill_first;
|
||||
ConfigOptionFloat infill_speed;
|
||||
ConfigOptionString layer_gcode;
|
||||
ConfigOptionInt max_fan_speed;
|
||||
ConfigOptionInt min_fan_speed;
|
||||
|
|
@ -1164,12 +1231,9 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
ConfigOptionBool only_retract_when_crossing_perimeters;
|
||||
ConfigOptionBool ooze_prevention;
|
||||
ConfigOptionString output_filename_format;
|
||||
ConfigOptionBool overhangs;
|
||||
ConfigOptionFloat perimeter_acceleration;
|
||||
ConfigOptionFloat perimeter_speed;
|
||||
ConfigOptionStrings post_process;
|
||||
ConfigOptionPoint print_center;
|
||||
ConfigOptionBool randomize_start;
|
||||
ConfigOptionFloat resolution;
|
||||
ConfigOptionFloats retract_before_travel;
|
||||
ConfigOptionBools retract_layer_change;
|
||||
|
|
@ -1183,17 +1247,12 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
ConfigOptionInt skirt_height;
|
||||
ConfigOptionInt skirts;
|
||||
ConfigOptionInt slowdown_below_layer_time;
|
||||
ConfigOptionFloatOrPercent small_perimeter_speed;
|
||||
ConfigOptionFloatOrPercent solid_infill_speed;
|
||||
ConfigOptionBool spiral_vase;
|
||||
ConfigOptionInt standby_temperature_delta;
|
||||
ConfigOptionString start_gcode;
|
||||
ConfigOptionBool start_perimeters_at_concave_points;
|
||||
ConfigOptionBool start_perimeters_at_non_overhang;
|
||||
ConfigOptionInts temperature;
|
||||
ConfigOptionInt threads;
|
||||
ConfigOptionString toolchange_gcode;
|
||||
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
||||
ConfigOptionFloat travel_speed;
|
||||
ConfigOptionBool use_firmware_retraction;
|
||||
ConfigOptionBool use_relative_e_distances;
|
||||
|
|
@ -1208,7 +1267,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
this->bridge_acceleration.value = 0;
|
||||
this->bridge_fan_speed.value = 100;
|
||||
this->bridge_flow_ratio.value = 1;
|
||||
this->bridge_speed.value = 60;
|
||||
this->brim_width.value = 0;
|
||||
this->complete_objects.value = false;
|
||||
this->cooling.value = true;
|
||||
|
|
@ -1216,8 +1274,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
this->disable_fan_first_layers.value = 1;
|
||||
this->duplicate_distance.value = 6;
|
||||
this->end_gcode.value = "M104 S0 ; turn off temperature\nG28 X0 ; home X axis\nM84 ; disable motors\n";
|
||||
this->external_perimeter_speed.value = 70;
|
||||
this->external_perimeter_speed.percent = true;
|
||||
this->external_perimeters_first.value = false;
|
||||
this->extruder_clearance_height.value = 20;
|
||||
this->extruder_clearance_radius.value = 20;
|
||||
|
|
@ -1239,13 +1295,11 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
this->first_layer_temperature.values.resize(1);
|
||||
this->first_layer_temperature.values[0] = 200;
|
||||
this->g0.value = false;
|
||||
this->gap_fill_speed.value = 20;
|
||||
this->gcode_arcs.value = false;
|
||||
this->gcode_comments.value = false;
|
||||
this->gcode_flavor.value = gcfRepRap;
|
||||
this->infill_acceleration.value = 0;
|
||||
this->infill_first.value = false;
|
||||
this->infill_speed.value = 60;
|
||||
this->layer_gcode.value = "";
|
||||
this->max_fan_speed.value = 100;
|
||||
this->min_fan_speed.value = 35;
|
||||
|
|
@ -1257,11 +1311,8 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
this->only_retract_when_crossing_perimeters.value = true;
|
||||
this->ooze_prevention.value = false;
|
||||
this->output_filename_format.value = "[input_filename_base].gcode";
|
||||
this->overhangs.value = true;
|
||||
this->perimeter_acceleration.value = 0;
|
||||
this->perimeter_speed.value = 30;
|
||||
this->print_center.point = Pointf(100,100);
|
||||
this->randomize_start.value = false;
|
||||
this->resolution.value = 0;
|
||||
this->retract_before_travel.values.resize(1);
|
||||
this->retract_before_travel.values[0] = 2;
|
||||
|
|
@ -1283,21 +1334,13 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
this->skirt_height.value = 1;
|
||||
this->skirts.value = 1;
|
||||
this->slowdown_below_layer_time.value = 30;
|
||||
this->small_perimeter_speed.value = 30;
|
||||
this->small_perimeter_speed.percent = false;
|
||||
this->solid_infill_speed.value = 60;
|
||||
this->solid_infill_speed.percent = false;
|
||||
this->spiral_vase.value = false;
|
||||
this->standby_temperature_delta.value = -5;
|
||||
this->start_gcode.value = "G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n";
|
||||
this->start_perimeters_at_concave_points.value = false;
|
||||
this->start_perimeters_at_non_overhang.value = false;
|
||||
this->temperature.values.resize(1);
|
||||
this->temperature.values[0] = 200;
|
||||
this->threads.value = 2;
|
||||
this->toolchange_gcode.value = "";
|
||||
this->top_solid_infill_speed.value = 50;
|
||||
this->top_solid_infill_speed.percent = false;
|
||||
this->travel_speed.value = 130;
|
||||
this->use_firmware_retraction.value = false;
|
||||
this->use_relative_e_distances.value = false;
|
||||
|
|
@ -1314,7 +1357,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
if (opt_key == "bridge_acceleration") return &this->bridge_acceleration;
|
||||
if (opt_key == "bridge_fan_speed") return &this->bridge_fan_speed;
|
||||
if (opt_key == "bridge_flow_ratio") return &this->bridge_flow_ratio;
|
||||
if (opt_key == "bridge_speed") return &this->bridge_speed;
|
||||
if (opt_key == "brim_width") return &this->brim_width;
|
||||
if (opt_key == "complete_objects") return &this->complete_objects;
|
||||
if (opt_key == "cooling") return &this->cooling;
|
||||
|
|
@ -1322,7 +1364,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
if (opt_key == "disable_fan_first_layers") return &this->disable_fan_first_layers;
|
||||
if (opt_key == "duplicate_distance") return &this->duplicate_distance;
|
||||
if (opt_key == "end_gcode") return &this->end_gcode;
|
||||
if (opt_key == "external_perimeter_speed") return &this->external_perimeter_speed;
|
||||
if (opt_key == "external_perimeters_first") return &this->external_perimeters_first;
|
||||
if (opt_key == "extruder_clearance_height") return &this->extruder_clearance_height;
|
||||
if (opt_key == "extruder_clearance_radius") return &this->extruder_clearance_radius;
|
||||
|
|
@ -1338,13 +1379,11 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
if (opt_key == "first_layer_speed") return &this->first_layer_speed;
|
||||
if (opt_key == "first_layer_temperature") return &this->first_layer_temperature;
|
||||
if (opt_key == "g0") return &this->g0;
|
||||
if (opt_key == "gap_fill_speed") return &this->gap_fill_speed;
|
||||
if (opt_key == "gcode_arcs") return &this->gcode_arcs;
|
||||
if (opt_key == "gcode_comments") return &this->gcode_comments;
|
||||
if (opt_key == "gcode_flavor") return &this->gcode_flavor;
|
||||
if (opt_key == "infill_acceleration") return &this->infill_acceleration;
|
||||
if (opt_key == "infill_first") return &this->infill_first;
|
||||
if (opt_key == "infill_speed") return &this->infill_speed;
|
||||
if (opt_key == "layer_gcode") return &this->layer_gcode;
|
||||
if (opt_key == "max_fan_speed") return &this->max_fan_speed;
|
||||
if (opt_key == "min_fan_speed") return &this->min_fan_speed;
|
||||
|
|
@ -1355,12 +1394,9 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
if (opt_key == "only_retract_when_crossing_perimeters") return &this->only_retract_when_crossing_perimeters;
|
||||
if (opt_key == "ooze_prevention") return &this->ooze_prevention;
|
||||
if (opt_key == "output_filename_format") return &this->output_filename_format;
|
||||
if (opt_key == "overhangs") return &this->overhangs;
|
||||
if (opt_key == "perimeter_acceleration") return &this->perimeter_acceleration;
|
||||
if (opt_key == "perimeter_speed") return &this->perimeter_speed;
|
||||
if (opt_key == "post_process") return &this->post_process;
|
||||
if (opt_key == "print_center") return &this->print_center;
|
||||
if (opt_key == "randomize_start") return &this->randomize_start;
|
||||
if (opt_key == "resolution") return &this->resolution;
|
||||
if (opt_key == "retract_before_travel") return &this->retract_before_travel;
|
||||
if (opt_key == "retract_layer_change") return &this->retract_layer_change;
|
||||
|
|
@ -1374,17 +1410,12 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
if (opt_key == "skirt_height") return &this->skirt_height;
|
||||
if (opt_key == "skirts") return &this->skirts;
|
||||
if (opt_key == "slowdown_below_layer_time") return &this->slowdown_below_layer_time;
|
||||
if (opt_key == "small_perimeter_speed") return &this->small_perimeter_speed;
|
||||
if (opt_key == "solid_infill_speed") return &this->solid_infill_speed;
|
||||
if (opt_key == "spiral_vase") return &this->spiral_vase;
|
||||
if (opt_key == "standby_temperature_delta") return &this->standby_temperature_delta;
|
||||
if (opt_key == "start_gcode") return &this->start_gcode;
|
||||
if (opt_key == "start_perimeters_at_concave_points") return &this->start_perimeters_at_concave_points;
|
||||
if (opt_key == "start_perimeters_at_non_overhang") return &this->start_perimeters_at_non_overhang;
|
||||
if (opt_key == "temperature") return &this->temperature;
|
||||
if (opt_key == "threads") return &this->threads;
|
||||
if (opt_key == "toolchange_gcode") return &this->toolchange_gcode;
|
||||
if (opt_key == "top_solid_infill_speed") return &this->top_solid_infill_speed;
|
||||
if (opt_key == "travel_speed") return &this->travel_speed;
|
||||
if (opt_key == "use_firmware_retraction") return &this->use_firmware_retraction;
|
||||
if (opt_key == "use_relative_e_distances") return &this->use_relative_e_distances;
|
||||
|
|
@ -1394,6 +1425,17 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
|
||||
return NULL;
|
||||
};
|
||||
};
|
||||
|
||||
class FullPrintConfig : public PrintObjectConfig, public PrintRegionConfig, public PrintConfig {
|
||||
public:
|
||||
ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
|
||||
ConfigOption* opt;
|
||||
if ((opt = PrintObjectConfig::option(opt_key, create)) != NULL) return opt;
|
||||
if ((opt = PrintRegionConfig::option(opt_key, create)) != NULL) return opt;
|
||||
if ((opt = PrintConfig::option(opt_key, create)) != NULL) return opt;
|
||||
return NULL;
|
||||
};
|
||||
|
||||
std::string get_extrusion_axis() {
|
||||
if (this->gcode_flavor == gcfMach3) {
|
||||
|
|
@ -1405,17 +1447,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||
}
|
||||
};
|
||||
|
||||
class FullPrintConfig : public PrintObjectConfig, public PrintRegionConfig, public PrintConfig {
|
||||
public:
|
||||
ConfigOption* option(const t_config_option_key opt_key, bool create = false) {
|
||||
ConfigOption* opt;
|
||||
if ((opt = PrintObjectConfig::option(opt_key, create)) != NULL) return opt;
|
||||
if ((opt = PrintRegionConfig::option(opt_key, create)) != NULL) return opt;
|
||||
if ((opt = PrintConfig::option(opt_key, create)) != NULL) return opt;
|
||||
return NULL;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 6.1.3a *
|
||||
* Date : 22 January 2014 *
|
||||
* Version : 6.1.5 *
|
||||
* Date : 22 May 2014 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2014 *
|
||||
* *
|
||||
|
|
@ -50,15 +50,6 @@
|
|||
|
||||
namespace ClipperLib {
|
||||
|
||||
#ifdef use_int32
|
||||
static cInt const loRange = 46340;
|
||||
static cInt const hiRange = 46340;
|
||||
#else
|
||||
static cInt const loRange = 0x3FFFFFFF;
|
||||
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||
typedef unsigned long long ulong64;
|
||||
#endif
|
||||
|
||||
static double const pi = 3.141592653589793238;
|
||||
static double const two_pi = pi *2;
|
||||
static double const def_arc_tolerance = 0.25;
|
||||
|
|
@ -240,8 +231,8 @@ bool PolyNode::IsOpen() const
|
|||
|
||||
//------------------------------------------------------------------------------
|
||||
// Int128 class (enables safe math on signed 64bit integers)
|
||||
// eg Int128 val1((cInt)9223372036854775807); //ie 2^63 -1
|
||||
// Int128 val2((cInt)9223372036854775807);
|
||||
// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
|
||||
// Int128 val2((long64)9223372036854775807);
|
||||
// Int128 val3 = val1 * val2;
|
||||
// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -249,22 +240,21 @@ bool PolyNode::IsOpen() const
|
|||
class Int128
|
||||
{
|
||||
public:
|
||||
ulong64 lo;
|
||||
long64 hi;
|
||||
|
||||
cUInt lo;
|
||||
cInt hi;
|
||||
|
||||
Int128(cInt _lo = 0)
|
||||
Int128(long64 _lo = 0)
|
||||
{
|
||||
lo = (cUInt)_lo;
|
||||
lo = (ulong64)_lo;
|
||||
if (_lo < 0) hi = -1; else hi = 0;
|
||||
}
|
||||
|
||||
|
||||
Int128(const Int128 &val): lo(val.lo), hi(val.hi){}
|
||||
|
||||
Int128(const cInt& _hi, const ulong64& _lo): lo(_lo), hi(_hi){}
|
||||
Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){}
|
||||
|
||||
Int128& operator = (const cInt &val)
|
||||
Int128& operator = (const long64 &val)
|
||||
{
|
||||
lo = (ulong64)val;
|
||||
if (val < 0) hi = -1; else hi = 0;
|
||||
|
|
@ -335,85 +325,10 @@ class Int128
|
|||
return Int128(~hi,~lo +1);
|
||||
}
|
||||
|
||||
Int128 operator/ (const Int128 &rhs) const
|
||||
{
|
||||
if (rhs.lo == 0 && rhs.hi == 0)
|
||||
throw "Int128 operator/: divide by zero";
|
||||
|
||||
bool negate = (rhs.hi < 0) != (hi < 0);
|
||||
Int128 dividend = *this;
|
||||
Int128 divisor = rhs;
|
||||
if (dividend.hi < 0) dividend = -dividend;
|
||||
if (divisor.hi < 0) divisor = -divisor;
|
||||
|
||||
if (divisor < dividend)
|
||||
{
|
||||
Int128 result = Int128(0);
|
||||
Int128 cntr = Int128(1);
|
||||
while (divisor.hi >= 0 && !(divisor > dividend))
|
||||
{
|
||||
divisor.hi <<= 1;
|
||||
if ((cInt)divisor.lo < 0) divisor.hi++;
|
||||
divisor.lo <<= 1;
|
||||
|
||||
cntr.hi <<= 1;
|
||||
if ((cInt)cntr.lo < 0) cntr.hi++;
|
||||
cntr.lo <<= 1;
|
||||
}
|
||||
divisor.lo >>= 1;
|
||||
if ((divisor.hi & 1) == 1)
|
||||
divisor.lo |= 0x8000000000000000LL;
|
||||
divisor.hi = (ulong64)divisor.hi >> 1;
|
||||
|
||||
cntr.lo >>= 1;
|
||||
if ((cntr.hi & 1) == 1)
|
||||
cntr.lo |= 0x8000000000000000LL;
|
||||
cntr.hi >>= 1;
|
||||
|
||||
while (cntr.hi != 0 || cntr.lo != 0)
|
||||
{
|
||||
if (!(dividend < divisor))
|
||||
{
|
||||
dividend -= divisor;
|
||||
result.hi |= cntr.hi;
|
||||
result.lo |= cntr.lo;
|
||||
}
|
||||
divisor.lo >>= 1;
|
||||
if ((divisor.hi & 1) == 1)
|
||||
divisor.lo |= 0x8000000000000000LL;
|
||||
divisor.hi >>= 1;
|
||||
|
||||
cntr.lo >>= 1;
|
||||
if ((cntr.hi & 1) == 1)
|
||||
cntr.lo |= 0x8000000000000000LL;
|
||||
cntr.hi >>= 1;
|
||||
}
|
||||
if (negate) result = -result;
|
||||
return result;
|
||||
}
|
||||
else if (rhs.hi == this->hi && rhs.lo == this->lo)
|
||||
return Int128(negate ? -1: 1);
|
||||
else
|
||||
return Int128(0);
|
||||
}
|
||||
|
||||
double AsDouble() const
|
||||
{
|
||||
const double shift64 = 18446744073709551616.0; //2^64
|
||||
if (hi < 0)
|
||||
{
|
||||
cUInt lo_ = ~lo + 1;
|
||||
if (lo_ == 0) return (double)hi * shift64;
|
||||
else return -(double)(lo_ + ~hi * shift64);
|
||||
}
|
||||
else
|
||||
return (double)(lo + hi * shift64);
|
||||
}
|
||||
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Int128 Int128Mul (cInt lhs, cInt rhs)
|
||||
Int128 Int128Mul (long64 lhs, long64 rhs)
|
||||
{
|
||||
bool negate = (lhs < 0) != (rhs < 0);
|
||||
|
||||
|
|
@ -431,9 +346,9 @@ Int128 Int128Mul (cInt lhs, cInt rhs)
|
|||
ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
|
||||
|
||||
Int128 tmp;
|
||||
tmp.hi = cInt(a + (c >> 32));
|
||||
tmp.lo = cInt(c << 32);
|
||||
tmp.lo += cInt(b);
|
||||
tmp.hi = long64(a + (c >> 32));
|
||||
tmp.lo = long64(c << 32);
|
||||
tmp.lo += long64(b);
|
||||
if (tmp.lo < b) tmp.hi++;
|
||||
if (negate) tmp = -tmp;
|
||||
return tmp;
|
||||
|
|
@ -444,6 +359,13 @@ Int128 Int128Mul (cInt lhs, cInt rhs)
|
|||
// Miscellaneous global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void Swap(cInt& val1, cInt& val2)
|
||||
{
|
||||
cInt tmp = val1;
|
||||
val1 = val2;
|
||||
val2 = tmp;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
bool Orientation(const Path &poly)
|
||||
{
|
||||
return Area(poly) >= 0;
|
||||
|
|
@ -494,6 +416,7 @@ bool PointIsVertex(const IntPoint &Pt, OutPt *pp)
|
|||
int PointInPolygon (const IntPoint &pt, const Path &path)
|
||||
{
|
||||
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
|
||||
//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
|
||||
//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
|
||||
int result = 0;
|
||||
size_t cnt = path.size();
|
||||
|
|
@ -539,7 +462,6 @@ int PointInPolygon (const IntPoint &pt, const Path &path)
|
|||
int PointInPolygon (const IntPoint &pt, OutPt *op)
|
||||
{
|
||||
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
|
||||
//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
|
||||
int result = 0;
|
||||
OutPt* startOp = op;
|
||||
for(;;)
|
||||
|
|
@ -674,20 +596,18 @@ inline cInt TopX(TEdge &edge, const cInt currentY)
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool IntersectPoint(TEdge &Edge1, TEdge &Edge2,
|
||||
IntPoint &ip, bool UseFullInt64Range)
|
||||
void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
|
||||
{
|
||||
#ifdef use_xyz
|
||||
ip.Z = 0;
|
||||
#endif
|
||||
|
||||
double b1, b2;
|
||||
//nb: with very large coordinate values, it's possible for SlopesEqual() to
|
||||
//return false but for the edge.Dx value be equal due to double precision rounding.
|
||||
if (SlopesEqual(Edge1, Edge2, UseFullInt64Range) || Edge1.Dx == Edge2.Dx)
|
||||
if (Edge1.Dx == Edge2.Dx)
|
||||
{
|
||||
if (Edge2.Bot.Y > Edge1.Bot.Y) ip = Edge2.Bot;
|
||||
else ip = Edge1.Bot;
|
||||
return false;
|
||||
ip.Y = Edge1.Curr.Y;
|
||||
ip.X = TopX(Edge1, ip.Y);
|
||||
return;
|
||||
}
|
||||
else if (Edge1.Delta.X == 0)
|
||||
{
|
||||
|
|
@ -734,7 +654,15 @@ bool IntersectPoint(TEdge &Edge1, TEdge &Edge2,
|
|||
else
|
||||
ip.X = TopX(Edge2, ip.Y);
|
||||
}
|
||||
return true;
|
||||
//finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ...
|
||||
if (ip.Y > Edge1.Curr.Y)
|
||||
{
|
||||
ip.Y = Edge1.Curr.Y;
|
||||
//use the more vertical edge to derive X ...
|
||||
if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx))
|
||||
ip.X = TopX(Edge2, ip.Y); else
|
||||
ip.X = TopX(Edge1, ip.Y);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -807,13 +735,9 @@ inline void ReverseHorizontal(TEdge &e)
|
|||
//swap horizontal edges' Top and Bottom x's so they follow the natural
|
||||
//progression of the bounds - ie so their xbots will align with the
|
||||
//adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
|
||||
cInt tmp = e.Top.X;
|
||||
e.Top.X = e.Bot.X;
|
||||
e.Bot.X = tmp;
|
||||
Swap(e.Top.X, e.Bot.X);
|
||||
#ifdef use_xyz
|
||||
tmp = e.Top.Z;
|
||||
e.Top.Z = e.Bot.Z;
|
||||
e.Bot.Z = tmp;
|
||||
Swap(e.Top.Z, e.Bot.Z);
|
||||
#endif
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -905,26 +829,6 @@ OutPt* GetBottomPt(OutPt *pp)
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool FindSegment(OutPt* &pp, bool UseFullInt64Range,
|
||||
IntPoint &pt1, IntPoint &pt2)
|
||||
{
|
||||
//OutPt1 & OutPt2 => the overlap segment (if the function returns true)
|
||||
if (!pp) return false;
|
||||
OutPt* pp2 = pp;
|
||||
IntPoint pt1a = pt1, pt2a = pt2;
|
||||
do
|
||||
{
|
||||
if (SlopesEqual(pt1a, pt2a, pp->Pt, pp->Prev->Pt, UseFullInt64Range) &&
|
||||
SlopesEqual(pt1a, pt2a, pp->Pt, UseFullInt64Range) &&
|
||||
GetOverlapSegment(pt1a, pt2a, pp->Pt, pp->Prev->Pt, pt1, pt2))
|
||||
return true;
|
||||
pp = pp->Next;
|
||||
}
|
||||
while (pp != pp2);
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1,
|
||||
const IntPoint pt2, const IntPoint pt3)
|
||||
{
|
||||
|
|
@ -937,41 +841,12 @@ bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1,
|
|||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint Pt)
|
||||
bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
|
||||
{
|
||||
if (p1 == p2) throw "JoinError";
|
||||
OutPt* result = new OutPt;
|
||||
result->Pt = Pt;
|
||||
if (p2 == p1->Next)
|
||||
{
|
||||
p1->Next = result;
|
||||
p2->Prev = result;
|
||||
result->Next = p2;
|
||||
result->Prev = p1;
|
||||
} else
|
||||
{
|
||||
p2->Next = result;
|
||||
p1->Prev = result;
|
||||
result->Next = p1;
|
||||
result->Prev = p2;
|
||||
}
|
||||
return result;
|
||||
if (seg1a > seg1b) Swap(seg1a, seg1b);
|
||||
if (seg2a > seg2b) Swap(seg2a, seg2b);
|
||||
return (seg1a < seg2b) && (seg2a < seg1b);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool HorzSegmentsOverlap(const IntPoint& pt1a, const IntPoint& pt1b,
|
||||
const IntPoint& pt2a, const IntPoint& pt2b)
|
||||
{
|
||||
//precondition: both segments are horizontal
|
||||
if ((pt1a.X > pt2a.X) == (pt1a.X < pt2b.X)) return true;
|
||||
else if ((pt1b.X > pt2a.X) == (pt1b.X < pt2b.X)) return true;
|
||||
else if ((pt2a.X > pt1a.X) == (pt2a.X < pt1b.X)) return true;
|
||||
else if ((pt2b.X > pt1a.X) == (pt2b.X < pt1b.X)) return true;
|
||||
else if ((pt1a.X == pt2a.X) && (pt1b.X == pt2b.X)) return true;
|
||||
else if ((pt1a.X == pt2b.X) && (pt1b.X == pt2a.X)) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// ClipperBase class methods ...
|
||||
|
|
@ -1030,20 +905,20 @@ TEdge* ClipperBase::ProcessBound(TEdge* E, bool IsClockwise)
|
|||
cInt StartX;
|
||||
if (IsHorizontal(*E))
|
||||
{
|
||||
//first we need to be careful here with open paths because this
|
||||
//may not be a true local minima (ie may be following a skip edge).
|
||||
//also, watch for adjacent horz edges to start heading left
|
||||
//before finishing right ...
|
||||
if (IsClockwise)
|
||||
{
|
||||
if (E->Prev->Bot.Y == E->Bot.Y) StartX = E->Prev->Bot.X;
|
||||
else StartX = E->Prev->Top.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (E->Next->Bot.Y == E->Bot.Y) StartX = E->Next->Bot.X;
|
||||
else StartX = E->Next->Top.X;
|
||||
}
|
||||
//first we need to be careful here with open paths because this
|
||||
//may not be a true local minima (ie may be following a skip edge).
|
||||
//also, watch for adjacent horz edges to start heading left
|
||||
//before finishing right ...
|
||||
if (IsClockwise)
|
||||
{
|
||||
if (E->Prev->Bot.Y == E->Bot.Y) StartX = E->Prev->Bot.X;
|
||||
else StartX = E->Prev->Top.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (E->Next->Bot.Y == E->Bot.Y) StartX = E->Next->Bot.X;
|
||||
else StartX = E->Next->Top.X;
|
||||
}
|
||||
if (E->Bot.X != StartX) ReverseHorizontal(*E);
|
||||
}
|
||||
|
||||
|
|
@ -1189,7 +1064,8 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
|
|||
TEdge *E = eStart, *eLoopStop = eStart;
|
||||
for (;;)
|
||||
{
|
||||
if ((E->Curr == E->Next->Curr))
|
||||
//nb: allows matching start and end points when not Closed ...
|
||||
if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart))
|
||||
{
|
||||
if (E == E->Next) break;
|
||||
if (E == eStart) eStart = E->Next;
|
||||
|
|
@ -1215,7 +1091,7 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
|
|||
continue;
|
||||
}
|
||||
E = E->Next;
|
||||
if (E == eLoopStop) break;
|
||||
if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break;
|
||||
}
|
||||
|
||||
if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next)))
|
||||
|
|
@ -1274,6 +1150,11 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
|
|||
m_edges.push_back(edges);
|
||||
bool clockwise;
|
||||
TEdge* EMin = 0;
|
||||
|
||||
//workaround to avoid an endless loop in the while loop below when
|
||||
//open paths have matching start and end points ...
|
||||
if (E->Prev->Bot == E->Prev->Top) E = E->Next;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
E = FindNextLocMin(E);
|
||||
|
|
@ -2028,7 +1909,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
|
|||
Join* jr = m_GhostJoins[i];
|
||||
//if the horizontal Rb and a 'ghost' horizontal overlap, then convert
|
||||
//the 'ghost' join to a real join ready for later ...
|
||||
if (HorzSegmentsOverlap(jr->OutPt1->Pt, jr->OffPt, rb->Bot, rb->Top))
|
||||
if (HorzSegmentsOverlap(jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X, rb->Top.X))
|
||||
AddJoin(jr->OutPt1, Op1, jr->OffPt);
|
||||
}
|
||||
}
|
||||
|
|
@ -2098,45 +1979,34 @@ void Clipper::DeleteFromSEL(TEdge *e)
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef use_xyz
|
||||
|
||||
void Clipper::SetZ(IntPoint& pt, TEdge& e)
|
||||
void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2)
|
||||
{
|
||||
pt.Z = 0;
|
||||
if (m_ZFill)
|
||||
{
|
||||
//put the 'preferred' point as first parameter ...
|
||||
if (e.OutIdx < 0)
|
||||
(*m_ZFill)(e.Bot, e.Top, pt); //outside a path so presume entering
|
||||
else
|
||||
(*m_ZFill)(e.Top, e.Bot, pt); //inside a path so presume exiting
|
||||
}
|
||||
if (pt.Z != 0 || !m_ZFill) return;
|
||||
else if (pt == e1.Bot) pt.Z = e1.Bot.Z;
|
||||
else if (pt == e1.Top) pt.Z = e1.Top.Z;
|
||||
else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
|
||||
else if (pt == e2.Top) pt.Z = e2.Top.Z;
|
||||
else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
#endif
|
||||
|
||||
void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
|
||||
const IntPoint &Pt, bool protect)
|
||||
void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt)
|
||||
{
|
||||
//e1 will be to the Left of e2 BELOW the intersection. Therefore e1 is before
|
||||
//e2 in AEL except when e1 is being inserted at the intersection point ...
|
||||
bool e1stops = !protect && !e1->NextInLML &&
|
||||
e1->Top.X == Pt.X && e1->Top.Y == Pt.Y;
|
||||
bool e2stops = !protect && !e2->NextInLML &&
|
||||
e2->Top.X == Pt.X && e2->Top.Y == Pt.Y;
|
||||
bool e1Contributing = ( e1->OutIdx >= 0 );
|
||||
bool e2Contributing = ( e2->OutIdx >= 0 );
|
||||
|
||||
#ifdef use_xyz
|
||||
SetZ(Pt, *e1, *e2);
|
||||
#endif
|
||||
|
||||
#ifdef use_lines
|
||||
//if either edge is on an OPEN path ...
|
||||
if (e1->WindDelta == 0 || e2->WindDelta == 0)
|
||||
{
|
||||
//ignore subject-subject open path intersections UNLESS they
|
||||
//are both open paths, AND they are both 'contributing maximas' ...
|
||||
if (e1->WindDelta == 0 && e2->WindDelta == 0)
|
||||
{
|
||||
if ((e1stops || e2stops) && e1Contributing && e2Contributing)
|
||||
AddLocalMaxPoly(e1, e2, Pt);
|
||||
}
|
||||
if (e1->WindDelta == 0 && e2->WindDelta == 0) return;
|
||||
|
||||
//if intersecting a subj line with a subj poly ...
|
||||
else if (e1->PolyTyp == e2->PolyTyp &&
|
||||
|
|
@ -2175,13 +2045,6 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
|
|||
if (e2Contributing) e2->OutIdx = Unassigned;
|
||||
}
|
||||
}
|
||||
|
||||
if (e1stops)
|
||||
if (e1->OutIdx < 0) DeleteFromAEL(e1);
|
||||
else throw clipperException("Error intersecting polylines");
|
||||
if (e2stops)
|
||||
if (e2->OutIdx < 0) DeleteFromAEL(e2);
|
||||
else throw clipperException("Error intersecting polylines");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -2246,10 +2109,11 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
|
|||
|
||||
if ( e1Contributing && e2Contributing )
|
||||
{
|
||||
if ( e1stops || e2stops ||
|
||||
(e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
|
||||
if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
|
||||
(e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) )
|
||||
AddLocalMaxPoly(e1, e2, Pt);
|
||||
{
|
||||
AddLocalMaxPoly(e1, e2, Pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddOutPt(e1, Pt);
|
||||
|
|
@ -2276,8 +2140,7 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
|
|||
SwapPolyIndexes(*e1, *e2);
|
||||
}
|
||||
}
|
||||
else if ( (e1Wc == 0 || e1Wc == 1) &&
|
||||
(e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
|
||||
else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1))
|
||||
{
|
||||
//neither edge is currently contributing ...
|
||||
|
||||
|
|
@ -2296,7 +2159,9 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
|
|||
}
|
||||
|
||||
if (e1->PolyTyp != e2->PolyTyp)
|
||||
AddLocalMinPoly(e1, e2, Pt);
|
||||
{
|
||||
AddLocalMinPoly(e1, e2, Pt);
|
||||
}
|
||||
else if (e1Wc == 1 && e2Wc == 1)
|
||||
switch( m_ClipType ) {
|
||||
case ctIntersection:
|
||||
|
|
@ -2318,17 +2183,6 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
|
|||
else
|
||||
SwapSides( *e1, *e2 );
|
||||
}
|
||||
|
||||
if( (e1stops != e2stops) &&
|
||||
( (e1stops && (e1->OutIdx >= 0)) || (e2stops && (e2->OutIdx >= 0)) ) )
|
||||
{
|
||||
SwapSides( *e1, *e2 );
|
||||
SwapPolyIndexes( *e1, *e2 );
|
||||
}
|
||||
|
||||
//finally, delete any non-contributing maxima edges ...
|
||||
if( e1stops ) DeleteFromAEL( e1 );
|
||||
if( e2stops ) DeleteFromAEL( e2 );
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -2519,12 +2373,7 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
|
|||
newOp->Prev = newOp;
|
||||
if (!outRec->IsOpen)
|
||||
SetHoleState(e, outRec);
|
||||
#ifdef use_xyz
|
||||
if (pt == e->Bot) newOp->Pt = e->Bot;
|
||||
else if (pt == e->Top) newOp->Pt = e->Top;
|
||||
else SetZ(newOp->Pt, *e);
|
||||
#endif
|
||||
e->OutIdx = outRec->Idx; //nb: do this after SetZ !
|
||||
e->OutIdx = outRec->Idx;
|
||||
return newOp;
|
||||
} else
|
||||
{
|
||||
|
|
@ -2543,11 +2392,6 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
|
|||
newOp->Prev->Next = newOp;
|
||||
op->Prev = newOp;
|
||||
if (ToFront) outRec->Pts = newOp;
|
||||
#ifdef use_xyz
|
||||
if (pt == e->Bot) newOp->Pt = e->Bot;
|
||||
else if (pt == e->Top) newOp->Pt = e->Top;
|
||||
else SetZ(newOp->Pt, *e);
|
||||
#endif
|
||||
return newOp;
|
||||
}
|
||||
}
|
||||
|
|
@ -2714,37 +2558,6 @@ void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right)
|
|||
}
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam)
|
||||
{
|
||||
//get the last Op for this horizontal edge
|
||||
//the point may be anywhere along the horizontal ...
|
||||
OutPt* outPt = m_PolyOuts[horzEdge->OutIdx]->Pts;
|
||||
if (horzEdge->Side != esLeft) outPt = outPt->Prev;
|
||||
|
||||
//First, match up overlapping horizontal edges (eg when one polygon's
|
||||
//intermediate horz edge overlaps an intermediate horz edge of another, or
|
||||
//when one polygon sits on top of another) ...
|
||||
//for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i)
|
||||
//{
|
||||
// Join* j = m_GhostJoins[i];
|
||||
// if (HorzSegmentsOverlap(j->OutPt1->Pt, j->OffPt, horzEdge->Bot, horzEdge->Top))
|
||||
// AddJoin(j->OutPt1, outPt, j->OffPt);
|
||||
//}
|
||||
|
||||
//Also, since horizontal edges at the top of one SB are often removed from
|
||||
//the AEL before we process the horizontal edges at the bottom of the next,
|
||||
//we need to create 'ghost' Join records of 'contrubuting' horizontals that
|
||||
//we can compare with horizontals at the bottom of the next SB.
|
||||
if (isTopOfScanbeam)
|
||||
{
|
||||
if (outPt->Pt == horzEdge->Top)
|
||||
AddGhostJoin(outPt, horzEdge->Bot);
|
||||
else
|
||||
AddGhostJoin(outPt, horzEdge->Top);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*******************************************************************************
|
||||
* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or *
|
||||
* Bottom of a scanbeam) are processed as if layered. The order in which HEs *
|
||||
|
|
@ -2784,28 +2597,42 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
|
|||
if ((dir == dLeftToRight && e->Curr.X <= horzRight) ||
|
||||
(dir == dRightToLeft && e->Curr.X >= horzLeft))
|
||||
{
|
||||
if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0)
|
||||
PrepareHorzJoins(horzEdge, isTopOfScanbeam);
|
||||
//so far we're still in range of the horizontal Edge but make sure
|
||||
//we're at the last of consec. horizontals when matching with eMaxPair
|
||||
if(e == eMaxPair && IsLastHorz)
|
||||
{
|
||||
if (dir == dLeftToRight)
|
||||
IntersectEdges(horzEdge, e, e->Top);
|
||||
else
|
||||
IntersectEdges(e, horzEdge, e->Top);
|
||||
if (eMaxPair->OutIdx >= 0) throw clipperException("ProcessHorizontal error");
|
||||
|
||||
if (horzEdge->OutIdx >= 0)
|
||||
{
|
||||
OutPt* op1 = AddOutPt(horzEdge, horzEdge->Top);
|
||||
TEdge* eNextHorz = m_SortedEdges;
|
||||
while (eNextHorz)
|
||||
{
|
||||
if (eNextHorz->OutIdx >= 0 &&
|
||||
HorzSegmentsOverlap(horzEdge->Bot.X,
|
||||
horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
|
||||
{
|
||||
OutPt* op2 = AddOutPt(eNextHorz, eNextHorz->Bot);
|
||||
AddJoin(op2, op1, eNextHorz->Top);
|
||||
}
|
||||
eNextHorz = eNextHorz->NextInSEL;
|
||||
}
|
||||
AddGhostJoin(op1, horzEdge->Bot);
|
||||
AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top);
|
||||
}
|
||||
DeleteFromAEL(horzEdge);
|
||||
DeleteFromAEL(eMaxPair);
|
||||
return;
|
||||
}
|
||||
else if(dir == dLeftToRight)
|
||||
{
|
||||
IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
|
||||
IntersectEdges(horzEdge, e, Pt, true);
|
||||
IntersectEdges(horzEdge, e, Pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
|
||||
IntersectEdges( e, horzEdge, Pt, true);
|
||||
IntersectEdges( e, horzEdge, Pt);
|
||||
}
|
||||
SwapPositionsInAEL( horzEdge, e );
|
||||
}
|
||||
|
|
@ -2814,9 +2641,6 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
|
|||
e = eNext;
|
||||
} //end while
|
||||
|
||||
if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0)
|
||||
PrepareHorzJoins(horzEdge, isTopOfScanbeam);
|
||||
|
||||
if (horzEdge->NextInLML && IsHorizontal(*horzEdge->NextInLML))
|
||||
{
|
||||
UpdateEdgeIntoAEL(horzEdge);
|
||||
|
|
@ -2831,6 +2655,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
|
|||
if(horzEdge->OutIdx >= 0)
|
||||
{
|
||||
OutPt* op1 = AddOutPt( horzEdge, horzEdge->Top);
|
||||
if (isTopOfScanbeam) AddGhostJoin(op1, horzEdge->Bot);
|
||||
UpdateEdgeIntoAEL(horzEdge);
|
||||
if (horzEdge->WindDelta == 0) return;
|
||||
//nb: HorzEdge is no longer horizontal here
|
||||
|
|
@ -2856,22 +2681,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
|
|||
else
|
||||
UpdateEdgeIntoAEL(horzEdge);
|
||||
}
|
||||
else if (eMaxPair)
|
||||
{
|
||||
if (eMaxPair->OutIdx >= 0)
|
||||
{
|
||||
if (dir == dLeftToRight)
|
||||
IntersectEdges(horzEdge, eMaxPair, horzEdge->Top);
|
||||
else
|
||||
IntersectEdges(eMaxPair, horzEdge, horzEdge->Top);
|
||||
if (eMaxPair->OutIdx >= 0)
|
||||
throw clipperException("ProcessHorizontal error");
|
||||
} else
|
||||
{
|
||||
DeleteFromAEL(horzEdge);
|
||||
DeleteFromAEL(eMaxPair);
|
||||
}
|
||||
} else
|
||||
else
|
||||
{
|
||||
if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top);
|
||||
DeleteFromAEL(horzEdge);
|
||||
|
|
@ -2958,16 +2768,7 @@ void Clipper::BuildIntersectList(const cInt botY, const cInt topY)
|
|||
IntPoint Pt;
|
||||
if(e->Curr.X > eNext->Curr.X)
|
||||
{
|
||||
if (!IntersectPoint(*e, *eNext, Pt, m_UseFullRange) && e->Curr.X > eNext->Curr.X +1)
|
||||
throw clipperException("Intersection error");
|
||||
if (Pt.Y > botY)
|
||||
{
|
||||
Pt.Y = botY;
|
||||
if (std::fabs(e->Dx) > std::fabs(eNext->Dx))
|
||||
Pt.X = TopX(*eNext, botY); else
|
||||
Pt.X = TopX(*e, botY);
|
||||
}
|
||||
|
||||
IntersectPoint(*e, *eNext, Pt);
|
||||
IntersectNode * newNode = new IntersectNode;
|
||||
newNode->Edge1 = e;
|
||||
newNode->Edge2 = eNext;
|
||||
|
|
@ -2995,7 +2796,7 @@ void Clipper::ProcessIntersectList()
|
|||
{
|
||||
IntersectNode* iNode = m_IntersectList[i];
|
||||
{
|
||||
IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt, true);
|
||||
IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt);
|
||||
SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 );
|
||||
}
|
||||
delete iNode;
|
||||
|
|
@ -3054,7 +2855,7 @@ void Clipper::DoMaxima(TEdge *e)
|
|||
TEdge* eNext = e->NextInAEL;
|
||||
while(eNext && eNext != eMaxPair)
|
||||
{
|
||||
IntersectEdges(e, eNext, e->Top, true);
|
||||
IntersectEdges(e, eNext, e->Top);
|
||||
SwapPositionsInAEL(e, eNext);
|
||||
eNext = e->NextInAEL;
|
||||
}
|
||||
|
|
@ -3066,7 +2867,9 @@ void Clipper::DoMaxima(TEdge *e)
|
|||
}
|
||||
else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 )
|
||||
{
|
||||
IntersectEdges( e, eMaxPair, e->Top);
|
||||
if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top);
|
||||
DeleteFromAEL(e);
|
||||
DeleteFromAEL(eMaxPair);
|
||||
}
|
||||
#ifdef use_lines
|
||||
else if (e->WindDelta == 0)
|
||||
|
|
@ -3134,9 +2937,13 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
|
|||
if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) &&
|
||||
(ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0))
|
||||
{
|
||||
OutPt* op = AddOutPt(ePrev, e->Curr);
|
||||
OutPt* op2 = AddOutPt(e, e->Curr);
|
||||
AddJoin(op, op2, e->Curr); //StrictlySimple (type-3) join
|
||||
IntPoint pt = e->Curr;
|
||||
#ifdef use_xyz
|
||||
SetZ(pt, *ePrev, *e);
|
||||
#endif
|
||||
OutPt* op = AddOutPt(ePrev, pt);
|
||||
OutPt* op2 = AddOutPt(e, pt);
|
||||
AddJoin(op, op2, pt); //StrictlySimple (type-3) join
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3518,6 +3325,7 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
|
|||
(j->OffPt == j->OutPt2->Pt))
|
||||
{
|
||||
//Strictly Simple join ...
|
||||
if (outRec1 != outRec2) return false;
|
||||
op1b = j->OutPt1->Next;
|
||||
while (op1b != op1 && (op1b->Pt == j->OffPt))
|
||||
op1b = op1b->Next;
|
||||
|
|
@ -3858,8 +3666,7 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
|
|||
(path[i].Y == newNode->Contour[k].Y &&
|
||||
path[i].X < newNode->Contour[k].X)) k = j;
|
||||
}
|
||||
if ((endType == etClosedPolygon && j < 2) ||
|
||||
(endType != etClosedPolygon && j < 0))
|
||||
if (endType == etClosedPolygon && j < 2)
|
||||
{
|
||||
delete newNode;
|
||||
return;
|
||||
|
|
@ -3869,7 +3676,7 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
|
|||
//if this path's lowest pt is lower than all the others then update m_lowest
|
||||
if (endType != etClosedPolygon) return;
|
||||
if (m_lowest.X < 0)
|
||||
m_lowest = IntPoint(0, k);
|
||||
m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
|
||||
else
|
||||
{
|
||||
IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y];
|
||||
|
|
@ -4159,8 +3966,20 @@ void ClipperOffset::DoOffset(double delta)
|
|||
|
||||
void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype)
|
||||
{
|
||||
//cross product ...
|
||||
m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y);
|
||||
if (m_sinA < 0.00005 && m_sinA > -0.00005) return;
|
||||
if (std::fabs(m_sinA * m_delta) < 1.0)
|
||||
{
|
||||
//dot product ...
|
||||
double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y );
|
||||
if (cosA > 0) // angle => 0 degrees
|
||||
{
|
||||
m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
|
||||
Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
|
||||
return;
|
||||
}
|
||||
//else angle => 180 degrees
|
||||
}
|
||||
else if (m_sinA > 1.0) m_sinA = 1.0;
|
||||
else if (m_sinA < -1.0) m_sinA = -1.0;
|
||||
|
||||
|
|
@ -4358,7 +4177,27 @@ double DistanceFromLineSqrd(
|
|||
bool SlopesNearCollinear(const IntPoint& pt1,
|
||||
const IntPoint& pt2, const IntPoint& pt3, double distSqrd)
|
||||
{
|
||||
return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
|
||||
//this function is more accurate when the point that's geometrically
|
||||
//between the other 2 points is the one that's tested for distance.
|
||||
//ie makes it more likely to pick up 'spikes' ...
|
||||
if (std::abs(pt1.X - pt2.X) > std::abs(pt1.Y - pt2.Y))
|
||||
{
|
||||
if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
|
||||
return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
|
||||
else if ((pt2.X > pt1.X) == (pt2.X < pt3.X))
|
||||
return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
|
||||
else
|
||||
return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y))
|
||||
return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
|
||||
else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y))
|
||||
return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
|
||||
else
|
||||
return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -4486,8 +4325,8 @@ void Minkowski(const Path& poly, const Path& path,
|
|||
pp.push_back(p);
|
||||
}
|
||||
|
||||
Paths quads;
|
||||
quads.reserve((pathCnt + delta) * (polyCnt + 1));
|
||||
solution.clear();
|
||||
solution.reserve((pathCnt + delta) * (polyCnt + 1));
|
||||
for (size_t i = 0; i < pathCnt - 1 + delta; ++i)
|
||||
for (size_t j = 0; j < polyCnt; ++j)
|
||||
{
|
||||
|
|
@ -4498,23 +4337,30 @@ void Minkowski(const Path& poly, const Path& path,
|
|||
quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]);
|
||||
quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]);
|
||||
if (!Orientation(quad)) ReversePath(quad);
|
||||
quads.push_back(quad);
|
||||
solution.push_back(quad);
|
||||
}
|
||||
|
||||
Clipper c;
|
||||
c.AddPaths(quads, ptSubject, true);
|
||||
c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed)
|
||||
{
|
||||
Minkowski(pattern, path, solution, true, pathIsClosed);
|
||||
Clipper c;
|
||||
c.AddPaths(solution, ptSubject, true);
|
||||
c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution,
|
||||
PolyFillType pathFillType, bool pathIsClosed)
|
||||
void TranslatePath(const Path& input, Path& output, IntPoint delta)
|
||||
{
|
||||
//precondition: input != output
|
||||
output.resize(input.size());
|
||||
for (size_t i = 0; i < input.size(); ++i)
|
||||
output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed)
|
||||
{
|
||||
Clipper c;
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
|
|
@ -4522,15 +4368,23 @@ void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution,
|
|||
Paths tmp;
|
||||
Minkowski(pattern, paths[i], tmp, true, pathIsClosed);
|
||||
c.AddPaths(tmp, ptSubject, true);
|
||||
if (pathIsClosed)
|
||||
{
|
||||
Path tmp2;
|
||||
TranslatePath(paths[i], tmp2, pattern[0]);
|
||||
c.AddPath(tmp2, ptClip, true);
|
||||
}
|
||||
}
|
||||
if (pathIsClosed) c.AddPaths(paths, ptClip, true);
|
||||
c.Execute(ctUnion, solution, pathFillType, pathFillType);
|
||||
c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution)
|
||||
{
|
||||
Minkowski(poly1, poly2, solution, false, true);
|
||||
Clipper c;
|
||||
c.AddPaths(solution, ptSubject, true);
|
||||
c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
/*******************************************************************************
|
||||
* *
|
||||
* Author : Angus Johnson *
|
||||
* Version : 6.1.3a *
|
||||
* Date : 22 January 2014 *
|
||||
* Version : 6.1.5 *
|
||||
* Date : 22 May 2014 *
|
||||
* Website : http://www.angusj.com *
|
||||
* Copyright : Angus Johnson 2010-2014 *
|
||||
* *
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
#ifndef clipper_hpp
|
||||
#define clipper_hpp
|
||||
|
||||
#define CLIPPER_VERSION "6.1.3"
|
||||
#define CLIPPER_VERSION "6.1.5"
|
||||
|
||||
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
|
||||
//improve performance but coordinate values are limited to the range +/- 46340
|
||||
|
|
@ -69,11 +69,15 @@ enum PolyType { ptSubject, ptClip };
|
|||
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
|
||||
|
||||
#ifdef use_int32
|
||||
typedef int cInt;
|
||||
typedef unsigned int cUInt;
|
||||
typedef int cInt;
|
||||
static cInt const loRange = 46340;
|
||||
static cInt const hiRange = 46340;
|
||||
#else
|
||||
typedef signed long long cInt;
|
||||
typedef unsigned long long cUInt;
|
||||
typedef signed long long cInt;
|
||||
typedef signed long long long64; //used by Int128 class
|
||||
typedef unsigned long long ulong64;
|
||||
static cInt const loRange = 0x3FFFFFFF;
|
||||
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||
#endif
|
||||
|
||||
struct IntPoint {
|
||||
|
|
@ -117,7 +121,7 @@ struct DoublePoint
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifdef use_xyz
|
||||
typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt);
|
||||
typedef void (*TZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
|
||||
#endif
|
||||
|
||||
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
|
||||
|
|
@ -183,8 +187,7 @@ void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.
|
|||
void CleanPolygons(Paths& polys, double distance = 1.415);
|
||||
|
||||
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
|
||||
void MinkowskiSum(const Path& pattern, const Paths& paths,
|
||||
Paths& solution, PolyFillType pathFillType, bool pathIsClosed);
|
||||
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed);
|
||||
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
|
||||
|
||||
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
|
||||
|
|
@ -308,15 +311,13 @@ private:
|
|||
bool IsTopHorz(const cInt XPos);
|
||||
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
|
||||
void DoMaxima(TEdge *e);
|
||||
void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam);
|
||||
void ProcessHorizontals(bool IsTopOfScanbeam);
|
||||
void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam);
|
||||
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
|
||||
OutRec* GetOutRec(int idx);
|
||||
void AppendPolygon(TEdge *e1, TEdge *e2);
|
||||
void IntersectEdges(TEdge *e1, TEdge *e2,
|
||||
const IntPoint &pt, bool protect = false);
|
||||
void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
|
||||
OutRec* CreateOutRec();
|
||||
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
|
||||
void DisposeAllOutRecs();
|
||||
|
|
@ -344,7 +345,7 @@ private:
|
|||
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
|
||||
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
|
||||
#ifdef use_xyz
|
||||
void SetZ(IntPoint& pt, TEdge& e);
|
||||
void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
|
||||
#endif
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue