mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-22 00:01:09 -06:00
Merge branch 'master' into sender
Conflicts: Build.PL lib/Slic3r/GUI/MainFrame.pm
This commit is contained in:
commit
13b7316807
74 changed files with 1260 additions and 553 deletions
|
@ -26,8 +26,14 @@ class ConfigOption {
|
|||
virtual void setInt(int val) {};
|
||||
};
|
||||
|
||||
class ConfigOptionVectorBase : public ConfigOption {
|
||||
public:
|
||||
virtual ~ConfigOptionVectorBase() {};
|
||||
virtual std::vector<std::string> vserialize() const = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ConfigOptionVector
|
||||
class ConfigOptionVector : public ConfigOptionVectorBase
|
||||
{
|
||||
public:
|
||||
virtual ~ConfigOptionVector() {};
|
||||
|
@ -63,7 +69,7 @@ class ConfigOptionFloat : public ConfigOption
|
|||
};
|
||||
};
|
||||
|
||||
class ConfigOptionFloats : public ConfigOption, public ConfigOptionVector<double>
|
||||
class ConfigOptionFloats : public ConfigOptionVector<double>
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -76,6 +82,16 @@ class ConfigOptionFloats : public ConfigOption, public ConfigOptionVector<double
|
|||
return ss.str();
|
||||
};
|
||||
|
||||
std::vector<std::string> vserialize() const {
|
||||
std::vector<std::string> vv;
|
||||
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
std::ostringstream ss;
|
||||
ss << *it;
|
||||
vv.push_back(ss.str());
|
||||
}
|
||||
return vv;
|
||||
};
|
||||
|
||||
bool deserialize(std::string str) {
|
||||
this->values.clear();
|
||||
std::istringstream is(str);
|
||||
|
@ -112,7 +128,7 @@ class ConfigOptionInt : public ConfigOption
|
|||
};
|
||||
};
|
||||
|
||||
class ConfigOptionInts : public ConfigOption, public ConfigOptionVector<int>
|
||||
class ConfigOptionInts : public ConfigOptionVector<int>
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -125,6 +141,16 @@ class ConfigOptionInts : public ConfigOption, public ConfigOptionVector<int>
|
|||
return ss.str();
|
||||
};
|
||||
|
||||
std::vector<std::string> vserialize() const {
|
||||
std::vector<std::string> vv;
|
||||
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
std::ostringstream ss;
|
||||
ss << *it;
|
||||
vv.push_back(ss.str());
|
||||
}
|
||||
return vv;
|
||||
};
|
||||
|
||||
bool deserialize(std::string str) {
|
||||
this->values.clear();
|
||||
std::istringstream is(str);
|
||||
|
@ -174,7 +200,7 @@ class ConfigOptionString : public ConfigOption
|
|||
};
|
||||
|
||||
// semicolon-separated strings
|
||||
class ConfigOptionStrings : public ConfigOption, public ConfigOptionVector<std::string>
|
||||
class ConfigOptionStrings : public ConfigOptionVector<std::string>
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -187,6 +213,10 @@ class ConfigOptionStrings : public ConfigOption, public ConfigOptionVector<std::
|
|||
return ss.str();
|
||||
};
|
||||
|
||||
std::vector<std::string> vserialize() const {
|
||||
return this->values;
|
||||
};
|
||||
|
||||
bool deserialize(std::string str) {
|
||||
this->values.clear();
|
||||
std::istringstream is(str);
|
||||
|
@ -279,7 +309,7 @@ class ConfigOptionPoint : public ConfigOption
|
|||
};
|
||||
};
|
||||
|
||||
class ConfigOptionPoints : public ConfigOption, public ConfigOptionVector<Pointf>
|
||||
class ConfigOptionPoints : public ConfigOptionVector<Pointf>
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -294,6 +324,16 @@ class ConfigOptionPoints : public ConfigOption, public ConfigOptionVector<Pointf
|
|||
return ss.str();
|
||||
};
|
||||
|
||||
std::vector<std::string> vserialize() const {
|
||||
std::vector<std::string> vv;
|
||||
for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
std::ostringstream ss;
|
||||
ss << *it;
|
||||
vv.push_back(ss.str());
|
||||
}
|
||||
return vv;
|
||||
};
|
||||
|
||||
bool deserialize(std::string str) {
|
||||
this->values.clear();
|
||||
std::istringstream is(str);
|
||||
|
@ -332,7 +372,7 @@ class ConfigOptionBool : public ConfigOption
|
|||
};
|
||||
};
|
||||
|
||||
class ConfigOptionBools : public ConfigOption, public ConfigOptionVector<bool>
|
||||
class ConfigOptionBools : public ConfigOptionVector<bool>
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -345,6 +385,16 @@ class ConfigOptionBools : public ConfigOption, public ConfigOptionVector<bool>
|
|||
return ss.str();
|
||||
};
|
||||
|
||||
std::vector<std::string> vserialize() const {
|
||||
std::vector<std::string> vv;
|
||||
for (std::vector<bool>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||
std::ostringstream ss;
|
||||
ss << (*it ? "1" : "0");
|
||||
vv.push_back(ss.str());
|
||||
}
|
||||
return vv;
|
||||
};
|
||||
|
||||
bool deserialize(std::string str) {
|
||||
this->values.clear();
|
||||
std::istringstream is(str);
|
||||
|
|
|
@ -191,12 +191,25 @@ ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines)
|
|||
// unless they represent closed loops
|
||||
for (Polylines::iterator polyline = polylines->begin(); polyline != polylines->end(); ++polyline) {
|
||||
if (polyline->points.front().distance_to(polyline->points.back()) < min_width) continue;
|
||||
// TODO: we should *not* extend endpoints where other polylines start/end
|
||||
// (such as T joints, which are returned as three polylines by MedialAxis)
|
||||
polyline->extend_start(max_width);
|
||||
polyline->extend_end(max_width);
|
||||
}
|
||||
|
||||
// clip again after extending endpoints to prevent them from exceeding the expolygon boundaries
|
||||
intersection(*polylines, *this, polylines);
|
||||
|
||||
// remove too short polylines
|
||||
// (we can't do this check before endpoints extension and clipping because we don't
|
||||
// know how long will the endpoints be extended since it depends on polygon thickness
|
||||
// which is variable - extension will be <= max_width/2 on each side)
|
||||
for (size_t i = 0; i < polylines->size(); ++i) {
|
||||
if ((*polylines)[i].length() < max_width) {
|
||||
polylines->erase(polylines->begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -35,9 +35,15 @@ enum ExtrusionLoopRole {
|
|||
class ExtrusionEntity
|
||||
{
|
||||
public:
|
||||
virtual bool is_collection() const {
|
||||
return false;
|
||||
};
|
||||
virtual bool is_loop() const {
|
||||
return false;
|
||||
};
|
||||
virtual bool can_reverse() const {
|
||||
return true;
|
||||
};
|
||||
virtual ExtrusionEntity* clone() const = 0;
|
||||
virtual ~ExtrusionEntity() {};
|
||||
virtual void reverse() = 0;
|
||||
|
@ -92,6 +98,9 @@ class ExtrusionLoop : public ExtrusionEntity
|
|||
bool is_loop() const {
|
||||
return true;
|
||||
};
|
||||
bool can_reverse() const {
|
||||
return false;
|
||||
};
|
||||
ExtrusionLoop* clone() const;
|
||||
bool make_clockwise();
|
||||
bool make_counter_clockwise();
|
||||
|
|
|
@ -86,7 +86,7 @@ ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCo
|
|||
Points endpoints;
|
||||
for (ExtrusionEntitiesPtr::iterator it = my_paths.begin(); it != my_paths.end(); ++it) {
|
||||
endpoints.push_back((*it)->first_point());
|
||||
if (no_reverse) {
|
||||
if (no_reverse || !(*it)->can_reverse()) {
|
||||
endpoints.push_back((*it)->first_point());
|
||||
} else {
|
||||
endpoints.push_back((*it)->last_point());
|
||||
|
@ -99,7 +99,7 @@ ExtrusionEntityCollection::chained_path_from(Point start_near, ExtrusionEntityCo
|
|||
int path_index = start_index/2;
|
||||
ExtrusionEntity* entity = my_paths.at(path_index);
|
||||
// never reverse loops, since it's pointless for chained path and callers might depend on orientation
|
||||
if (start_index % 2 && !no_reverse && !entity->is_loop()) {
|
||||
if (start_index % 2 && !no_reverse && entity->can_reverse()) {
|
||||
entity->reverse();
|
||||
}
|
||||
retval->entities.push_back(my_paths.at(path_index));
|
||||
|
@ -121,6 +121,22 @@ ExtrusionEntityCollection::grow() const
|
|||
return pp;
|
||||
}
|
||||
|
||||
/* Recursively count paths and loops contained in this collection */
|
||||
size_t
|
||||
ExtrusionEntityCollection::items_count() const
|
||||
{
|
||||
size_t count = 0;
|
||||
for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
|
||||
if ((*it)->is_collection()) {
|
||||
ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(*it);
|
||||
count += collection->items_count();
|
||||
} else {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
// there is no ExtrusionLoop::Collection or ExtrusionEntity::Collection
|
||||
REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");
|
||||
|
|
|
@ -16,6 +16,12 @@ class ExtrusionEntityCollection : public ExtrusionEntity
|
|||
ExtrusionEntityCollection(): no_sort(false) {};
|
||||
ExtrusionEntityCollection(const ExtrusionEntityCollection &collection);
|
||||
ExtrusionEntityCollection& operator= (const ExtrusionEntityCollection &other);
|
||||
bool is_collection() const {
|
||||
return true;
|
||||
};
|
||||
bool can_reverse() const {
|
||||
return !this->no_sort;
|
||||
};
|
||||
void swap (ExtrusionEntityCollection &c);
|
||||
void chained_path(ExtrusionEntityCollection* retval, bool no_reverse = false, std::vector<size_t>* orig_indices = NULL) const;
|
||||
void chained_path_from(Point start_near, ExtrusionEntityCollection* retval, bool no_reverse = false, std::vector<size_t>* orig_indices = NULL) const;
|
||||
|
@ -23,6 +29,7 @@ class ExtrusionEntityCollection : public ExtrusionEntity
|
|||
Point first_point() const;
|
||||
Point last_point() const;
|
||||
Polygons grow() const;
|
||||
size_t items_count() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -161,6 +161,133 @@ simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval)
|
|||
Slic3r::simplify_polygons(pp, retval);
|
||||
}
|
||||
|
||||
double
|
||||
linint(double value, double oldmin, double oldmax, double newmin, double newmax)
|
||||
{
|
||||
return (value - oldmin) * (newmax - newmin) / (oldmax - oldmin) + newmin;
|
||||
}
|
||||
|
||||
Pointfs
|
||||
arrange(size_t total_parts, Pointf part, coordf_t dist, const BoundingBoxf &bb)
|
||||
{
|
||||
// use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm
|
||||
part.x += dist;
|
||||
part.y += dist;
|
||||
|
||||
Pointf area;
|
||||
if (bb.defined) {
|
||||
area = bb.size();
|
||||
} else {
|
||||
// bogus area size, large enough not to trigger the error below
|
||||
area.x = part.x * total_parts;
|
||||
area.y = part.y * total_parts;
|
||||
}
|
||||
|
||||
// this is how many cells we have available into which to put parts
|
||||
size_t cellw = floor((area.x + dist) / part.x);
|
||||
size_t cellh = floor((area.x + dist) / part.x);
|
||||
|
||||
if (total_parts > (cellw * cellh))
|
||||
CONFESS("%zu parts won't fit in your print area!\n", total_parts);
|
||||
|
||||
// total space used by cells
|
||||
Pointf cells(cellw * part.x, cellh * part.y);
|
||||
|
||||
// bounding box of total space used by cells
|
||||
BoundingBoxf cells_bb;
|
||||
cells_bb.merge(Pointf(0,0)); // min
|
||||
cells_bb.merge(cells); // max
|
||||
|
||||
// center bounding box to area
|
||||
cells_bb.translate(
|
||||
-(area.x - cells.x) / 2,
|
||||
-(area.y - cells.y) / 2
|
||||
);
|
||||
|
||||
// list of cells, sorted by distance from center
|
||||
std::vector<ArrangeItemIndex> cellsorder;
|
||||
|
||||
// work out distance for all cells, sort into list
|
||||
for (size_t i = 0; i <= cellw-1; ++i) {
|
||||
for (size_t j = 0; j <= cellh-1; ++j) {
|
||||
coordf_t cx = linint(i + 0.5, 0, cellw, cells_bb.min.x, cells_bb.max.x);
|
||||
coordf_t cy = linint(j + 0.5, 0, cellh, cells_bb.max.y, cells_bb.min.y);
|
||||
|
||||
coordf_t xd = fabs((area.x / 2) - cx);
|
||||
coordf_t yd = fabs((area.y / 2) - cy);
|
||||
|
||||
ArrangeItem c;
|
||||
c.pos.x = cx;
|
||||
c.pos.y = cy;
|
||||
c.index_x = i;
|
||||
c.index_y = j;
|
||||
c.dist = xd * xd + yd * yd - fabs((cellw / 2) - (i + 0.5));
|
||||
|
||||
// binary insertion sort
|
||||
{
|
||||
coordf_t index = c.dist;
|
||||
size_t low = 0;
|
||||
size_t high = cellsorder.size();
|
||||
while (low < high) {
|
||||
size_t mid = (low + ((high - low) / 2)) | 0;
|
||||
coordf_t midval = cellsorder[mid].index;
|
||||
|
||||
if (midval < index) {
|
||||
low = mid + 1;
|
||||
} else if (midval > index) {
|
||||
high = mid;
|
||||
} else {
|
||||
cellsorder.insert(cellsorder.begin() + mid, ArrangeItemIndex(index, c));
|
||||
goto ENDSORT;
|
||||
}
|
||||
}
|
||||
cellsorder.insert(cellsorder.begin() + low, ArrangeItemIndex(index, c));
|
||||
}
|
||||
ENDSORT: true;
|
||||
}
|
||||
}
|
||||
|
||||
// the extents of cells actually used by objects
|
||||
coordf_t lx = 0;
|
||||
coordf_t ty = 0;
|
||||
coordf_t rx = 0;
|
||||
coordf_t by = 0;
|
||||
|
||||
// now find cells actually used by objects, map out the extents so we can position correctly
|
||||
for (size_t i = 1; i <= total_parts; ++i) {
|
||||
ArrangeItemIndex c = cellsorder[i - 1];
|
||||
coordf_t cx = c.item.index_x;
|
||||
coordf_t cy = c.item.index_y;
|
||||
if (i == 1) {
|
||||
lx = rx = cx;
|
||||
ty = by = cy;
|
||||
} else {
|
||||
if (cx > rx) rx = cx;
|
||||
if (cx < lx) lx = cx;
|
||||
if (cy > by) by = cy;
|
||||
if (cy < ty) ty = cy;
|
||||
}
|
||||
}
|
||||
// now we actually place objects into cells, positioned such that the left and bottom borders are at 0
|
||||
Pointfs positions;
|
||||
for (size_t i = 1; i <= total_parts; ++i) {
|
||||
ArrangeItemIndex c = cellsorder.front();
|
||||
cellsorder.erase(cellsorder.begin());
|
||||
coordf_t cx = c.item.index_x - lx;
|
||||
coordf_t cy = c.item.index_y - ty;
|
||||
|
||||
positions.push_back(Pointf(cx * part.x, cy * part.y));
|
||||
}
|
||||
|
||||
if (bb.defined) {
|
||||
for (Pointfs::iterator p = positions.begin(); p != positions.end(); ++p) {
|
||||
p->x += bb.min.x;
|
||||
p->y += bb.min.y;
|
||||
}
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
Line
|
||||
MedialAxis::edge_to_line(const VD::edge_type &edge) const
|
||||
{
|
||||
|
@ -198,8 +325,11 @@ MedialAxis::build(Polylines* polylines)
|
|||
}
|
||||
*/
|
||||
|
||||
typedef const VD::vertex_type vert_t;
|
||||
typedef const VD::edge_type edge_t;
|
||||
|
||||
// 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
|
||||
// note: this keeps twins, so it inserts twice the number of the valid edges
|
||||
this->edges.clear();
|
||||
for (VD::const_edge_iterator edge = this->vd.edges().begin(); edge != this->vd.edges().end(); ++edge) {
|
||||
// if we only process segments representing closed loops, none if the
|
||||
|
@ -209,61 +339,64 @@ MedialAxis::build(Polylines* polylines)
|
|||
}
|
||||
|
||||
// count valid segments for each vertex
|
||||
std::map< const VD::vertex_type*,std::set<const VD::edge_type*> > vertex_edges;
|
||||
std::set<const VD::vertex_type*> entry_nodes;
|
||||
for (VD::const_vertex_iterator vertex = this->vd.vertices().begin(); vertex != this->vd.vertices().end(); ++vertex) {
|
||||
// get a reference to the list of valid edges originating from this vertex
|
||||
std::set<const VD::edge_type*>& edges = vertex_edges[&*vertex];
|
||||
std::map< vert_t*,std::set<edge_t*> > vertex_edges; // collects edges connected for each vertex
|
||||
std::set<vert_t*> startpoints; // collects all vertices having a single starting edge
|
||||
for (VD::const_vertex_iterator it = this->vd.vertices().begin(); it != this->vd.vertices().end(); ++it) {
|
||||
vert_t* vertex = &*it;
|
||||
|
||||
// get one random edge originating from this vertex
|
||||
const VD::edge_type* edge = vertex->incident_edge();
|
||||
// loop through all edges originating from this vertex
|
||||
// starting from a random one
|
||||
edge_t* edge = vertex->incident_edge();
|
||||
do {
|
||||
if (this->edges.count(edge) > 0) // only count valid edges
|
||||
edges.insert(edge);
|
||||
edge = edge->rot_next(); // next edge originating from this vertex
|
||||
// if this edge was not pruned by our filter above,
|
||||
// add it to vertex_edges
|
||||
if (this->edges.count(edge) > 0)
|
||||
vertex_edges[vertex].insert(edge);
|
||||
|
||||
// continue looping next edge originating from this vertex
|
||||
edge = edge->rot_next();
|
||||
} while (edge != vertex->incident_edge());
|
||||
|
||||
// if there's only one edge starting at this vertex then it's a leaf
|
||||
size_t edge_count = edges.size();
|
||||
if (edge_count == 1) {
|
||||
entry_nodes.insert(&*vertex);
|
||||
// if there's only one edge starting at this vertex then it's an endpoint
|
||||
if (vertex_edges[vertex].size() == 1) {
|
||||
startpoints.insert(vertex);
|
||||
}
|
||||
}
|
||||
|
||||
// prune recursively
|
||||
while (!entry_nodes.empty()) {
|
||||
// prune startpoints recursively if extreme segments are not valid
|
||||
while (!startpoints.empty()) {
|
||||
// get a random entry node
|
||||
const VD::vertex_type* v = *entry_nodes.begin();
|
||||
vert_t* v = *startpoints.begin();
|
||||
|
||||
// get edge starting from v
|
||||
assert(!vertex_edges[v].empty());
|
||||
const VD::edge_type* edge = *vertex_edges[v].begin();
|
||||
assert(vertex_edges[v].size() == 1);
|
||||
edge_t* edge = *vertex_edges[v].begin();
|
||||
|
||||
if (!this->is_valid_edge(*edge)) {
|
||||
// if edge is not valid, erase it from edge list
|
||||
// if edge is not valid, erase it and its twin from edge list
|
||||
(void)this->edges.erase(edge);
|
||||
(void)this->edges.erase(edge->twin());
|
||||
|
||||
// decrement edge counters for the affected nodes
|
||||
const VD::vertex_type* v1 = edge->vertex1();
|
||||
vert_t* v1 = edge->vertex1();
|
||||
(void)vertex_edges[v].erase(edge);
|
||||
(void)vertex_edges[v1].erase(edge->twin());
|
||||
|
||||
// also, check whether the end vertex is a new leaf
|
||||
if (vertex_edges[v1].size() == 1) {
|
||||
entry_nodes.insert(v1);
|
||||
startpoints.insert(v1);
|
||||
} else if (vertex_edges[v1].empty()) {
|
||||
entry_nodes.erase(v1);
|
||||
startpoints.erase(v1);
|
||||
}
|
||||
}
|
||||
|
||||
// remove node from the set to prevent it from being visited again
|
||||
entry_nodes.erase(v);
|
||||
startpoints.erase(v);
|
||||
}
|
||||
|
||||
// iterate through the valid edges to build polylines
|
||||
while (!this->edges.empty()) {
|
||||
const VD::edge_type& edge = **this->edges.begin();
|
||||
edge_t &edge = **this->edges.begin();
|
||||
|
||||
// start a polyline
|
||||
Polyline polyline;
|
||||
|
@ -278,13 +411,14 @@ MedialAxis::build(Polylines* polylines)
|
|||
this->process_edge_neighbors(edge, &polyline.points);
|
||||
|
||||
// get previous points
|
||||
Points pp;
|
||||
this->process_edge_neighbors(*edge.twin(), &pp);
|
||||
polyline.points.insert(polyline.points.begin(), pp.rbegin(), pp.rend());
|
||||
{
|
||||
Points pp;
|
||||
this->process_edge_neighbors(*edge.twin(), &pp);
|
||||
polyline.points.insert(polyline.points.begin(), pp.rbegin(), pp.rend());
|
||||
}
|
||||
|
||||
// append polyline to result if it's not too small
|
||||
if (polyline.length() > this->max_width)
|
||||
polylines->push_back(polyline);
|
||||
// append polyline to result
|
||||
polylines->push_back(polyline);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,69 +456,59 @@ MedialAxis::is_valid_edge(const VD::edge_type& edge) const
|
|||
"thin" nature of our input, these edges will be very short and not part of
|
||||
our wanted output. */
|
||||
|
||||
// retrieve the original line segments which generated the edge we're checking
|
||||
const VD::cell_type &cell1 = *edge.cell();
|
||||
const VD::cell_type &cell2 = *edge.twin()->cell();
|
||||
if (cell1.contains_segment() && cell2.contains_segment()) {
|
||||
Line segment1 = this->retrieve_segment(cell1);
|
||||
Line segment2 = this->retrieve_segment(cell2);
|
||||
if (segment1.a == segment2.b || segment1.b == segment2.a) return false;
|
||||
|
||||
// calculate relative angle between the two boundary segments
|
||||
double angle = fabs(segment2.orientation() - segment1.orientation());
|
||||
|
||||
// fabs(angle) ranges from 0 (collinear, same direction) to PI (collinear, opposite direction)
|
||||
// we're interested only in segments close to the second case (facing segments)
|
||||
// so we allow some tolerance (say, 30°)
|
||||
if (angle < PI*2/3 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// each vertex is equidistant to both cell segments
|
||||
// but such distance might differ between the two vertices;
|
||||
// in this case it means the shape is getting narrow (like a corner)
|
||||
// and we might need to skip the edge since it's not really part of
|
||||
// our skeleton
|
||||
Point v0( edge.vertex0()->x(), edge.vertex0()->y() );
|
||||
Point v1( edge.vertex1()->x(), edge.vertex1()->y() );
|
||||
double dist0 = v0.perp_distance_to(segment1);
|
||||
double dist1 = v1.perp_distance_to(segment1);
|
||||
|
||||
/*
|
||||
double diff = fabs(dist1 - dist0);
|
||||
double dist_between_segments1 = segment1.a.distance_to(segment2);
|
||||
double dist_between_segments2 = segment1.b.distance_to(segment2);
|
||||
printf("w = %f/%f, dist0 = %f, dist1 = %f, diff = %f, seg1len = %f, seg2len = %f, edgelen = %f, s2s = %f / %f\n",
|
||||
unscale(this->max_width), unscale(this->min_width),
|
||||
unscale(dist0), unscale(dist1), unscale(diff),
|
||||
unscale(segment1.length()), unscale(segment2.length()),
|
||||
unscale(this->edge_to_line(edge).length()),
|
||||
unscale(dist_between_segments1), unscale(dist_between_segments2)
|
||||
);
|
||||
*/
|
||||
|
||||
// if this segment is the centerline for a very thin area, we might want to skip it
|
||||
// in case the area is too thin
|
||||
if (dist0 < this->min_width/2 || dist1 < this->min_width/2) {
|
||||
//printf(" => too thin, skipping\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
// if distance between this edge and the thin area boundary is greater
|
||||
// than half the max width, then it's not a true medial axis segment
|
||||
if (dist1 > this->width*2) {
|
||||
printf(" => too fat, skipping\n");
|
||||
//return false;
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
if (!cell1.contains_segment() || !cell2.contains_segment()) return false;
|
||||
const Line &segment1 = this->retrieve_segment(cell1);
|
||||
const Line &segment2 = this->retrieve_segment(cell2);
|
||||
|
||||
// calculate the relative angle between the two boundary segments
|
||||
double angle = fabs(segment2.orientation() - segment1.orientation());
|
||||
|
||||
// fabs(angle) ranges from 0 (collinear, same direction) to PI (collinear, opposite direction)
|
||||
// we're interested only in segments close to the second case (facing segments)
|
||||
// so we allow some tolerance.
|
||||
// this filter ensures that we're dealing with a narrow/oriented area (longer than thick)
|
||||
if (fabs(angle - PI) > PI/5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
// each edge vertex is equidistant to both cell segments
|
||||
// but such distance might differ between the two vertices;
|
||||
// in this case it means the shape is getting narrow (like a corner)
|
||||
// and we might need to skip the edge since it's not really part of
|
||||
// our skeleton
|
||||
|
||||
// get perpendicular distance of each edge vertex to the segment(s)
|
||||
double dist0 = segment1.a.distance_to(segment2.b);
|
||||
double dist1 = segment1.b.distance_to(segment2.a);
|
||||
|
||||
/*
|
||||
Line line = this->edge_to_line(edge);
|
||||
double diff = fabs(dist1 - dist0);
|
||||
double dist_between_segments1 = segment1.a.distance_to(segment2);
|
||||
double dist_between_segments2 = segment1.b.distance_to(segment2);
|
||||
printf("w = %f/%f, dist0 = %f, dist1 = %f, diff = %f, seg1len = %f, seg2len = %f, edgelen = %f, s2s = %f / %f\n",
|
||||
unscale(this->max_width), unscale(this->min_width),
|
||||
unscale(dist0), unscale(dist1), unscale(diff),
|
||||
unscale(segment1.length()), unscale(segment2.length()),
|
||||
unscale(line.length()),
|
||||
unscale(dist_between_segments1), unscale(dist_between_segments2)
|
||||
);
|
||||
*/
|
||||
|
||||
// if this edge is the centerline for a very thin area, we might want to skip it
|
||||
// in case the area is too thin
|
||||
if (dist0 < this->min_width && dist1 < this->min_width) {
|
||||
//printf(" => too thin, skipping\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Line
|
||||
const Line&
|
||||
MedialAxis::retrieve_segment(const VD::cell_type& cell) const
|
||||
{
|
||||
VD::cell_type::source_index_type index = cell.source_index() - this->points.size();
|
||||
|
|
|
@ -23,6 +23,21 @@ double rad2deg_dir(double angle);
|
|||
double deg2rad(double angle);
|
||||
void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* retval);
|
||||
|
||||
class ArrangeItem {
|
||||
public:
|
||||
Pointf pos;
|
||||
size_t index_x, index_y;
|
||||
coordf_t dist;
|
||||
};
|
||||
class ArrangeItemIndex {
|
||||
public:
|
||||
coordf_t index;
|
||||
ArrangeItem item;
|
||||
ArrangeItemIndex(coordf_t _index, ArrangeItem _item) : index(_index), item(_item) {};
|
||||
};
|
||||
double linint(double value, double oldmin, double oldmax, double newmin, double newmax);
|
||||
Pointfs arrange(size_t total_parts, Pointf part, coordf_t dist, const BoundingBoxf &bb = BoundingBoxf());
|
||||
|
||||
class MedialAxis {
|
||||
public:
|
||||
Points points;
|
||||
|
@ -39,7 +54,7 @@ class MedialAxis {
|
|||
Line edge_to_line(const VD::edge_type &edge) const;
|
||||
void process_edge_neighbors(const voronoi_diagram<double>::edge_type& edge, Points* points);
|
||||
bool is_valid_edge(const voronoi_diagram<double>::edge_type& edge) const;
|
||||
Line retrieve_segment(const voronoi_diagram<double>::cell_type& cell) const;
|
||||
const Line& retrieve_segment(const voronoi_diagram<double>::cell_type& cell) const;
|
||||
};
|
||||
|
||||
} }
|
||||
|
|
|
@ -126,6 +126,14 @@ Layer::make_slices()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Layer::merge_slices()
|
||||
{
|
||||
FOREACH_LAYERREGION(this, layerm) {
|
||||
(*layerm)->merge_slices();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
Layer::any_internal_region_slice_contains(const T &item) const
|
||||
|
|
|
@ -47,7 +47,7 @@ class LayerRegion
|
|||
PolylineCollection unsupported_bridge_edges;
|
||||
|
||||
// ordered collection of extrusion paths/loops to build all perimeters
|
||||
// (this collection contains both ExtrusionPath and ExtrusionLoop objects)
|
||||
// (this collection contains only ExtrusionEntityCollection objects)
|
||||
ExtrusionEntityCollection perimeters;
|
||||
|
||||
// ordered collection of extrusion paths to fill surfaces
|
||||
|
@ -95,6 +95,7 @@ class Layer {
|
|||
LayerRegion* add_region(PrintRegion* print_region);
|
||||
|
||||
void make_slices();
|
||||
void merge_slices();
|
||||
template <class T> bool any_internal_region_slice_contains(const T &item) const;
|
||||
template <class T> bool any_bottom_region_slice_contains(const T &item) const;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Model.hpp"
|
||||
#include "Geometry.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -481,7 +482,12 @@ ModelObject::center_around_origin()
|
|||
|
||||
if (!this->instances.empty()) {
|
||||
for (ModelInstancePtrs::const_iterator i = this->instances.begin(); i != this->instances.end(); ++i) {
|
||||
(*i)->offset.translate(-vector.x, -vector.y);
|
||||
// apply rotation and scaling to vector as well before translating instance,
|
||||
// in order to leave final position unaltered
|
||||
Vectorf3 v = vector.negative();
|
||||
v.rotate((*i)->rotation, (*i)->offset);
|
||||
v.scale((*i)->scaling_factor);
|
||||
(*i)->offset.translate(v.x, v.y);
|
||||
}
|
||||
this->update_bounding_box();
|
||||
}
|
||||
|
@ -514,6 +520,26 @@ ModelObject::scale(const Pointf3 &versor)
|
|||
this->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
void
|
||||
ModelObject::rotate(float angle, const Axis &axis)
|
||||
{
|
||||
for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) {
|
||||
(*v)->mesh.rotate(angle, axis);
|
||||
}
|
||||
this->origin_translation = Pointf3(0,0,0);
|
||||
this->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
void
|
||||
ModelObject::flip(const Axis &axis)
|
||||
{
|
||||
for (ModelVolumePtrs::const_iterator v = this->volumes.begin(); v != this->volumes.end(); ++v) {
|
||||
(*v)->mesh.flip(axis);
|
||||
}
|
||||
this->origin_translation = Pointf3(0,0,0);
|
||||
this->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
size_t
|
||||
ModelObject::materials_count() const
|
||||
{
|
||||
|
|
|
@ -129,6 +129,8 @@ class ModelObject
|
|||
void translate(const Vectorf3 &vector);
|
||||
void translate(coordf_t x, coordf_t y, coordf_t z);
|
||||
void scale(const Pointf3 &versor);
|
||||
void rotate(float angle, const Axis &axis);
|
||||
void flip(const Axis &axis);
|
||||
size_t materials_count() const;
|
||||
size_t facets_count() const;
|
||||
bool needed_repair() const;
|
||||
|
@ -175,7 +177,7 @@ class ModelInstance
|
|||
{
|
||||
friend class ModelObject;
|
||||
public:
|
||||
double rotation; // around mesh center point
|
||||
double rotation; // in radians around mesh center point
|
||||
double scaling_factor;
|
||||
Pointf offset; // in unscaled coordinates
|
||||
|
||||
|
|
|
@ -29,22 +29,14 @@ PlaceholderParser::update_timestamp()
|
|||
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_hour;
|
||||
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_min;
|
||||
ss << std::setw(2) << std::setfill('0') << timeinfo->tm_sec;
|
||||
this->_single["timestamp"] = ss.str();
|
||||
this->set("timestamp", ss.str());
|
||||
}
|
||||
this->_single["year"] = this->_int_to_string(1900 + timeinfo->tm_year);
|
||||
this->_single["month"] = this->_int_to_string(1 + timeinfo->tm_mon);
|
||||
this->_single["day"] = this->_int_to_string(timeinfo->tm_mday);
|
||||
this->_single["hour"] = this->_int_to_string(timeinfo->tm_hour);
|
||||
this->_single["minute"] = this->_int_to_string(timeinfo->tm_min);
|
||||
this->_single["second"] = this->_int_to_string(timeinfo->tm_sec);
|
||||
}
|
||||
|
||||
std::string
|
||||
PlaceholderParser::_int_to_string(int value) const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << value;
|
||||
return ss.str();
|
||||
this->set("year", 1900 + timeinfo->tm_year);
|
||||
this->set("month", 1 + timeinfo->tm_mon);
|
||||
this->set("day", timeinfo->tm_mday);
|
||||
this->set("hour", timeinfo->tm_hour);
|
||||
this->set("minute", timeinfo->tm_min);
|
||||
this->set("second", timeinfo->tm_sec);
|
||||
}
|
||||
|
||||
void PlaceholderParser::apply_config(DynamicPrintConfig &config)
|
||||
|
@ -66,53 +58,20 @@ void PlaceholderParser::apply_config(DynamicPrintConfig &config)
|
|||
i != opt_keys.end(); ++i)
|
||||
{
|
||||
const t_config_option_key &key = *i;
|
||||
|
||||
// set placeholders for options with multiple values
|
||||
const ConfigOptionDef &def = (*config.def)[key];
|
||||
switch (def.type) {
|
||||
case coFloats:
|
||||
this->set_multiple_from_vector(key,
|
||||
*(ConfigOptionFloats*)config.option(key));
|
||||
break;
|
||||
|
||||
case coInts:
|
||||
this->set_multiple_from_vector(key,
|
||||
*(ConfigOptionInts*)config.option(key));
|
||||
break;
|
||||
|
||||
case coStrings:
|
||||
this->set_multiple_from_vector(key,
|
||||
*(ConfigOptionStrings*)config.option(key));
|
||||
break;
|
||||
|
||||
case coPoints:
|
||||
this->set_multiple_from_vector(key,
|
||||
*(ConfigOptionPoints*)config.option(key));
|
||||
break;
|
||||
|
||||
case coBools:
|
||||
this->set_multiple_from_vector(key,
|
||||
*(ConfigOptionBools*)config.option(key));
|
||||
break;
|
||||
|
||||
case coPoint:
|
||||
{
|
||||
const ConfigOptionPoint &opt =
|
||||
*(ConfigOptionPoint*)config.option(key);
|
||||
|
||||
this->_single[key] = opt.serialize();
|
||||
|
||||
Pointf val = opt;
|
||||
this->_multiple[key + "_X"] = val.x;
|
||||
this->_multiple[key + "_Y"] = val.y;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
const ConfigOption* opt = config.option(key);
|
||||
|
||||
if (const ConfigOptionVectorBase* optv = dynamic_cast<const ConfigOptionVectorBase*>(opt)) {
|
||||
// set placeholders for options with multiple values
|
||||
this->set(key, optv->vserialize());
|
||||
} else if (const ConfigOptionPoint* optp = dynamic_cast<const ConfigOptionPoint*>(opt)) {
|
||||
this->_single[key] = optp->serialize();
|
||||
|
||||
Pointf val = *optp;
|
||||
this->_multiple[key + "_X"] = val.x;
|
||||
this->_multiple[key + "_Y"] = val.y;
|
||||
} else {
|
||||
// set single-value placeholders
|
||||
this->_single[key] = config.serialize(key);
|
||||
break;
|
||||
this->_single[key] = opt->serialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,34 +80,30 @@ void
|
|||
PlaceholderParser::set(const std::string &key, const std::string &value)
|
||||
{
|
||||
this->_single[key] = value;
|
||||
this->_multiple.erase(key);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream &stm, const Pointf &pointf)
|
||||
void
|
||||
PlaceholderParser::set(const std::string &key, int value)
|
||||
{
|
||||
return stm << pointf.x << "," << pointf.y;
|
||||
std::ostringstream ss;
|
||||
ss << value;
|
||||
this->set(key, ss.str());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void PlaceholderParser::set_multiple_from_vector(const std::string &key,
|
||||
ConfigOptionVector<T> &opt)
|
||||
void
|
||||
PlaceholderParser::set(const std::string &key, const std::vector<std::string> &values)
|
||||
{
|
||||
const std::vector<T> &vals = opt.values;
|
||||
|
||||
for (size_t i = 0; i < vals.size(); ++i) {
|
||||
std::stringstream multikey_stm;
|
||||
multikey_stm << key << "_" << i;
|
||||
|
||||
std::stringstream val_stm;
|
||||
val_stm << vals[i];
|
||||
|
||||
this->_multiple[multikey_stm.str()] = val_stm.str();
|
||||
}
|
||||
|
||||
if (vals.size() > 0) {
|
||||
std::stringstream val_stm;
|
||||
val_stm << vals[0];
|
||||
this->_multiple[key] = val_stm.str();
|
||||
for (std::vector<std::string>::const_iterator v = values.begin(); v != values.end(); ++v) {
|
||||
std::stringstream ss;
|
||||
ss << key << "_" << (v - values.begin());
|
||||
|
||||
this->_multiple[ ss.str() ] = *v;
|
||||
if (v == values.begin()) {
|
||||
this->_multiple[key] = *v;
|
||||
}
|
||||
}
|
||||
this->_single.erase(key);
|
||||
}
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <myinit.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
|
||||
|
@ -20,12 +21,8 @@ class PlaceholderParser
|
|||
void update_timestamp();
|
||||
void apply_config(DynamicPrintConfig &config);
|
||||
void set(const std::string &key, const std::string &value);
|
||||
|
||||
private:
|
||||
template<class T>
|
||||
void set_multiple_from_vector(
|
||||
const std::string &key, ConfigOptionVector<T> &opt);
|
||||
std::string _int_to_string(int value) const;
|
||||
void set(const std::string &key, int value);
|
||||
void set(const std::string &key, const std::vector<std::string> &values);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "MultiPoint.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -340,6 +339,12 @@ REGISTER_CLASS(Point3, "Point3");
|
|||
|
||||
#endif
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream &stm, const Pointf &pointf)
|
||||
{
|
||||
return stm << pointf.x << "," << pointf.y;
|
||||
}
|
||||
|
||||
void
|
||||
Pointf::scale(double factor)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <vector>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -77,6 +78,8 @@ class Point3 : public Point
|
|||
explicit Point3(coord_t _x = 0, coord_t _y = 0, coord_t _z = 0): Point(_x, _y), z(_z) {};
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &stm, const Pointf &pointf);
|
||||
|
||||
class Pointf
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -139,11 +139,31 @@ Polyline::simplify_by_visibility(const T &area)
|
|||
Points &pp = this->points;
|
||||
|
||||
// find first point in area
|
||||
size_t start = 0;
|
||||
while (start < pp.size() && !area.contains(pp[start])) {
|
||||
start++;
|
||||
size_t s = 0;
|
||||
while (s < pp.size() && !area.contains(pp[s])) {
|
||||
++s;
|
||||
}
|
||||
|
||||
// find last point in area
|
||||
size_t e = pp.size()-1;
|
||||
while (e > 0 && !area.contains(pp[e])) {
|
||||
--e;
|
||||
}
|
||||
|
||||
// this ugly algorithm resembles a binary search
|
||||
while (e > s + 1) {
|
||||
size_t mid = (s + e) / 2;
|
||||
if (area.contains(Line(pp[s], pp[mid]))) {
|
||||
pp.erase(pp.begin() + s + 1, pp.begin() + mid);
|
||||
// repeat recursively until no further simplification is possible
|
||||
++s;
|
||||
e = pp.size()-1;
|
||||
} else {
|
||||
e = mid;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// The following implementation is complete but it's not efficient at all:
|
||||
for (size_t s = start; s < pp.size() && !pp.empty(); ++s) {
|
||||
// find the farthest point to which we can build
|
||||
// a line that is contained in the supplied area
|
||||
|
@ -158,6 +178,7 @@ Polyline::simplify_by_visibility(const T &area)
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
template void Polyline::simplify_by_visibility<ExPolygon>(const ExPolygon &area);
|
||||
template void Polyline::simplify_by_visibility<ExPolygonCollection>(const ExPolygonCollection &area);
|
||||
|
|
|
@ -172,7 +172,8 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|
|||
} else if (*opt_key == "brim_width") {
|
||||
steps.insert(psBrim);
|
||||
steps.insert(psSkirt);
|
||||
} else if (*opt_key == "nozzle_diameter") {
|
||||
} else if (*opt_key == "nozzle_diameter"
|
||||
|| *opt_key == "resolution") {
|
||||
osteps.insert(posSlice);
|
||||
} else if (*opt_key == "avoid_crossing_perimeters"
|
||||
|| *opt_key == "bed_shape"
|
||||
|
@ -300,7 +301,7 @@ Print::step_done(PrintObjectStep step) const
|
|||
|
||||
// returns 0-based indices of used extruders
|
||||
std::set<size_t>
|
||||
Print::extruders() const
|
||||
Print::object_extruders() const
|
||||
{
|
||||
std::set<size_t> extruders;
|
||||
|
||||
|
@ -316,6 +317,16 @@ Print::extruders() const
|
|||
if ((*region)->config.top_solid_layers.value > 0 || (*region)->config.bottom_solid_layers.value > 0)
|
||||
extruders.insert((*region)->config.solid_infill_extruder - 1);
|
||||
}
|
||||
|
||||
return extruders;
|
||||
}
|
||||
|
||||
// returns 0-based indices of used extruders
|
||||
std::set<size_t>
|
||||
Print::support_material_extruders() const
|
||||
{
|
||||
std::set<size_t> extruders;
|
||||
|
||||
FOREACH_OBJECT(this, object) {
|
||||
if ((*object)->has_support_material()) {
|
||||
extruders.insert((*object)->config.support_material_extruder - 1);
|
||||
|
@ -326,6 +337,18 @@ Print::extruders() const
|
|||
return extruders;
|
||||
}
|
||||
|
||||
// returns 0-based indices of used extruders
|
||||
std::set<size_t>
|
||||
Print::extruders() const
|
||||
{
|
||||
std::set<size_t> extruders = this->object_extruders();
|
||||
|
||||
std::set<size_t> s_extruders = this->support_material_extruders();
|
||||
extruders.insert(s_extruders.begin(), s_extruders.end());
|
||||
|
||||
return extruders;
|
||||
}
|
||||
|
||||
void
|
||||
Print::_simplify_slices(double distance)
|
||||
{
|
||||
|
|
|
@ -199,6 +199,8 @@ class Print
|
|||
Flow brim_flow() const;
|
||||
Flow skirt_flow() const;
|
||||
|
||||
std::set<size_t> object_extruders() const;
|
||||
std::set<size_t> support_material_extruders() const;
|
||||
std::set<size_t> extruders() const;
|
||||
void _simplify_slices(double distance);
|
||||
double max_allowed_layer_height() const;
|
||||
|
|
|
@ -232,6 +232,12 @@ PrintConfigDef::build_def() {
|
|||
Options["fan_below_layer_time"].min = 0;
|
||||
Options["fan_below_layer_time"].max = 1000;
|
||||
|
||||
Options["filament_colour"].type = coStrings;
|
||||
Options["filament_colour"].label = "Color";
|
||||
Options["filament_colour"].tooltip = "This is only used in the Slic3r interface as a visual help.";
|
||||
Options["filament_colour"].cli = "filament-color=s@";
|
||||
Options["filament_colour"].gui_type = "color";
|
||||
|
||||
Options["filament_diameter"].type = coFloats;
|
||||
Options["filament_diameter"].label = "Diameter";
|
||||
Options["filament_diameter"].tooltip = "Enter your filament diameter here. Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average.";
|
||||
|
|
|
@ -409,6 +409,7 @@ class PrintConfig : public GCodeConfig
|
|||
ConfigOptionPoints extruder_offset;
|
||||
ConfigOptionBool fan_always_on;
|
||||
ConfigOptionInt fan_below_layer_time;
|
||||
ConfigOptionStrings filament_colour;
|
||||
ConfigOptionFloat first_layer_acceleration;
|
||||
ConfigOptionInt first_layer_bed_temperature;
|
||||
ConfigOptionFloatOrPercent first_layer_extrusion_width;
|
||||
|
@ -464,6 +465,8 @@ class PrintConfig : public GCodeConfig
|
|||
this->extruder_offset.values[0] = Pointf(0,0);
|
||||
this->fan_always_on.value = false;
|
||||
this->fan_below_layer_time.value = 60;
|
||||
this->filament_colour.values.resize(1);
|
||||
this->filament_colour.values[0] = "#FFFFFF";
|
||||
this->first_layer_acceleration.value = 0;
|
||||
this->first_layer_bed_temperature.value = 0;
|
||||
this->first_layer_extrusion_width.value = 200;
|
||||
|
@ -523,6 +526,7 @@ class PrintConfig : public GCodeConfig
|
|||
if (opt_key == "extruder_offset") return &this->extruder_offset;
|
||||
if (opt_key == "fan_always_on") return &this->fan_always_on;
|
||||
if (opt_key == "fan_below_layer_time") return &this->fan_below_layer_time;
|
||||
if (opt_key == "filament_colour") return &this->filament_colour;
|
||||
if (opt_key == "first_layer_acceleration") return &this->first_layer_acceleration;
|
||||
if (opt_key == "first_layer_bed_temperature") return &this->first_layer_bed_temperature;
|
||||
if (opt_key == "first_layer_extrusion_width") return &this->first_layer_extrusion_width;
|
||||
|
|
|
@ -222,8 +222,7 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
|
|||
|| *opt_key == "thin_walls"
|
||||
|| *opt_key == "external_perimeters_first") {
|
||||
steps.insert(posPerimeters);
|
||||
} else if (*opt_key == "resolution"
|
||||
|| *opt_key == "layer_height"
|
||||
} else if (*opt_key == "layer_height"
|
||||
|| *opt_key == "first_layer_height"
|
||||
|| *opt_key == "xy_size_compensation"
|
||||
|| *opt_key == "raft_layers") {
|
||||
|
|
|
@ -200,40 +200,61 @@ void TriangleMesh::translate(float x, float y, float z)
|
|||
stl_invalidate_shared_vertices(&this->stl);
|
||||
}
|
||||
|
||||
void TriangleMesh::rotate(float angle, const Axis &axis)
|
||||
{
|
||||
// admesh uses degrees
|
||||
angle = Slic3r::Geometry::rad2deg(angle);
|
||||
|
||||
if (axis == X) {
|
||||
stl_rotate_x(&(this->stl), angle);
|
||||
} else if (axis == Y) {
|
||||
stl_rotate_y(&(this->stl), angle);
|
||||
} else if (axis == Z) {
|
||||
stl_rotate_z(&(this->stl), angle);
|
||||
}
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
}
|
||||
|
||||
void TriangleMesh::rotate_x(float angle)
|
||||
{
|
||||
stl_rotate_x(&(this->stl), angle);
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
this->rotate(angle, X);
|
||||
}
|
||||
|
||||
void TriangleMesh::rotate_y(float angle)
|
||||
{
|
||||
stl_rotate_y(&(this->stl), angle);
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
this->rotate(angle, Y);
|
||||
}
|
||||
|
||||
void TriangleMesh::rotate_z(float angle)
|
||||
{
|
||||
stl_rotate_z(&(this->stl), angle);
|
||||
this->rotate(angle, Z);
|
||||
}
|
||||
|
||||
void TriangleMesh::flip(const Axis &axis)
|
||||
{
|
||||
if (axis == X) {
|
||||
stl_mirror_yz(&this->stl);
|
||||
} else if (axis == Y) {
|
||||
stl_mirror_xz(&this->stl);
|
||||
} else if (axis == Z) {
|
||||
stl_mirror_xy(&this->stl);
|
||||
}
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
}
|
||||
|
||||
void TriangleMesh::flip_x()
|
||||
{
|
||||
stl_mirror_yz(&this->stl);
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
this->flip(X);
|
||||
}
|
||||
|
||||
void TriangleMesh::flip_y()
|
||||
{
|
||||
stl_mirror_xz(&this->stl);
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
this->flip(Y);
|
||||
}
|
||||
|
||||
void TriangleMesh::flip_z()
|
||||
{
|
||||
stl_mirror_xy(&this->stl);
|
||||
stl_invalidate_shared_vertices(&this->stl);
|
||||
this->flip(Z);
|
||||
}
|
||||
|
||||
void TriangleMesh::align_to_origin()
|
||||
|
|
|
@ -32,9 +32,11 @@ class TriangleMesh
|
|||
void scale(float factor);
|
||||
void scale(const Pointf3 &versor);
|
||||
void translate(float x, float y, float z);
|
||||
void rotate(float angle, const Axis &axis);
|
||||
void rotate_x(float angle);
|
||||
void rotate_y(float angle);
|
||||
void rotate_z(float angle);
|
||||
void flip(const Axis &axis);
|
||||
void flip_x();
|
||||
void flip_y();
|
||||
void flip_z();
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#define SLIC3R_VERSION "1.2.7-dev"
|
||||
#define SLIC3R_VERSION "1.2.8-dev"
|
||||
|
||||
#define EPSILON 1e-4
|
||||
#define SCALING_FACTOR 0.000001
|
||||
|
@ -17,7 +17,12 @@
|
|||
typedef long coord_t;
|
||||
typedef double coordf_t;
|
||||
|
||||
namespace Slic3r {}
|
||||
namespace Slic3r {
|
||||
|
||||
// TODO: make sure X = 0
|
||||
enum Axis { X, Y, Z };
|
||||
|
||||
}
|
||||
using namespace Slic3r;
|
||||
|
||||
/* Implementation of CONFESS("foo"): */
|
||||
|
|
|
@ -4,7 +4,7 @@ use strict;
|
|||
use warnings;
|
||||
|
||||
use Slic3r::XS;
|
||||
use Test::More tests => 22;
|
||||
use Test::More tests => 24;
|
||||
|
||||
my $point = Slic3r::Point->new(10, 15);
|
||||
is_deeply [ @$point ], [10, 15], 'point roundtrip';
|
||||
|
@ -32,12 +32,14 @@ ok !$point->coincides_with($point2), 'coincides_with';
|
|||
|
||||
{
|
||||
my $line = Slic3r::Line->new([0,0], [100,0]);
|
||||
is +Slic3r::Point->new(0,0)->distance_to_line($line), 0, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(0,0) ->distance_to_line($line), 0, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(100,0)->distance_to_line($line), 0, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(50,0)->distance_to_line($line), 0, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(50,0) ->distance_to_line($line), 0, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(150,0)->distance_to_line($line), 50, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(0,50)->distance_to_line($line), 50, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(0,50) ->distance_to_line($line), 50, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(50,50)->distance_to_line($line), 50, 'distance_to_line()';
|
||||
is +Slic3r::Point->new(50,50) ->perp_distance_to_line($line), 50, 'perp_distance_to_line()';
|
||||
is +Slic3r::Point->new(150,50)->perp_distance_to_line($line), 50, 'perp_distance_to_line()';
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@ use strict;
|
|||
use warnings;
|
||||
|
||||
use Slic3r::XS;
|
||||
use Test::More tests => 21;
|
||||
use Test::More tests => 18;
|
||||
|
||||
my $points = [
|
||||
[100, 100],
|
||||
|
@ -88,7 +88,8 @@ is_deeply $polyline->pp, [ @$points, @$points ], 'append_polyline';
|
|||
is scalar(@$p2), 4, 'split_at';
|
||||
}
|
||||
|
||||
{
|
||||
# disabled because we now use a more efficient but incomplete algorithm
|
||||
if (0) {
|
||||
my $polyline = Slic3r::Polyline->new(
|
||||
map [$_,10], (0,10,20,30,40,50,60)
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@ use strict;
|
|||
use warnings;
|
||||
|
||||
use Slic3r::XS;
|
||||
use Test::More tests => 16;
|
||||
use Test::More tests => 18;
|
||||
|
||||
my $points = [
|
||||
[100, 100],
|
||||
|
@ -87,4 +87,11 @@ is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated';
|
|||
pass 'chained_path with no_sort';
|
||||
}
|
||||
|
||||
{
|
||||
my $coll2 = $collection->clone;
|
||||
ok !$coll2->no_sort, 'expected no_sort value';
|
||||
$coll2->no_sort(1);
|
||||
ok $coll2->clone->no_sort, 'no_sort is kept after clone';
|
||||
}
|
||||
|
||||
__END__
|
||||
|
|
|
@ -4,7 +4,7 @@ use strict;
|
|||
use warnings;
|
||||
|
||||
use Slic3r::XS;
|
||||
use Test::More tests => 8;
|
||||
use Test::More tests => 9;
|
||||
|
||||
use constant PI => 4 * atan2(1, 1);
|
||||
|
||||
|
@ -31,4 +31,11 @@ use constant PI => 4 * atan2(1, 1);
|
|||
ok !Slic3r::Geometry::directions_parallel_within(PI/2, PI, 0), 'directions_parallel_within';
|
||||
ok !Slic3r::Geometry::directions_parallel_within(PI/2, PI, PI/180), 'directions_parallel_within';
|
||||
}
|
||||
|
||||
{
|
||||
my $positions = Slic3r::Geometry::arrange(4, Slic3r::Pointf->new(20, 20),
|
||||
5, Slic3r::Geometry::BoundingBoxf->new);
|
||||
is scalar(@$positions), 4, 'arrange() returns expected number of positions';
|
||||
}
|
||||
|
||||
__END__
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
%name{Slic3r::ExtrusionPath::Collection} class ExtrusionEntityCollection {
|
||||
%name{_new} ExtrusionEntityCollection();
|
||||
Clone<ExtrusionEntityCollection> clone()
|
||||
%code{% RETVAL = THIS->clone(); %};
|
||||
void reverse();
|
||||
void clear()
|
||||
%code{% THIS->entities.clear(); %};
|
||||
|
@ -24,6 +26,8 @@
|
|||
Clone<Point> last_point();
|
||||
int count()
|
||||
%code{% RETVAL = THIS->entities.size(); %};
|
||||
int items_count()
|
||||
%code{% RETVAL = THIS->items_count(); %};
|
||||
bool empty()
|
||||
%code{% RETVAL = THIS->entities.empty(); %};
|
||||
std::vector<size_t> orig_indices()
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
%package{Slic3r::Geometry};
|
||||
|
||||
Pointfs arrange(size_t total_parts, Pointf* part, coordf_t dist, BoundingBoxf* bb)
|
||||
%code{% RETVAL = Slic3r::Geometry::arrange(total_parts, *part, dist, *bb); %};
|
||||
|
||||
%{
|
||||
|
||||
bool
|
||||
|
@ -87,4 +90,17 @@ simplify_polygons(polygons, tolerance)
|
|||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
|
||||
IV
|
||||
_constant()
|
||||
ALIAS:
|
||||
X = X
|
||||
Y = Y
|
||||
Z = Z
|
||||
PROTOTYPE:
|
||||
CODE:
|
||||
RETVAL = ix;
|
||||
OUTPUT: RETVAL
|
||||
|
||||
%}
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
%code%{ RETVAL = (int)(intptr_t)THIS; %};
|
||||
|
||||
void make_slices();
|
||||
void merge_slices();
|
||||
bool any_internal_region_slice_contains_polyline(Polyline* polyline)
|
||||
%code%{ RETVAL = THIS->any_internal_region_slice_contains(*polyline); %};
|
||||
bool any_bottom_region_slice_contains_polyline(Polyline* polyline)
|
||||
|
|
|
@ -182,6 +182,8 @@ ModelMaterial::attributes()
|
|||
void translate(double x, double y, double z);
|
||||
void scale_xyz(Pointf3* versor)
|
||||
%code{% THIS->scale(*versor); %};
|
||||
void rotate(float angle, Axis axis);
|
||||
void flip(Axis axis);
|
||||
|
||||
Model* cut(double z)
|
||||
%code%{
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
void apply_config(DynamicPrintConfig *config)
|
||||
%code%{ THIS->apply_config(*config); %};
|
||||
void set(std::string key, std::string value);
|
||||
void set_multiple(std::string key, std::vector<std::string> values)
|
||||
%code%{ THIS->set(key, values); %};
|
||||
|
||||
void _single_set(std::string k, std::string v)
|
||||
%code%{ THIS->_single[k] = v; %};
|
||||
|
|
|
@ -161,6 +161,22 @@ _constant()
|
|||
void set_step_started(PrintStep step)
|
||||
%code%{ THIS->state.set_started(step); %};
|
||||
|
||||
std::vector<int> object_extruders()
|
||||
%code%{
|
||||
std::set<size_t> extruders = THIS->object_extruders();
|
||||
RETVAL.reserve(extruders.size());
|
||||
for (std::set<size_t>::const_iterator e = extruders.begin(); e != extruders.end(); ++e) {
|
||||
RETVAL.push_back(*e);
|
||||
}
|
||||
%};
|
||||
std::vector<int> support_material_extruders()
|
||||
%code%{
|
||||
std::set<size_t> extruders = THIS->support_material_extruders();
|
||||
RETVAL.reserve(extruders.size());
|
||||
for (std::set<size_t>::const_iterator e = extruders.begin(); e != extruders.end(); ++e) {
|
||||
RETVAL.push_back(*e);
|
||||
}
|
||||
%};
|
||||
std::vector<int> extruders()
|
||||
%code%{
|
||||
std::set<size_t> extruders = THIS->extruders();
|
||||
|
|
|
@ -188,6 +188,7 @@ Clone<BridgeDetector> O_OBJECT_SLIC3R_T
|
|||
|
||||
GLVertexArray* O_OBJECT_SLIC3R
|
||||
|
||||
Axis T_UV
|
||||
ExtrusionLoopRole T_UV
|
||||
ExtrusionRole T_UV
|
||||
FlowRole T_UV
|
||||
|
|
|
@ -176,6 +176,12 @@
|
|||
%typemap{SupportLayerPtrs*};
|
||||
|
||||
|
||||
%typemap{Axis}{parsed}{
|
||||
%cpp_type{Axis};
|
||||
%precall_code{%
|
||||
$CVar = (Axis)SvUV($PerlVar);
|
||||
%};
|
||||
};
|
||||
%typemap{SurfaceType}{parsed}{
|
||||
%cpp_type{SurfaceType};
|
||||
%precall_code{%
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue