Merge branch 'dev' of https://github.com/prusa3d/PrusaSlicer into et_reload_from_disk
This commit is contained in:
commit
d6c3c766aa
@ -247,7 +247,7 @@ extern void its_transform(indexed_triangle_set &its, T *trafo3x4)
|
||||
template<typename T>
|
||||
inline void its_transform(indexed_triangle_set &its, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
|
||||
{
|
||||
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
|
||||
//const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
|
||||
for (stl_vertex &v : its.vertices)
|
||||
v = (t * v.template cast<T>()).template cast<float>().eval();
|
||||
}
|
||||
|
@ -13,103 +13,200 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct SurfaceGroupAttrib
|
||||
struct SurfaceFillParams
|
||||
{
|
||||
SurfaceGroupAttrib() : is_solid(false), flow_width(0.f), pattern(-1) {}
|
||||
bool operator==(const SurfaceGroupAttrib &other) const
|
||||
{ return is_solid == other.is_solid && flow_width == other.flow_width && pattern == other.pattern; }
|
||||
bool is_solid;
|
||||
float flow_width;
|
||||
// pattern is of type InfillPattern, -1 for an unset pattern.
|
||||
int pattern;
|
||||
SurfaceFillParams() : flow(0.f, 0.f, 0.f, false) { memset(this, 0, sizeof(*this)); }
|
||||
// Zero based extruder ID.
|
||||
unsigned int extruder;
|
||||
// Infill pattern, adjusted for the density etc.
|
||||
InfillPattern pattern;
|
||||
|
||||
// FillBase
|
||||
// in unscaled coordinates
|
||||
coordf_t spacing;
|
||||
// infill / perimeter overlap, in unscaled coordinates
|
||||
coordf_t overlap;
|
||||
// Angle as provided by the region config, in radians.
|
||||
float angle;
|
||||
// Non-negative for a bridge.
|
||||
float bridge_angle;
|
||||
|
||||
// FillParams
|
||||
float density;
|
||||
// Don't connect the fill lines around the inner perimeter.
|
||||
bool dont_connect;
|
||||
// Don't adjust spacing to fill the space evenly.
|
||||
bool dont_adjust;
|
||||
|
||||
// width, height of extrusion, nozzle diameter, is bridge
|
||||
// For the output, for fill generator.
|
||||
Flow flow;
|
||||
|
||||
// For the output
|
||||
ExtrusionRole extrusion_role;
|
||||
|
||||
// Various print settings?
|
||||
|
||||
// Index of this entry in a linear vector.
|
||||
size_t idx;
|
||||
|
||||
|
||||
bool operator<(const SurfaceFillParams &rhs) const {
|
||||
#define RETURN_COMPARE_NON_EQUAL(KEY) if (this->KEY < rhs.KEY) return true; if (this->KEY > rhs.KEY) return false;
|
||||
#define RETURN_COMPARE_NON_EQUAL_TYPED(TYPE, KEY) if (TYPE(this->KEY) < TYPE(rhs.KEY)) return true; if (TYPE(this->KEY) > TYPE(rhs.KEY)) return false;
|
||||
|
||||
// Sort first by decreasing bridging angle, so that the bridges are processed with priority when trimming one layer by the other.
|
||||
if (this->bridge_angle > rhs.bridge_angle) return true;
|
||||
if (this->bridge_angle < rhs.bridge_angle) return false;
|
||||
|
||||
RETURN_COMPARE_NON_EQUAL(extruder);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, pattern);
|
||||
RETURN_COMPARE_NON_EQUAL(spacing);
|
||||
RETURN_COMPARE_NON_EQUAL(overlap);
|
||||
RETURN_COMPARE_NON_EQUAL(angle);
|
||||
RETURN_COMPARE_NON_EQUAL(density);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_connect);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.width);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.height);
|
||||
RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, flow.bridge);
|
||||
RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, extrusion_role);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const SurfaceFillParams &rhs) const {
|
||||
return this->extruder == rhs.extruder &&
|
||||
this->pattern == rhs.pattern &&
|
||||
this->pattern == rhs.pattern &&
|
||||
this->spacing == rhs.spacing &&
|
||||
this->overlap == rhs.overlap &&
|
||||
this->angle == rhs.angle &&
|
||||
this->density == rhs.density &&
|
||||
this->dont_connect == rhs.dont_connect &&
|
||||
this->dont_adjust == rhs.dont_adjust &&
|
||||
this->flow == rhs.flow &&
|
||||
this->extrusion_role == rhs.extrusion_role;
|
||||
}
|
||||
};
|
||||
|
||||
// Generate infills for Slic3r::Layer::Region.
|
||||
// The Slic3r::Layer::Region at this point of time may contain
|
||||
// surfaces of various types (internal/bridge/top/bottom/solid).
|
||||
// The infills are generated on the groups of surfaces with a compatible type.
|
||||
// Returns an array of Slic3r::ExtrusionPath::Collection objects containing the infills generaed now
|
||||
// and the thin fills generated by generate_perimeters().
|
||||
void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
{
|
||||
// Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id;
|
||||
|
||||
double fill_density = layerm.region()->config().fill_density;
|
||||
Flow infill_flow = layerm.flow(frInfill);
|
||||
Flow solid_infill_flow = layerm.flow(frSolidInfill);
|
||||
Flow top_solid_infill_flow = layerm.flow(frTopSolidInfill);
|
||||
struct SurfaceFill {
|
||||
SurfaceFill(const SurfaceFillParams& params) : region_id(size_t(-1)), surface(stCount, ExPolygon()), params(params) {}
|
||||
|
||||
Surfaces surfaces;
|
||||
|
||||
// merge adjacent surfaces
|
||||
// in case of bridge surfaces, the ones with defined angle will be attached to the ones
|
||||
// without any angle (shouldn't this logic be moved to process_external_surfaces()?)
|
||||
{
|
||||
Polygons polygons_bridged;
|
||||
polygons_bridged.reserve(layerm.fill_surfaces.surfaces.size());
|
||||
for (Surfaces::iterator it = layerm.fill_surfaces.surfaces.begin(); it != layerm.fill_surfaces.surfaces.end(); ++ it)
|
||||
if (it->bridge_angle >= 0)
|
||||
polygons_append(polygons_bridged, *it);
|
||||
|
||||
// group surfaces by distinct properties (equal surface_type, thickness, thickness_layers, bridge_angle)
|
||||
// group is of type Slic3r::SurfaceCollection
|
||||
//FIXME: Use some smart heuristics to merge similar surfaces to eliminate tiny regions.
|
||||
std::vector<SurfacesPtr> groups;
|
||||
layerm.fill_surfaces.group(&groups);
|
||||
|
||||
// merge compatible groups (we can generate continuous infill for them)
|
||||
{
|
||||
// cache flow widths and patterns used for all solid groups
|
||||
// (we'll use them for comparing compatible groups)
|
||||
std::vector<SurfaceGroupAttrib> group_attrib(groups.size());
|
||||
for (size_t i = 0; i < groups.size(); ++ i) {
|
||||
// we can only merge solid non-bridge surfaces, so discard
|
||||
// non-solid surfaces
|
||||
const Surface &surface = *groups[i].front();
|
||||
if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0)) {
|
||||
group_attrib[i].is_solid = true;
|
||||
group_attrib[i].flow_width = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width;
|
||||
group_attrib[i].pattern = surface.is_external() ?
|
||||
size_t region_id;
|
||||
Surface surface;
|
||||
ExPolygons expolygons;
|
||||
SurfaceFillParams params;
|
||||
};
|
||||
|
||||
std::vector<SurfaceFill> group_fills(const Layer &layer)
|
||||
{
|
||||
std::vector<SurfaceFill> surface_fills;
|
||||
|
||||
// Fill in a map of a region & surface to SurfaceFillParams.
|
||||
std::set<SurfaceFillParams> set_surface_params;
|
||||
std::vector<std::vector<const SurfaceFillParams*>> region_to_surface_params(layer.regions().size(), std::vector<const SurfaceFillParams*>());
|
||||
SurfaceFillParams params;
|
||||
bool has_internal_voids = false;
|
||||
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
|
||||
const LayerRegion &layerm = *layer.regions()[region_id];
|
||||
region_to_surface_params[region_id].assign(layerm.fill_surfaces.size(), nullptr);
|
||||
for (const Surface &surface : layerm.fill_surfaces.surfaces)
|
||||
if (surface.surface_type == stInternalVoid)
|
||||
has_internal_voids = true;
|
||||
else {
|
||||
FlowRole extrusion_role = (surface.surface_type == stTop) ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
|
||||
bool is_bridge = layerm.layer()->id() > 0 && surface.is_bridge();
|
||||
params.extruder = layerm.region()->extruder(extrusion_role);
|
||||
params.pattern = layerm.region()->config().fill_pattern.value;
|
||||
params.density = float(layerm.region()->config().fill_density);
|
||||
|
||||
if (surface.is_solid()) {
|
||||
params.density = 100.f;
|
||||
params.pattern = (surface.is_external() && ! is_bridge) ?
|
||||
(surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) :
|
||||
ipRectilinear;
|
||||
}
|
||||
}
|
||||
// Loop through solid groups, find compatible groups and append them to this one.
|
||||
for (size_t i = 0; i < groups.size(); ++ i) {
|
||||
if (! group_attrib[i].is_solid)
|
||||
continue;
|
||||
for (size_t j = i + 1; j < groups.size();) {
|
||||
if (group_attrib[i] == group_attrib[j]) {
|
||||
// groups are compatible, merge them
|
||||
groups[i].insert(groups[i].end(), groups[j].begin(), groups[j].end());
|
||||
groups.erase(groups.begin() + j);
|
||||
group_attrib.erase(group_attrib.begin() + j);
|
||||
} else
|
||||
++ j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Give priority to bridges. Process the bridges in the first round, the rest of the surfaces in the 2nd round.
|
||||
for (size_t round = 0; round < 2; ++ round) {
|
||||
for (std::vector<SurfacesPtr>::iterator it_group = groups.begin(); it_group != groups.end(); ++ it_group) {
|
||||
const SurfacesPtr &group = *it_group;
|
||||
bool is_bridge = group.front()->bridge_angle >= 0;
|
||||
if (is_bridge != (round == 0))
|
||||
continue;
|
||||
// Make a union of polygons defining the infiill regions of a group, use a safety offset.
|
||||
Polygons union_p = union_(to_polygons(*it_group), true);
|
||||
// Subtract surfaces having a defined bridge_angle from any other, use a safety offset.
|
||||
if (! polygons_bridged.empty() && ! is_bridge)
|
||||
union_p = diff(union_p, polygons_bridged, true);
|
||||
// subtract any other surface already processed
|
||||
//FIXME Vojtech: Because the bridge surfaces came first, they are subtracted twice!
|
||||
// Using group.front() as a template.
|
||||
surfaces_append(surfaces, diff_ex(union_p, to_polygons(surfaces), true), *group.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ipRectilinear;
|
||||
} else if (params.density <= 0)
|
||||
continue;
|
||||
|
||||
params.extrusion_role =
|
||||
is_bridge ?
|
||||
erBridgeInfill :
|
||||
(surface.is_solid() ?
|
||||
((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) :
|
||||
erInternalInfill);
|
||||
params.bridge_angle = float(surface.bridge_angle);
|
||||
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
params.flow = layerm.region()->flow(
|
||||
extrusion_role,
|
||||
(surface.thickness == -1) ? layerm.layer()->height : surface.thickness, // extrusion height
|
||||
is_bridge || Fill::use_bridge_flow(params.pattern), // bridge flow?
|
||||
layerm.layer()->id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layerm.layer()->object()
|
||||
);
|
||||
|
||||
// Calculate flow spacing for infill pattern generation.
|
||||
if (! surface.is_solid() && ! is_bridge) {
|
||||
// it's internal infill, so we can calculate a generic flow spacing
|
||||
// for all layers, for avoiding the ugly effect of
|
||||
// misaligned infill on first layer because of different extrusion width and
|
||||
// layer height
|
||||
params.spacing = layerm.region()->flow(
|
||||
frInfill,
|
||||
layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers?
|
||||
false, // no bridge
|
||||
false, // no first layer
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
).spacing();
|
||||
} else
|
||||
params.spacing = params.flow.spacing();
|
||||
|
||||
auto it_params = set_surface_params.find(params);
|
||||
if (it_params == set_surface_params.end())
|
||||
it_params = set_surface_params.insert(it_params, params);
|
||||
region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()] = &(*it_params);
|
||||
}
|
||||
}
|
||||
|
||||
surface_fills.reserve(set_surface_params.size());
|
||||
for (const SurfaceFillParams ¶ms : set_surface_params) {
|
||||
const_cast<SurfaceFillParams&>(params).idx = surface_fills.size();
|
||||
surface_fills.emplace_back(params);
|
||||
}
|
||||
|
||||
for (size_t region_id = 0; region_id < layer.regions().size(); ++ region_id) {
|
||||
const LayerRegion &layerm = *layer.regions()[region_id];
|
||||
for (const Surface &surface : layerm.fill_surfaces.surfaces)
|
||||
if (surface.surface_type != stInternalVoid) {
|
||||
const SurfaceFillParams *params = region_to_surface_params[region_id][&surface - &layerm.fill_surfaces.surfaces.front()];
|
||||
if (params != nullptr) {
|
||||
SurfaceFill &fill = surface_fills[params->idx];
|
||||
if (fill.region_id == size_t(-1)) {
|
||||
fill.region_id = region_id;
|
||||
fill.surface = surface;
|
||||
fill.expolygons.emplace_back(std::move(fill.surface.expolygon));
|
||||
} else
|
||||
fill.expolygons.emplace_back(surface.expolygon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Polygons all_polygons;
|
||||
for (SurfaceFill &fill : surface_fills)
|
||||
if (! fill.expolygons.empty() && (fill.expolygons.size() > 1 || ! all_polygons.empty())) {
|
||||
Polygons polys = to_polygons(std::move(fill.expolygons));
|
||||
// Make a union of polygons, use a safety offset, subtract the preceding polygons.
|
||||
// Bridges are processed first (see SurfaceFill::operator<())
|
||||
fill.expolygons = all_polygons.empty() ? union_ex(polys, true) : diff_ex(polys, all_polygons, true);
|
||||
append(all_polygons, std::move(polys));
|
||||
}
|
||||
}
|
||||
|
||||
// we need to detect any narrow surfaces that might collapse
|
||||
// when adding spacing below
|
||||
// such narrow surfaces are often generated in sloping walls
|
||||
@ -119,155 +216,170 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
|
||||
// we are going to grow such regions by overlapping them with the void (if any)
|
||||
// TODO: detect and investigate whether there could be narrow regions without
|
||||
// any void neighbors
|
||||
{
|
||||
coord_t distance_between_surfaces = std::max(
|
||||
std::max(infill_flow.scaled_spacing(), solid_infill_flow.scaled_spacing()),
|
||||
top_solid_infill_flow.scaled_spacing());
|
||||
Polygons surfaces_polygons = to_polygons(surfaces);
|
||||
Polygons collapsed = diff(
|
||||
surfaces_polygons,
|
||||
offset2(surfaces_polygons, (float)-distance_between_surfaces/2, (float)+distance_between_surfaces/2),
|
||||
true);
|
||||
Polygons to_subtract;
|
||||
to_subtract.reserve(collapsed.size() + number_polygons(surfaces));
|
||||
for (Surfaces::const_iterator it_surface = surfaces.begin(); it_surface != surfaces.end(); ++ it_surface)
|
||||
if (it_surface->surface_type == stInternalVoid)
|
||||
polygons_append(to_subtract, *it_surface);
|
||||
polygons_append(to_subtract, collapsed);
|
||||
surfaces_append(
|
||||
surfaces,
|
||||
intersection_ex(
|
||||
offset(collapsed, (float)distance_between_surfaces),
|
||||
to_subtract,
|
||||
true),
|
||||
stInternalSolid);
|
||||
if (has_internal_voids) {
|
||||
// Internal voids are generated only if "infill_only_where_needed" or "infill_every_layers" are active.
|
||||
coord_t distance_between_surfaces = 0;
|
||||
Polygons surfaces_polygons;
|
||||
Polygons voids;
|
||||
int region_internal_infill = -1;
|
||||
int region_solid_infill = -1;
|
||||
int region_some_infill = -1;
|
||||
for (SurfaceFill &surface_fill : surface_fills)
|
||||
if (! surface_fill.expolygons.empty()) {
|
||||
distance_between_surfaces = std::max(distance_between_surfaces, surface_fill.params.flow.scaled_spacing());
|
||||
append((surface_fill.surface.surface_type == stInternalVoid) ? voids : surfaces_polygons, to_polygons(surface_fill.expolygons));
|
||||
if (surface_fill.surface.surface_type == stInternalSolid)
|
||||
region_internal_infill = (int)surface_fill.region_id;
|
||||
if (surface_fill.surface.is_solid())
|
||||
region_solid_infill = (int)surface_fill.region_id;
|
||||
if (surface_fill.surface.surface_type != stInternalVoid)
|
||||
region_some_infill = (int)surface_fill.region_id;
|
||||
}
|
||||
if (! voids.empty() && ! surfaces_polygons.empty()) {
|
||||
// First clip voids by the printing polygons, as the voids were ignored by the loop above during mutual clipping.
|
||||
voids = diff(voids, surfaces_polygons);
|
||||
// Corners of infill regions, which would not be filled with an extrusion path with a radius of distance_between_surfaces/2
|
||||
Polygons collapsed = diff(
|
||||
surfaces_polygons,
|
||||
offset2(surfaces_polygons, (float)-distance_between_surfaces/2, (float)+distance_between_surfaces/2),
|
||||
true);
|
||||
//FIXME why the voids are added to collapsed here? First it is expensive, second the result may lead to some unwanted regions being
|
||||
// added if two offsetted void regions merge.
|
||||
// polygons_append(voids, collapsed);
|
||||
ExPolygons extensions = intersection_ex(offset(collapsed, (float)distance_between_surfaces), voids, true);
|
||||
// Now find an internal infill SurfaceFill to add these extrusions to.
|
||||
SurfaceFill *internal_solid_fill = nullptr;
|
||||
unsigned int region_id = 0;
|
||||
if (region_internal_infill != -1)
|
||||
region_id = region_internal_infill;
|
||||
else if (region_solid_infill != -1)
|
||||
region_id = region_solid_infill;
|
||||
else if (region_some_infill != -1)
|
||||
region_id = region_some_infill;
|
||||
const LayerRegion& layerm = *layer.regions()[region_id];
|
||||
for (SurfaceFill &surface_fill : surface_fills)
|
||||
if (surface_fill.surface.surface_type == stInternalSolid && std::abs(layerm.layer()->height - surface_fill.params.flow.height) < EPSILON) {
|
||||
internal_solid_fill = &surface_fill;
|
||||
break;
|
||||
}
|
||||
if (internal_solid_fill == nullptr) {
|
||||
// Produce another solid fill.
|
||||
params.extruder = layerm.region()->extruder(frSolidInfill);
|
||||
params.pattern = ipRectilinear;
|
||||
params.density = 100.f;
|
||||
params.extrusion_role = erInternalInfill;
|
||||
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
params.flow = layerm.region()->flow(
|
||||
frSolidInfill,
|
||||
layerm.layer()->height, // extrusion height
|
||||
false, // bridge flow?
|
||||
layerm.layer()->id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layer.object()
|
||||
);
|
||||
params.spacing = params.flow.spacing();
|
||||
surface_fills.emplace_back(params);
|
||||
surface_fills.back().surface.surface_type = stInternalSolid;
|
||||
surface_fills.back().surface.thickness = layer.height;
|
||||
surface_fills.back().expolygons = std::move(extensions);
|
||||
} else {
|
||||
append(extensions, std::move(internal_solid_fill->expolygons));
|
||||
internal_solid_fill->expolygons = union_ex(extensions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0) {
|
||||
// require "Slic3r/SVG.pm";
|
||||
// Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg",
|
||||
// expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ],
|
||||
// red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ],
|
||||
// );
|
||||
}
|
||||
return surface_fills;
|
||||
}
|
||||
|
||||
// friend to Layer
|
||||
void Layer::make_fills()
|
||||
{
|
||||
for (LayerRegion *layerm : m_regions)
|
||||
layerm->fills.clear();
|
||||
|
||||
std::vector<SurfaceFill> surface_fills = group_fills(*this);
|
||||
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
|
||||
|
||||
for (SurfaceFill &surface_fill : surface_fills) {
|
||||
// Create the filler object.
|
||||
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
|
||||
f->set_bounding_box(bbox);
|
||||
f->layer_id = this->id();
|
||||
f->z = this->print_z;
|
||||
f->angle = surface_fill.params.angle;
|
||||
f->spacing = surface_fill.params.spacing;
|
||||
|
||||
for (const Surface &surface : surfaces) {
|
||||
if (surface.surface_type == stInternalVoid)
|
||||
continue;
|
||||
InfillPattern fill_pattern = layerm.region()->config().fill_pattern.value;
|
||||
double density = fill_density;
|
||||
FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill :
|
||||
(surface.is_solid() ? frSolidInfill : frInfill);
|
||||
bool is_bridge = layerm.layer()->id() > 0 && surface.is_bridge();
|
||||
|
||||
if (surface.is_solid()) {
|
||||
density = 100.;
|
||||
fill_pattern = (surface.is_external() && ! is_bridge) ?
|
||||
(surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) :
|
||||
ipRectilinear;
|
||||
} else if (density <= 0)
|
||||
continue;
|
||||
|
||||
// get filler object
|
||||
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(fill_pattern));
|
||||
f->set_bounding_box(layerm.layer()->object()->bounding_box());
|
||||
|
||||
// calculate the actual flow we'll be using for this infill
|
||||
coordf_t h = (surface.thickness == -1) ? layerm.layer()->height : surface.thickness;
|
||||
Flow flow = layerm.region()->flow(
|
||||
role,
|
||||
h,
|
||||
is_bridge || f->use_bridge_flow(), // bridge flow?
|
||||
layerm.layer()->id() == 0, // first layer?
|
||||
-1, // auto width
|
||||
*layerm.layer()->object()
|
||||
);
|
||||
|
||||
// calculate flow spacing for infill pattern generation
|
||||
bool using_internal_flow = false;
|
||||
if (! surface.is_solid() && ! is_bridge) {
|
||||
// it's internal infill, so we can calculate a generic flow spacing
|
||||
// for all layers, for avoiding the ugly effect of
|
||||
// misaligned infill on first layer because of different extrusion width and
|
||||
// layer height
|
||||
Flow internal_flow = layerm.region()->flow(
|
||||
frInfill,
|
||||
layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers?
|
||||
false, // no bridge
|
||||
false, // no first layer
|
||||
-1, // auto width
|
||||
*layerm.layer()->object()
|
||||
);
|
||||
f->spacing = internal_flow.spacing();
|
||||
using_internal_flow = true;
|
||||
} else {
|
||||
f->spacing = flow.spacing();
|
||||
}
|
||||
|
||||
bool using_internal_flow = ! surface_fill.surface.is_solid() && ! surface_fill.params.flow.bridge;
|
||||
double link_max_length = 0.;
|
||||
if (! is_bridge) {
|
||||
if (! surface_fill.params.flow.bridge) {
|
||||
#if 0
|
||||
link_max_length = layerm.region()->config().get_abs_value(surface.is_external() ? "external_fill_link_max_length" : "fill_link_max_length", flow.spacing());
|
||||
// printf("flow spacing: %f, is_external: %d, link_max_length: %lf\n", flow.spacing(), int(surface.is_external()), link_max_length);
|
||||
#else
|
||||
if (density > 80.) // 80%
|
||||
if (surface_fill.params.density > 80.) // 80%
|
||||
link_max_length = 3. * f->spacing;
|
||||
#endif
|
||||
}
|
||||
|
||||
f->layer_id = layerm.layer()->id();
|
||||
f->z = layerm.layer()->print_z;
|
||||
f->angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||
// Maximum length of the perimeter segment linking two infill lines.
|
||||
f->link_max_length = (coord_t)scale_(link_max_length);
|
||||
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
|
||||
f->loop_clipping = coord_t(scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||
// f->layer_height = h;
|
||||
f->loop_clipping = coord_t(scale_(surface_fill.params.flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
|
||||
|
||||
// apply half spacing using this flow's own spacing and generate infill
|
||||
FillParams params;
|
||||
params.density = float(0.01 * density);
|
||||
// params.dont_adjust = true;
|
||||
params.dont_adjust = false;
|
||||
Polylines polylines = f->fill_surface(&surface, params);
|
||||
if (polylines.empty())
|
||||
continue;
|
||||
params.density = float(0.01 * surface_fill.params.density);
|
||||
params.dont_adjust = surface_fill.params.dont_adjust; // false
|
||||
|
||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||
// pattern generator)
|
||||
if (using_internal_flow) {
|
||||
// if we used the internal flow we're not doing a solid infill
|
||||
// so we can safely ignore the slight variation that might have
|
||||
// been applied to $f->flow_spacing
|
||||
} else {
|
||||
flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, (float)h, is_bridge || f->use_bridge_flow());
|
||||
}
|
||||
|
||||
// Save into layer.
|
||||
auto *eec = new ExtrusionEntityCollection();
|
||||
out.entities.push_back(eec);
|
||||
// Only concentric fills are not sorted.
|
||||
eec->no_sort = f->no_sort();
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, std::move(polylines),
|
||||
is_bridge ?
|
||||
erBridgeInfill :
|
||||
(surface.is_solid() ?
|
||||
((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) :
|
||||
erInternalInfill),
|
||||
flow.mm3_per_mm(), flow.width, flow.height);
|
||||
for (ExPolygon &expoly : surface_fill.expolygons) {
|
||||
surface_fill.surface.expolygon = std::move(expoly);
|
||||
Polylines polylines = f->fill_surface(&surface_fill.surface, params);
|
||||
if (! polylines.empty()) {
|
||||
// calculate actual flow from spacing (which might have been adjusted by the infill
|
||||
// pattern generator)
|
||||
double flow_mm3_per_mm = surface_fill.params.flow.mm3_per_mm();
|
||||
double flow_width = surface_fill.params.flow.width;
|
||||
if (using_internal_flow) {
|
||||
// if we used the internal flow we're not doing a solid infill
|
||||
// so we can safely ignore the slight variation that might have
|
||||
// been applied to f->spacing
|
||||
} else {
|
||||
Flow new_flow = Flow::new_from_spacing(float(f->spacing), surface_fill.params.flow.nozzle_diameter, surface_fill.params.flow.height, surface_fill.params.flow.bridge);
|
||||
flow_mm3_per_mm = new_flow.mm3_per_mm();
|
||||
flow_width = new_flow.width;
|
||||
}
|
||||
// Save into layer.
|
||||
auto *eec = new ExtrusionEntityCollection();
|
||||
m_regions[surface_fill.region_id]->fills.entities.push_back(eec);
|
||||
// Only concentric fills are not sorted.
|
||||
eec->no_sort = f->no_sort();
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, std::move(polylines),
|
||||
surface_fill.params.extrusion_role,
|
||||
flow_mm3_per_mm, float(flow_width), surface_fill.params.flow.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add thin fill regions
|
||||
// thin_fills are of C++ Slic3r::ExtrusionEntityCollection, perl type Slic3r::ExtrusionPath::Collection
|
||||
// Unpacks the collection, creates multiple collections per path.
|
||||
// The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection.
|
||||
// Why the paths are unpacked?
|
||||
for (const ExtrusionEntity *thin_fill : layerm.thin_fills.entities) {
|
||||
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
|
||||
out.entities.push_back(&collection);
|
||||
collection.entities.push_back(thin_fill->clone());
|
||||
}
|
||||
for (LayerRegion *layerm : m_regions)
|
||||
for (const ExtrusionEntity *thin_fill : layerm->thin_fills.entities) {
|
||||
ExtrusionEntityCollection &collection = *(new ExtrusionEntityCollection());
|
||||
layerm->fills.entities.push_back(&collection);
|
||||
collection.entities.push_back(thin_fill->clone());
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
for (LayerRegion *layerm : m_regions)
|
||||
for (size_t i = 0; i < layerm->fills.entities.size(); ++ i)
|
||||
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i]) != nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -34,7 +34,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
||||
case ipArchimedeanChords: return new FillArchimedeanChords();
|
||||
case ipHilbertCurve: return new FillHilbertCurve();
|
||||
case ipOctagramSpiral: return new FillOctagramSpiral();
|
||||
default: throw std::invalid_argument("unknown type");;
|
||||
default: throw std::invalid_argument("unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,24 @@ Fill* Fill::new_from_type(const std::string &type)
|
||||
return (it == enum_keys_map.end()) ? nullptr : new_from_type(InfillPattern(it->second));
|
||||
}
|
||||
|
||||
// Force initialization of the Fill::use_bridge_flow() internal static map in a thread safe fashion even on compilers
|
||||
// not supporting thread safe non-static data member initializers.
|
||||
static bool use_bridge_flow_initializer = Fill::use_bridge_flow(ipGrid);
|
||||
|
||||
bool Fill::use_bridge_flow(const InfillPattern type)
|
||||
{
|
||||
static std::vector<unsigned char> cached;
|
||||
if (cached.empty()) {
|
||||
cached.assign(size_t(ipCount), 0);
|
||||
for (size_t i = 0; i < cached.size(); ++ i) {
|
||||
auto *fill = Fill::new_from_type((InfillPattern)i);
|
||||
cached[i] = fill->use_bridge_flow();
|
||||
delete fill;
|
||||
}
|
||||
}
|
||||
return cached[type] != 0;
|
||||
}
|
||||
|
||||
Polylines Fill::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
{
|
||||
// Perform offset.
|
||||
|
@ -70,6 +70,7 @@ public:
|
||||
|
||||
static Fill* new_from_type(const InfillPattern type);
|
||||
static Fill* new_from_type(const std::string &type);
|
||||
static bool use_bridge_flow(const InfillPattern type);
|
||||
|
||||
void set_bounding_box(const Slic3r::BoundingBox &bbox) { bounding_box = bbox; }
|
||||
|
||||
|
@ -56,6 +56,8 @@ public:
|
||||
// Enable some perimeter squish (see INSET_OVERLAP_TOLERANCE).
|
||||
// Here an overlap of 0.2x external perimeter spacing is allowed for by the elephant foot compensation.
|
||||
coord_t scaled_elephant_foot_spacing() const { return coord_t(0.5f * float(this->scaled_width() + 0.6f * this->scaled_spacing())); }
|
||||
|
||||
bool operator==(const Flow &rhs) const { return this->width == rhs.width && this->height == rhs.height && this->nozzle_diameter == rhs.nozzle_diameter && this->bridge == rhs.bridge; }
|
||||
|
||||
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio);
|
||||
// Create a flow from the spacing of extrusion lines.
|
||||
|
@ -662,15 +662,19 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
if (print->config().remaining_times.value) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for normal mode" << log_memory_info();
|
||||
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
GCodeTimeEstimator::PostProcessData normal_data = m_normal_time_estimator.get_post_process_data();
|
||||
GCodeTimeEstimator::PostProcessData silent_data = m_silent_time_estimator.get_post_process_data();
|
||||
|
||||
bool remaining_times_enabled = print->config().remaining_times.value;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Time estimator post processing" << log_memory_info();
|
||||
GCodeTimeEstimator::post_process(path_tmp, 60.0f, remaining_times_enabled ? &normal_data : nullptr, (remaining_times_enabled && m_silent_time_estimator_enabled) ? &silent_data : nullptr);
|
||||
|
||||
if (remaining_times_enabled)
|
||||
{
|
||||
m_normal_time_estimator.reset();
|
||||
if (m_silent_time_estimator_enabled) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Processing remaining times for silent mode" << log_memory_info();
|
||||
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// starts analyzer calculations
|
||||
@ -1738,13 +1742,9 @@ void GCode::process_layer(
|
||||
|
||||
// This extrusion is part of certain Region, which tells us which extruder should be used for it:
|
||||
int correct_extruder_id = Print::get_extruder(*fill, region);
|
||||
//FIXME what is this?
|
||||
entity_type=="infills" ?
|
||||
std::max<int>(0, (is_solid_infill(fill->entities.front()->role()) ? region.config().solid_infill_extruder : region.config().infill_extruder) - 1) :
|
||||
std::max<int>(region.config().perimeter_extruder.value - 1, 0);
|
||||
|
||||
// Let's recover vector of extruder overrides:
|
||||
const ExtruderPerCopy* entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, (int)layer_to_print.object()->copies().size());
|
||||
const ExtruderPerCopy* entity_overrides = const_cast<LayerTools&>(layer_tools).wiping_extrusions().get_extruder_overrides(fill, correct_extruder_id, layer_to_print.object()->copies().size());
|
||||
|
||||
// Now we must add this extrusion into the by_extruder map, once for each extruder that will print it:
|
||||
for (unsigned int extruder : layer_tools.extruders)
|
||||
@ -3027,7 +3027,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
|
||||
|
||||
// This function takes the eec and appends its entities to either perimeters or infills of this Region (depending on the first parameter)
|
||||
// It also saves pointer to ExtruderPerCopy struct (for each entity), that holds information about which extruders should be used for which copy.
|
||||
void GCode::ObjectByExtruder::Island::Region::append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copies_extruder, unsigned int object_copies_num)
|
||||
void GCode::ObjectByExtruder::Island::Region::append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copies_extruder, size_t object_copies_num)
|
||||
{
|
||||
// We are going to manipulate either perimeters or infills, exactly in the same way. Let's create pointers to the proper structure to not repeat ourselves:
|
||||
ExtrusionEntityCollection* perimeters_or_infills = &infills;
|
||||
|
@ -246,7 +246,7 @@ protected:
|
||||
std::vector<const ExtruderPerCopy*> perimeters_overrides;
|
||||
|
||||
// Appends perimeter/infill entities and writes don't indices of those that are not to be extruder as part of perimeter/infill wiping
|
||||
void append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copy_extruders, unsigned int object_copies_num);
|
||||
void append(const std::string& type, const ExtrusionEntityCollection* eec, const ExtruderPerCopy* copy_extruders, size_t object_copies_num);
|
||||
};
|
||||
|
||||
std::vector<Region> by_region; // all extrusions for this island, grouped by regions
|
||||
|
@ -458,14 +458,14 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& object = object_list[i];
|
||||
const PrintObject* object = object_list[i];
|
||||
|
||||
// Finds this layer:
|
||||
auto this_layer_it = std::find_if(object->layers().begin(), object->layers().end(), [<](const Layer* lay) { return std::abs(lt.print_z - lay->print_z)<EPSILON; });
|
||||
if (this_layer_it == object->layers().end())
|
||||
continue;
|
||||
const Layer* this_layer = *this_layer_it;
|
||||
unsigned int num_of_copies = object->copies().size();
|
||||
size_t num_of_copies = object->copies().size();
|
||||
|
||||
for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
|
||||
|
||||
@ -494,7 +494,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
|
||||
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) { // this infill will be used to wipe this extruder
|
||||
set_extruder_override(fill, copy, new_extruder, num_of_copies);
|
||||
volume_to_wipe -= fill->total_volume();
|
||||
volume_to_wipe -= float(fill->total_volume());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -512,7 +512,7 @@ float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int
|
||||
|
||||
if ((!is_entity_overridden(fill, copy) && fill->total_volume() > min_infill_volume)) {
|
||||
set_extruder_override(fill, copy, new_extruder, num_of_copies);
|
||||
volume_to_wipe -= fill->total_volume();
|
||||
volume_to_wipe -= float(fill->total_volume());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -540,9 +540,9 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
if (this_layer_it == object->layers().end())
|
||||
continue;
|
||||
const Layer* this_layer = *this_layer_it;
|
||||
unsigned int num_of_copies = object->copies().size();
|
||||
size_t num_of_copies = object->copies().size();
|
||||
|
||||
for (unsigned int copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
|
||||
for (size_t copy = 0; copy < num_of_copies; ++copy) { // iterate through copies first, so that we mark neighbouring infills to minimize travel moves
|
||||
for (size_t region_id = 0; region_id < object->region_volumes.size(); ++ region_id) {
|
||||
const auto& region = *object->print()->regions()[region_id];
|
||||
|
||||
@ -598,7 +598,7 @@ void WipingExtrusions::ensure_perimeters_infills_order(const Print& print)
|
||||
// so -1 was used as "print as usual".
|
||||
// The resulting vector has to keep track of which extrusions are the ones that were overridden and which were not. In the extruder is used as overridden,
|
||||
// its number is saved as it is (zero-based index). Usual extrusions are saved as -number-1 (unfortunately there is no negative zero).
|
||||
const std::vector<int>* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies)
|
||||
const std::vector<int>* WipingExtrusions::get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies)
|
||||
{
|
||||
auto entity_map_it = entity_map.find(entity);
|
||||
if (entity_map_it == entity_map.end())
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
}
|
||||
|
||||
// This is called from GCode::process_layer - see implementation for further comments:
|
||||
const std::vector<int>* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, int num_of_copies);
|
||||
const std::vector<int>* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies);
|
||||
|
||||
// This function goes through all infill entities, decides which ones will be used for wiping and
|
||||
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
|
||||
@ -44,7 +44,7 @@ private:
|
||||
void set_extruder_override(const ExtrusionEntity* entity, unsigned int copy_id, int extruder, unsigned int num_of_copies);
|
||||
|
||||
// Returns true in case that entity is not printed with its usual extruder for a given copy:
|
||||
bool is_entity_overridden(const ExtrusionEntity* entity, int copy_id) const {
|
||||
bool is_entity_overridden(const ExtrusionEntity* entity, size_t copy_id) const {
|
||||
return (entity_map.find(entity) == entity_map.end() ? false : entity_map.at(entity).at(copy_id) != -1);
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ public:
|
||||
|
||||
float dx = x - m_current_pos.x();
|
||||
float dy = y - m_current_pos.y();
|
||||
double len = sqrt(dx*dx+dy*dy);
|
||||
float len = std::sqrt(dx*dx+dy*dy);
|
||||
if (record_length)
|
||||
m_used_filament_length += e;
|
||||
|
||||
@ -159,11 +159,11 @@ public:
|
||||
Vec2f rotated_current_pos(rotate(m_current_pos + Vec2f(0.f,m_y_shift), m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle)); // this is where we are
|
||||
Vec2f rot(rotate(Vec2f(x,y+m_y_shift), m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle)); // this is where we want to go
|
||||
|
||||
if (! m_preview_suppressed && e > 0.f && len > 0.) {
|
||||
if (! m_preview_suppressed && e > 0.f && len > 0.f) {
|
||||
change_analyzer_mm3_per_mm(len, e);
|
||||
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
|
||||
// This is left zero if it is a travel move.
|
||||
float width = float(double(e) * m_filpar[0].filament_area / (len * m_layer_height));
|
||||
float width = e * m_filpar[0].filament_area / (len * m_layer_height);
|
||||
// Correct for the roundings of a squished extrusion.
|
||||
width += m_layer_height * float(1. - M_PI / 4.);
|
||||
if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos)
|
||||
@ -172,10 +172,10 @@ public:
|
||||
}
|
||||
|
||||
m_gcode += "G1";
|
||||
if (std::abs(rot.x() - rotated_current_pos.x()) > EPSILON)
|
||||
if (std::abs(rot.x() - rotated_current_pos.x()) > (float)EPSILON)
|
||||
m_gcode += set_format_X(rot.x());
|
||||
|
||||
if (std::abs(rot.y() - rotated_current_pos.y()) > EPSILON)
|
||||
if (std::abs(rot.y() - rotated_current_pos.y()) > (float)EPSILON)
|
||||
m_gcode += set_format_Y(rot.y());
|
||||
|
||||
|
||||
@ -184,7 +184,7 @@ public:
|
||||
|
||||
if (f != 0.f && f != m_current_feedrate) {
|
||||
if (limit_volumetric_flow) {
|
||||
float e_speed = e / (((len == 0) ? std::abs(e) : len) / f * 60.f);
|
||||
float e_speed = e / (((len == 0.f) ? std::abs(e) : len) / f * 60.f);
|
||||
f /= std::max(1.f, e_speed / m_filpar[m_current_tool].max_e_speed);
|
||||
}
|
||||
m_gcode += set_format_F(f);
|
||||
@ -194,7 +194,7 @@ public:
|
||||
m_current_pos.y() = y;
|
||||
|
||||
// Update the elapsed time with a rough estimate.
|
||||
m_elapsed_time += ((len == 0) ? std::abs(e) : len) / m_current_feedrate * 60.f;
|
||||
m_elapsed_time += ((len == 0.f) ? std::abs(e) : len) / m_current_feedrate * 60.f;
|
||||
m_gcode += "\n";
|
||||
return *this;
|
||||
}
|
||||
@ -214,7 +214,7 @@ public:
|
||||
{
|
||||
float dx = x - m_current_pos.x();
|
||||
float dy = y - m_current_pos.y();
|
||||
return extrude_explicit(x, y, sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true);
|
||||
return extrude_explicit(x, y, std::sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true);
|
||||
}
|
||||
|
||||
WipeTowerWriter& extrude(const Vec2f &dest, const float f = 0.f)
|
||||
@ -311,7 +311,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
WipeTowerWriter& set_tool(int tool)
|
||||
WipeTowerWriter& set_tool(unsigned tool)
|
||||
{
|
||||
m_current_tool = tool;
|
||||
return *this;
|
||||
@ -320,57 +320,52 @@ public:
|
||||
// Set extruder temperature, don't wait by default.
|
||||
WipeTowerWriter& set_extruder_temp(int temperature, bool wait = false)
|
||||
{
|
||||
char buf[128];
|
||||
sprintf(buf, "M%d S%d\n", wait ? 109 : 104, temperature);
|
||||
m_gcode += buf;
|
||||
m_gcode += "M" + std::to_string(wait ? 109 : 104) + " S" + std::to_string(temperature) + "\n";
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
// Wait for a period of time (seconds).
|
||||
WipeTowerWriter& wait(float time)
|
||||
{
|
||||
if (time==0)
|
||||
if (time==0.f)
|
||||
return *this;
|
||||
char buf[128];
|
||||
sprintf(buf, "G4 S%.3f\n", time);
|
||||
m_gcode += buf;
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
// Set speed factor override percentage.
|
||||
WipeTowerWriter& speed_override(int speed)
|
||||
{
|
||||
char buf[128];
|
||||
sprintf(buf, "M220 S%d\n", speed);
|
||||
m_gcode += buf;
|
||||
m_gcode += "M220 S" + std::to_string(speed) + "\n";
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
// Let the firmware back up the active speed override value.
|
||||
WipeTowerWriter& speed_override_backup()
|
||||
{
|
||||
m_gcode += "M220 B\n";
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
// Let the firmware restore the active speed override value.
|
||||
WipeTowerWriter& speed_override_restore()
|
||||
{
|
||||
m_gcode += "M220 R\n";
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
// Set digital trimpot motor
|
||||
WipeTowerWriter& set_extruder_trimpot(int current)
|
||||
{
|
||||
char buf[128];
|
||||
if (m_gcode_flavor == gcfRepRap)
|
||||
sprintf(buf, "M906 E%d\n", current);
|
||||
m_gcode += "M906 E";
|
||||
else
|
||||
sprintf(buf, "M907 E%d\n", current);
|
||||
m_gcode += buf;
|
||||
m_gcode += "M907 E";
|
||||
m_gcode += std::to_string(current) + "\n";
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
WipeTowerWriter& flush_planner_queue()
|
||||
{
|
||||
@ -386,28 +381,20 @@ public:
|
||||
}
|
||||
|
||||
WipeTowerWriter& comment_with_value(const char *comment, int value)
|
||||
{
|
||||
char strvalue[64];
|
||||
sprintf(strvalue, "%d", value);
|
||||
m_gcode += std::string(";") + comment + strvalue + "\n";
|
||||
{
|
||||
m_gcode += std::string(";") + comment + std::to_string(value) + "\n";
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
WipeTowerWriter& set_fan(unsigned int speed)
|
||||
WipeTowerWriter& set_fan(unsigned speed)
|
||||
{
|
||||
if (speed == m_last_fan_speed)
|
||||
return *this;
|
||||
|
||||
if (speed == 0)
|
||||
m_gcode += "M107\n";
|
||||
else
|
||||
{
|
||||
m_gcode += "M106 S";
|
||||
char buf[128];
|
||||
sprintf(buf,"%u\n",(unsigned int)(255.0 * speed / 100.0));
|
||||
m_gcode += buf;
|
||||
}
|
||||
else
|
||||
m_gcode += "M106 S" + std::to_string(unsigned(255.0 * speed / 100.0)) + "\n";
|
||||
m_last_fan_speed = speed;
|
||||
return *this;
|
||||
}
|
||||
@ -430,7 +417,7 @@ private:
|
||||
float m_y_shift = 0.f;
|
||||
float m_wipe_tower_width = 0.f;
|
||||
float m_wipe_tower_depth = 0.f;
|
||||
float m_last_fan_speed = 0.f;
|
||||
unsigned m_last_fan_speed = 0.f;
|
||||
int current_temp = -1;
|
||||
const float m_default_analyzer_line_width;
|
||||
float m_used_filament_length = 0.f;
|
||||
@ -479,12 +466,12 @@ private:
|
||||
WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool) :
|
||||
m_semm(config.single_extruder_multi_material.value),
|
||||
m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y),
|
||||
m_wipe_tower_width(config.wipe_tower_width),
|
||||
m_wipe_tower_rotation_angle(config.wipe_tower_rotation_angle),
|
||||
m_wipe_tower_width(float(config.wipe_tower_width)),
|
||||
m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)),
|
||||
m_y_shift(0.f),
|
||||
m_z_pos(0.f),
|
||||
m_is_first_layer(false),
|
||||
m_bridging(config.wipe_tower_bridging),
|
||||
m_bridging(float(config.wipe_tower_bridging)),
|
||||
m_gcode_flavor(config.gcode_flavor),
|
||||
m_current_tool(initial_tool),
|
||||
wipe_volumes(wiping_matrix)
|
||||
@ -492,16 +479,16 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
if (m_semm) {
|
||||
m_cooling_tube_retraction = config.cooling_tube_retraction;
|
||||
m_cooling_tube_length = config.cooling_tube_length;
|
||||
m_parking_pos_retraction = config.parking_pos_retraction;
|
||||
m_extra_loading_move = config.extra_loading_move;
|
||||
m_set_extruder_trimpot = config.high_current_on_filament_swap;
|
||||
m_cooling_tube_retraction = float(config.cooling_tube_retraction);
|
||||
m_cooling_tube_length = float(config.cooling_tube_length);
|
||||
m_parking_pos_retraction = float(config.parking_pos_retraction);
|
||||
m_extra_loading_move = float(config.extra_loading_move);
|
||||
m_set_extruder_trimpot = config.high_current_on_filament_swap;
|
||||
}
|
||||
// Calculate where the priming lines should be - very naive test not detecting parallelograms or custom shapes
|
||||
const std::vector<Vec2d>& bed_points = config.bed_shape.values;
|
||||
m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed);
|
||||
m_bed_width = BoundingBoxf(bed_points).size().x();
|
||||
m_bed_width = float(BoundingBoxf(bed_points).size().x());
|
||||
}
|
||||
|
||||
|
||||
@ -518,21 +505,21 @@ void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
|
||||
// If this is a single extruder MM printer, we will use all the SE-specific config values.
|
||||
// Otherwise, the defaults will be used to turn off the SE stuff.
|
||||
if (m_semm) {
|
||||
m_filpar[idx].loading_speed = config.filament_loading_speed.get_at(idx);
|
||||
m_filpar[idx].loading_speed_start = config.filament_loading_speed_start.get_at(idx);
|
||||
m_filpar[idx].unloading_speed = config.filament_unloading_speed.get_at(idx);
|
||||
m_filpar[idx].unloading_speed_start = config.filament_unloading_speed_start.get_at(idx);
|
||||
m_filpar[idx].delay = config.filament_toolchange_delay.get_at(idx);
|
||||
m_filpar[idx].loading_speed = float(config.filament_loading_speed.get_at(idx));
|
||||
m_filpar[idx].loading_speed_start = float(config.filament_loading_speed_start.get_at(idx));
|
||||
m_filpar[idx].unloading_speed = float(config.filament_unloading_speed.get_at(idx));
|
||||
m_filpar[idx].unloading_speed_start = float(config.filament_unloading_speed_start.get_at(idx));
|
||||
m_filpar[idx].delay = float(config.filament_toolchange_delay.get_at(idx));
|
||||
m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx);
|
||||
m_filpar[idx].cooling_initial_speed = config.filament_cooling_initial_speed.get_at(idx);
|
||||
m_filpar[idx].cooling_final_speed = config.filament_cooling_final_speed.get_at(idx);
|
||||
m_filpar[idx].cooling_initial_speed = float(config.filament_cooling_initial_speed.get_at(idx));
|
||||
m_filpar[idx].cooling_final_speed = float(config.filament_cooling_final_speed.get_at(idx));
|
||||
}
|
||||
|
||||
m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point
|
||||
float nozzle_diameter = config.nozzle_diameter.get_at(idx);
|
||||
float nozzle_diameter = float(config.nozzle_diameter.get_at(idx));
|
||||
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
|
||||
|
||||
float max_vol_speed = config.filament_max_volumetric_speed.get_at(idx);
|
||||
float max_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx));
|
||||
if (max_vol_speed!= 0.f)
|
||||
m_filpar[idx].max_e_speed = (max_vol_speed / filament_area());
|
||||
|
||||
@ -561,7 +548,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
||||
const std::vector<unsigned int> &tools,
|
||||
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
|
||||
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
|
||||
bool last_wipe_inside_wipe_tower)
|
||||
bool /*last_wipe_inside_wipe_tower*/)
|
||||
{
|
||||
this->set_layer(first_layer_height, first_layer_height, tools.size(), true, false);
|
||||
this->m_current_tool = tools.front();
|
||||
@ -696,7 +683,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(unsigned int tool, bool last_
|
||||
box_coordinates cleaning_box(
|
||||
Vec2f(m_perimeter_width / 2.f, m_perimeter_width / 2.f),
|
||||
m_wipe_tower_width - m_perimeter_width,
|
||||
(tool != (unsigned int)(-1) ? /*m_layer_info->depth*/wipe_area+m_depth_traversed-0.5*m_perimeter_width
|
||||
(tool != (unsigned int)(-1) ? /*m_layer_info->depth*/wipe_area+m_depth_traversed-0.5f*m_perimeter_width
|
||||
: m_wipe_tower_depth-m_perimeter_width));
|
||||
|
||||
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
|
||||
@ -802,7 +789,7 @@ WipeTower::ToolChangeResult WipeTower::toolchange_Brim(bool sideOnly, float y_of
|
||||
// Extrude 4 rounds of a brim around the future wipe tower.
|
||||
box_coordinates box(wipeTower_box);
|
||||
for (size_t i = 0; i < 4; ++ i) {
|
||||
box.expand(m_perimeter_width - m_layer_height*(1.f-M_PI_4)); // the brim shall have 'normal' spacing with no extra void space
|
||||
box.expand(m_perimeter_width - m_layer_height*float(1.-M_PI_4)); // the brim shall have 'normal' spacing with no extra void space
|
||||
writer.travel (box.ld, 7000)
|
||||
.extrude(box.lu, 2100).extrude(box.ru)
|
||||
.extrude(box.rd ).extrude(box.ld);
|
||||
@ -911,8 +898,8 @@ void WipeTower::toolchange_Unload(
|
||||
const float x = volume_to_length(m_filpar[m_current_tool].ramming_speed[i] * 0.25f, line_width, m_layer_height);
|
||||
const float e = m_filpar[m_current_tool].ramming_speed[i] * 0.25f / filament_area(); // transform volume per sec to E move;
|
||||
const float dist = std::min(x - e_done, remaining); // distance to travel for either the next 0.25s, or to the next turnaround
|
||||
const float actual_time = dist/x * 0.25;
|
||||
writer.ram(writer.x(), writer.x() + (m_left_to_right ? 1.f : -1.f) * dist, 0, 0, e * (dist / x), dist / (actual_time / 60.));
|
||||
const float actual_time = dist/x * 0.25f;
|
||||
writer.ram(writer.x(), writer.x() + (m_left_to_right ? 1.f : -1.f) * dist, 0.f, 0.f, e * (dist / x), dist / (actual_time / 60.f));
|
||||
remaining -= dist;
|
||||
|
||||
if (remaining < WT_EPSILON) { // we reached a turning point
|
||||
@ -995,8 +982,8 @@ void WipeTower::toolchange_Unload(
|
||||
// Change the tool, set a speed override for soluble and flex materials.
|
||||
void WipeTower::toolchange_Change(
|
||||
WipeTowerWriter &writer,
|
||||
const unsigned int new_tool,
|
||||
const std::string& new_material)
|
||||
const size_t new_tool,
|
||||
const std::string& new_material)
|
||||
{
|
||||
// Ask the writer about how much of the old filament we consumed:
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
@ -1091,21 +1078,21 @@ void WipeTower::toolchange_Wipe(
|
||||
|
||||
float traversed_x = writer.x();
|
||||
if (m_left_to_right)
|
||||
writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
|
||||
writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
|
||||
else
|
||||
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
|
||||
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed * wipe_coeff);
|
||||
|
||||
if (writer.y()+EPSILON > cleaning_box.lu.y()-0.5f*m_perimeter_width)
|
||||
if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*m_perimeter_width)
|
||||
break; // in case next line would not fit
|
||||
|
||||
traversed_x -= writer.x();
|
||||
x_to_wipe -= fabs(traversed_x);
|
||||
x_to_wipe -= std::abs(traversed_x);
|
||||
if (x_to_wipe < WT_EPSILON) {
|
||||
writer.travel(m_left_to_right ? xl + 1.5*m_perimeter_width : xr - 1.5*m_perimeter_width, writer.y(), 7200);
|
||||
writer.travel(m_left_to_right ? xl + 1.5f*m_perimeter_width : xr - 1.5f*m_perimeter_width, writer.y(), 7200);
|
||||
break;
|
||||
}
|
||||
// stepping to the next line:
|
||||
writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5*m_perimeter_width, writer.y() + dy);
|
||||
writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5f*m_perimeter_width, writer.y() + dy);
|
||||
m_left_to_right = !m_left_to_right;
|
||||
}
|
||||
|
||||
@ -1188,7 +1175,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
||||
writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
|
||||
.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), 2900 * speed_factor);
|
||||
|
||||
const int n = 1+(right-left)/(m_bridging);
|
||||
const int n = 1+int((right-left)/m_bridging);
|
||||
const float dx = (right-left)/n;
|
||||
for (int i=1;i<=n;++i) {
|
||||
float x=left+dx*i;
|
||||
@ -1267,7 +1254,7 @@ void WipeTower::plan_tower()
|
||||
for (auto& layer : m_plan)
|
||||
layer.depth = 0.f;
|
||||
|
||||
for (int layer_index = m_plan.size() - 1; layer_index >= 0; --layer_index)
|
||||
for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index)
|
||||
{
|
||||
float this_layer_depth = std::max(m_plan[layer_index].depth, m_plan[layer_index].toolchanges_depth());
|
||||
m_plan[layer_index].depth = this_layer_depth;
|
||||
|
@ -7,21 +7,21 @@
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
class WipeTowerWriter;
|
||||
|
||||
class PrintConfig;
|
||||
enum GCodeFlavor : unsigned char;
|
||||
|
||||
|
||||
class WipeTower
|
||||
{
|
||||
public:
|
||||
struct Extrusion
|
||||
{
|
||||
{
|
||||
Extrusion(const Vec2f &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {}
|
||||
// End position of this extrusion.
|
||||
Vec2f pos;
|
||||
@ -79,7 +79,6 @@ public:
|
||||
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
||||
// wipe_area -- space available for one toolchange in mm
|
||||
WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool);
|
||||
virtual ~WipeTower() {}
|
||||
|
||||
|
||||
// Set the extruder properties.
|
||||
@ -244,7 +243,7 @@ private:
|
||||
bool m_print_brim = true;
|
||||
// A fill-in direction (positive Y, negative Y) alternates with each layer.
|
||||
wipe_shape m_current_shape = SHAPE_NORMAL;
|
||||
unsigned int m_current_tool = 0;
|
||||
size_t m_current_tool = 0;
|
||||
const std::vector<std::vector<float>> wipe_volumes;
|
||||
|
||||
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
|
||||
@ -309,13 +308,13 @@ private:
|
||||
// to store information about tool changes for a given layer
|
||||
struct WipeTowerInfo{
|
||||
struct ToolChange {
|
||||
unsigned int old_tool;
|
||||
unsigned int new_tool;
|
||||
size_t old_tool;
|
||||
size_t new_tool;
|
||||
float required_depth;
|
||||
float ramming_depth;
|
||||
float first_wipe_line;
|
||||
float wipe_volume;
|
||||
ToolChange(unsigned int old, unsigned int newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f)
|
||||
ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f)
|
||||
: old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {}
|
||||
};
|
||||
float z; // z position of the layer
|
||||
@ -350,7 +349,7 @@ private:
|
||||
|
||||
void toolchange_Change(
|
||||
WipeTowerWriter &writer,
|
||||
const unsigned int new_tool,
|
||||
const size_t new_tool,
|
||||
const std::string& new_material);
|
||||
|
||||
void toolchange_Load(
|
||||
|
@ -173,9 +173,7 @@ namespace Slic3r {
|
||||
const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; _TE_NORMAL_LAST_M73_OUTPUT_PLACEHOLDER";
|
||||
const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; _TE_SILENT_LAST_M73_OUTPUT_PLACEHOLDER";
|
||||
|
||||
// temporary human readable form to use until not removed from gcode by the new post-process method
|
||||
const std::string GCodeTimeEstimator::Color_Change_Tag = "PRINT_COLOR_CHANGE";
|
||||
// const std::string GCodeTimeEstimator::Color_Change_Tag = "_TE_COLOR_CHANGE";
|
||||
|
||||
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
|
||||
: m_mode(mode)
|
||||
@ -273,130 +271,138 @@ namespace Slic3r {
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
bool GCodeTimeEstimator::post_process_remaining_times(const std::string& filename, float interval)
|
||||
bool GCodeTimeEstimator::post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode)
|
||||
{
|
||||
boost::nowide::ifstream in(filename);
|
||||
if (!in.good())
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for reading.\n"));
|
||||
throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for reading.\n"));
|
||||
|
||||
std::string path_tmp = filename + ".times";
|
||||
std::string path_tmp = filename + ".postprocess";
|
||||
|
||||
FILE* out = boost::nowide::fopen(path_tmp.c_str(), "wb");
|
||||
if (out == nullptr)
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nCannot open file for writing.\n"));
|
||||
throw std::runtime_error(std::string("Time estimator post process export failed.\nCannot open file for writing.\n"));
|
||||
|
||||
std::string time_mask;
|
||||
switch (m_mode)
|
||||
{
|
||||
default:
|
||||
case Normal:
|
||||
{
|
||||
time_mask = "M73 P%s R%s\n";
|
||||
break;
|
||||
}
|
||||
case Silent:
|
||||
{
|
||||
time_mask = "M73 Q%s S%s\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::string normal_time_mask = "M73 P%s R%s\n";
|
||||
std::string silent_time_mask = "M73 Q%s S%s\n";
|
||||
char line_M73[64];
|
||||
|
||||
unsigned int g1_lines_count = 0;
|
||||
float last_recorded_time = 0.0f;
|
||||
std::string gcode_line;
|
||||
// buffer line to export only when greater than 64K to reduce writing calls
|
||||
std::string export_line;
|
||||
char time_line[64];
|
||||
G1LineIdToBlockIdMap::const_iterator it_line_id = m_g1_line_ids.begin();
|
||||
while (std::getline(in, gcode_line))
|
||||
{
|
||||
if (!in.good())
|
||||
{
|
||||
fclose(out);
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nError while reading from file.\n"));
|
||||
}
|
||||
|
||||
// replaces placeholders for initial line M73 with the real lines
|
||||
if (((m_mode == Normal) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag)) ||
|
||||
((m_mode == Silent) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag)))
|
||||
{
|
||||
sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(m_time).c_str());
|
||||
gcode_line = time_line;
|
||||
}
|
||||
// replaces placeholders for final line M73 with the real lines
|
||||
else if (((m_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) ||
|
||||
((m_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag)))
|
||||
{
|
||||
sprintf(time_line, time_mask.c_str(), "100", "0");
|
||||
gcode_line = time_line;
|
||||
}
|
||||
else
|
||||
gcode_line += "\n";
|
||||
|
||||
|
||||
// add remaining time lines where needed
|
||||
m_parser.parse_line(gcode_line,
|
||||
[this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
if (line.cmd_is("G1"))
|
||||
{
|
||||
++g1_lines_count;
|
||||
|
||||
assert(it_line_id == m_g1_line_ids.end() || it_line_id->first >= g1_lines_count);
|
||||
|
||||
const Block *block = nullptr;
|
||||
if (it_line_id != m_g1_line_ids.end() && it_line_id->first == g1_lines_count) {
|
||||
if (line.has_e() && it_line_id->second < (unsigned int)m_blocks.size())
|
||||
block = &m_blocks[it_line_id->second];
|
||||
++it_line_id;
|
||||
}
|
||||
|
||||
if (block != nullptr && block->elapsed_time != -1.0f) {
|
||||
float block_remaining_time = m_time - block->elapsed_time;
|
||||
if (std::abs(last_recorded_time - block_remaining_time) > interval)
|
||||
{
|
||||
sprintf(time_line, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / m_time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
||||
gcode_line += time_line;
|
||||
|
||||
last_recorded_time = block_remaining_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export_line += gcode_line;
|
||||
if (export_line.length() > 65535)
|
||||
{
|
||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
|
||||
if (ferror(out))
|
||||
{
|
||||
in.close();
|
||||
fclose(out);
|
||||
boost::nowide::remove(path_tmp.c_str());
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nIs the disk full?\n"));
|
||||
}
|
||||
export_line.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (export_line.length() > 0)
|
||||
{
|
||||
// helper function to write to disk
|
||||
auto write_string = [&](const std::string& str) {
|
||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out);
|
||||
if (ferror(out))
|
||||
{
|
||||
in.close();
|
||||
fclose(out);
|
||||
boost::nowide::remove(path_tmp.c_str());
|
||||
throw std::runtime_error(std::string("Remaining times export failed.\nIs the disk full?\n"));
|
||||
throw std::runtime_error(std::string("Time estimator post process export failed.\nIs the disk full?\n"));
|
||||
}
|
||||
export_line.clear();
|
||||
};
|
||||
|
||||
GCodeReader parser;
|
||||
unsigned int g1_lines_count = 0;
|
||||
int normal_g1_line_id = 0;
|
||||
float normal_last_recorded_time = 0.0f;
|
||||
int silent_g1_line_id = 0;
|
||||
float silent_last_recorded_time = 0.0f;
|
||||
|
||||
// helper function to process g1 lines
|
||||
auto process_g1_line = [&](const PostProcessData* const data, const GCodeReader::GCodeLine& line, int& g1_line_id, float& last_recorded_time, const std::string& time_mask) {
|
||||
if (data == nullptr)
|
||||
return;
|
||||
|
||||
assert((g1_line_id >= (int)data->g1_line_ids.size()) || (data->g1_line_ids[g1_line_id].first >= g1_lines_count));
|
||||
const Block* block = nullptr;
|
||||
const G1LineIdToBlockId& map_item = data->g1_line_ids[g1_line_id];
|
||||
if ((g1_line_id < (int)data->g1_line_ids.size()) && (map_item.first == g1_lines_count))
|
||||
{
|
||||
if (line.has_e() && (map_item.second < (unsigned int)data->blocks.size()))
|
||||
block = &data->blocks[map_item.second];
|
||||
++g1_line_id;
|
||||
}
|
||||
|
||||
if ((block != nullptr) && (block->elapsed_time != -1.0f))
|
||||
{
|
||||
float block_remaining_time = data->time - block->elapsed_time;
|
||||
if (std::abs(last_recorded_time - block_remaining_time) > interval_sec)
|
||||
{
|
||||
sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
||||
gcode_line += line_M73;
|
||||
|
||||
last_recorded_time = block_remaining_time;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
while (std::getline(in, gcode_line))
|
||||
{
|
||||
if (!in.good())
|
||||
{
|
||||
fclose(out);
|
||||
throw std::runtime_error(std::string("Time estimator post process export failed.\nError while reading from file.\n"));
|
||||
}
|
||||
|
||||
// check tags
|
||||
// remove color change tag
|
||||
if (gcode_line == "; " + Color_Change_Tag)
|
||||
continue;
|
||||
|
||||
// replaces placeholders for initial line M73 with the real lines
|
||||
if ((normal_mode != nullptr) && (gcode_line == Normal_First_M73_Output_Placeholder_Tag))
|
||||
{
|
||||
sprintf(line_M73, normal_time_mask.c_str(), "0", _get_time_minutes(normal_mode->time).c_str());
|
||||
gcode_line = line_M73;
|
||||
}
|
||||
else if ((silent_mode != nullptr) && (gcode_line == Silent_First_M73_Output_Placeholder_Tag))
|
||||
{
|
||||
sprintf(line_M73, silent_time_mask.c_str(), "0", _get_time_minutes(silent_mode->time).c_str());
|
||||
gcode_line = line_M73;
|
||||
}
|
||||
// replaces placeholders for final line M73 with the real lines
|
||||
else if ((normal_mode != nullptr) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag))
|
||||
{
|
||||
sprintf(line_M73, normal_time_mask.c_str(), "100", "0");
|
||||
gcode_line = line_M73;
|
||||
}
|
||||
else if ((silent_mode != nullptr) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))
|
||||
{
|
||||
sprintf(line_M73, silent_time_mask.c_str(), "100", "0");
|
||||
gcode_line = line_M73;
|
||||
}
|
||||
else
|
||||
gcode_line += "\n";
|
||||
|
||||
// add remaining time lines where needed
|
||||
parser.parse_line(gcode_line,
|
||||
[&](GCodeReader& reader, const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
if (line.cmd_is("G1"))
|
||||
{
|
||||
++g1_lines_count;
|
||||
process_g1_line(silent_mode, line, silent_g1_line_id, silent_last_recorded_time, silent_time_mask);
|
||||
process_g1_line(normal_mode, line, normal_g1_line_id, normal_last_recorded_time, normal_time_mask);
|
||||
}
|
||||
});
|
||||
|
||||
export_line += gcode_line;
|
||||
if (export_line.length() > 65535)
|
||||
write_string(export_line);
|
||||
}
|
||||
|
||||
if (!export_line.empty())
|
||||
write_string(export_line);
|
||||
|
||||
fclose(out);
|
||||
in.close();
|
||||
|
||||
if (rename_file(path_tmp, filename))
|
||||
throw std::runtime_error(std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + filename + '\n' +
|
||||
"Is " + path_tmp + " locked?" + '\n');
|
||||
"Is " + path_tmp + " locked?" + '\n');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -213,9 +213,19 @@ namespace Slic3r {
|
||||
typedef std::map<Block::EMoveType, MoveStats> MovesStatsMap;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
public:
|
||||
typedef std::pair<unsigned int, unsigned int> G1LineIdToBlockId;
|
||||
typedef std::vector<G1LineIdToBlockId> G1LineIdToBlockIdMap;
|
||||
|
||||
struct PostProcessData
|
||||
{
|
||||
const G1LineIdToBlockIdMap& g1_line_ids;
|
||||
const BlocksList& blocks;
|
||||
float time;
|
||||
|
||||
PostProcessData(const G1LineIdToBlockIdMap& g1_line_ids, const BlocksList& blocks, float time) : g1_line_ids(g1_line_ids), blocks(blocks), time(time) {}
|
||||
};
|
||||
|
||||
private:
|
||||
EMode m_mode;
|
||||
GCodeReader m_parser;
|
||||
@ -263,11 +273,12 @@ namespace Slic3r {
|
||||
void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
|
||||
|
||||
// Process the gcode contained in the file with the given filename,
|
||||
// placing in it new lines (M73) containing the remaining time, at the given interval in seconds
|
||||
// and saving the result back in the same file
|
||||
// This time estimator should have been already used to calculate the time estimate for the gcode
|
||||
// contained in the given file before to call this method
|
||||
bool post_process_remaining_times(const std::string& filename, float interval_sec);
|
||||
// replacing placeholders with correspondent new lines M73
|
||||
// placing new lines M73 (containing the remaining time) where needed (in dependence of the given interval in seconds)
|
||||
// and removing working tags (as those used for color changes)
|
||||
// if normal_mode == nullptr no M73 line will be added for normal mode
|
||||
// if silent_mode == nullptr no M73 line will be added for silent mode
|
||||
static bool post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode);
|
||||
|
||||
// Set current position on the given axis with the given value
|
||||
void set_axis_position(EAxis axis, float position);
|
||||
@ -362,6 +373,8 @@ namespace Slic3r {
|
||||
// Return an estimate of the memory consumed by the time estimator.
|
||||
size_t memory_used() const;
|
||||
|
||||
PostProcessData get_post_process_data() const { return PostProcessData(m_g1_line_ids, m_blocks, m_time); }
|
||||
|
||||
private:
|
||||
void _reset();
|
||||
void _reset_time();
|
||||
|
@ -171,21 +171,6 @@ void Layer::make_perimeters()
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << " - Done";
|
||||
}
|
||||
|
||||
void Layer::make_fills()
|
||||
{
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("Making fills for layer " PRINTF_ZU "\n", this->id());
|
||||
#endif
|
||||
for (LayerRegion *layerm : m_regions) {
|
||||
layerm->fills.clear();
|
||||
make_fill(*layerm, layerm->fills);
|
||||
#ifndef NDEBUG
|
||||
for (size_t i = 0; i < layerm->fills.entities.size(); ++ i)
|
||||
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i]) != NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Layer::export_region_slices_to_svg(const char *path) const
|
||||
{
|
||||
BoundingBox bbox;
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
config(config), object_config(object_config), print_config(print_config),
|
||||
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
|
||||
_ext_mm3_per_mm(-1), _mm3_per_mm(-1), _mm3_per_mm_overhang(-1)
|
||||
{};
|
||||
{}
|
||||
void process();
|
||||
|
||||
private:
|
||||
|
@ -108,7 +108,6 @@ static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConf
|
||||
|
||||
std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig &rhs)
|
||||
{
|
||||
const ConfigDef *def = rhs.def();
|
||||
std::vector<std::string> diff_keys;
|
||||
for (const t_config_option_key &opt_key : rhs.keys())
|
||||
if (! opts_equal(m_config, rhs, opt_key))
|
||||
@ -124,7 +123,6 @@ std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig
|
||||
// a current extruder ID is used.
|
||||
bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs)
|
||||
{
|
||||
const ConfigDef *def = rhs.def();
|
||||
bool modified = false;
|
||||
for (const t_config_option_key &opt_key : rhs.keys()) {
|
||||
if (! opts_equal(m_config, rhs, opt_key)) {
|
||||
|
@ -1228,24 +1228,35 @@ std::string Print::validate() const
|
||||
if (has_custom_layering) {
|
||||
const std::vector<coordf_t> &layer_height_profile_tallest = layer_height_profiles[tallest_object_idx];
|
||||
for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) {
|
||||
if (idx_object == tallest_object_idx)
|
||||
continue;
|
||||
const std::vector<coordf_t> &layer_height_profile = layer_height_profiles[idx_object];
|
||||
bool failed = false;
|
||||
if (layer_height_profile_tallest.size() >= layer_height_profile.size()) {
|
||||
size_t i = 0;
|
||||
while (i < layer_height_profile.size() && i < layer_height_profile_tallest.size()) {
|
||||
if (std::abs(layer_height_profile_tallest[i] - layer_height_profile[i])) {
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
++ i;
|
||||
if (i == layer_height_profile.size() - 2) // this element contains this objects max z
|
||||
if (layer_height_profile_tallest[i] > layer_height_profile[i]) // the difference does not matter in this case
|
||||
++ i;
|
||||
|
||||
// The comparison of the profiles is not just about element-wise equality, some layers may not be
|
||||
// explicitely included. Always remember z and height of last reference layer that in the vector
|
||||
// and compare to that.
|
||||
size_t i = 0; // index into tested profile
|
||||
size_t j = 0; // index into reference profile
|
||||
coordf_t ref_z = -1.;
|
||||
coordf_t next_ref_z = layer_height_profile_tallest[0];
|
||||
coordf_t ref_height = -1.;
|
||||
while (i < layer_height_profile.size()) {
|
||||
coordf_t this_z = layer_height_profile[i];
|
||||
coordf_t this_height = layer_height_profile[i+1];
|
||||
if (next_ref_z < this_z + EPSILON) {
|
||||
ref_z = next_ref_z;
|
||||
do { // one layer can be in the vector several times
|
||||
ref_height = layer_height_profile_tallest[j+1];
|
||||
if (j+2 >= layer_height_profile_tallest.size())
|
||||
break;
|
||||
j += 2;
|
||||
next_ref_z = layer_height_profile_tallest[j];
|
||||
} while (ref_z == next_ref_z);
|
||||
}
|
||||
} else
|
||||
failed = true;
|
||||
if (failed)
|
||||
return L("The Wipe tower is only supported if all objects have the same layer height profile");
|
||||
if (std::abs(this_height - ref_height) > EPSILON)
|
||||
return L("The Wipe tower is only supported if all objects have the same layer height profile");
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ class PrintRegion
|
||||
public:
|
||||
const Print* print() const { return m_print; }
|
||||
const PrintRegionConfig& config() const { return m_config; }
|
||||
// 1-based extruder identifier for this region and role.
|
||||
unsigned int extruder(FlowRole role) const;
|
||||
Flow flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const;
|
||||
// Average diameter of nozzles participating on extruding this region.
|
||||
coordf_t nozzle_dmr_avg(const PrintConfig &print_config) const;
|
||||
|
@ -2049,7 +2049,7 @@ void PrintConfigDef::init_fff_params()
|
||||
{
|
||||
int threads = (unsigned int)boost::thread::hardware_concurrency();
|
||||
def->set_default_value(new ConfigOptionInt(threads > 0 ? threads : 2));
|
||||
def->cli == ConfigOptionDef::nocli;
|
||||
def->cli = ConfigOptionDef::nocli;
|
||||
}
|
||||
|
||||
def = this->add("toolchange_gcode", coString);
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum GCodeFlavor {
|
||||
enum GCodeFlavor : unsigned char {
|
||||
gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit,
|
||||
gcfSmoothie, gcfNoExtrusion,
|
||||
};
|
||||
@ -35,7 +35,7 @@ enum PrintHostType {
|
||||
|
||||
enum InfillPattern {
|
||||
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipCount,
|
||||
};
|
||||
|
||||
enum SupportMaterialPattern {
|
||||
|
@ -1443,11 +1443,8 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
|
||||
layer_height_profile.clear();
|
||||
|
||||
if (layer_height_profile.empty()) {
|
||||
if (0)
|
||||
// if (this->layer_height_profile.empty())
|
||||
layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
|
||||
else
|
||||
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment
|
||||
//layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes);
|
||||
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges);
|
||||
updated = true;
|
||||
}
|
||||
return updated;
|
||||
@ -1870,12 +1867,13 @@ std::vector<ExPolygons> PrintObject::slice_modifiers(size_t region_id, const std
|
||||
merge.assign(out.size(), false);
|
||||
} else {
|
||||
for (size_t i = 0; i < out.size(); ++ i)
|
||||
if (! this_slices[i].empty())
|
||||
if (! this_slices[i].empty()) {
|
||||
if (! out[i].empty()) {
|
||||
append(out[i], this_slices[i]);
|
||||
merge[i] = true;
|
||||
} else
|
||||
out[i] = std::move(this_slices[i]);
|
||||
}
|
||||
}
|
||||
i = j;
|
||||
} else
|
||||
|
@ -2,6 +2,21 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// 1-based extruder identifier for this region and role.
|
||||
unsigned int PrintRegion::extruder(FlowRole role) const
|
||||
{
|
||||
size_t extruder = 0;
|
||||
if (role == frPerimeter || role == frExternalPerimeter)
|
||||
extruder = m_config.perimeter_extruder;
|
||||
else if (role == frInfill)
|
||||
extruder = m_config.infill_extruder;
|
||||
else if (role == frSolidInfill || role == frTopSolidInfill)
|
||||
extruder = m_config.solid_infill_extruder;
|
||||
else
|
||||
throw std::invalid_argument("Unknown role");
|
||||
return extruder;
|
||||
}
|
||||
|
||||
Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_layer, double width, const PrintObject &object) const
|
||||
{
|
||||
ConfigOptionFloatOrPercent config_width;
|
||||
@ -28,24 +43,13 @@ Flow PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool fir
|
||||
throw std::invalid_argument("Unknown role");
|
||||
}
|
||||
}
|
||||
if (config_width.value == 0) {
|
||||
|
||||
if (config_width.value == 0)
|
||||
config_width = object.config().extrusion_width;
|
||||
}
|
||||
|
||||
// get the configured nozzle_diameter for the extruder associated
|
||||
// to the flow role requested
|
||||
size_t extruder = 0; // 1-based
|
||||
if (role == frPerimeter || role == frExternalPerimeter) {
|
||||
extruder = m_config.perimeter_extruder;
|
||||
} else if (role == frInfill) {
|
||||
extruder = m_config.infill_extruder;
|
||||
} else if (role == frSolidInfill || role == frTopSolidInfill) {
|
||||
extruder = m_config.solid_infill_extruder;
|
||||
} else {
|
||||
throw std::invalid_argument("Unknown role");
|
||||
}
|
||||
double nozzle_diameter = m_print->config().nozzle_diameter.get_at(extruder-1);
|
||||
|
||||
// Get the configured nozzle_diameter for the extruder associated to the flow role requested.
|
||||
// Here this->extruder(role) - 1 may underflow to MAX_INT, but then the get_at() will follback to zero'th element, so everything is all right.
|
||||
double nozzle_diameter = m_print->config().nozzle_diameter.get_at(this->extruder(role) - 1);
|
||||
return Flow::new_from_config_width(role, config_width, (float)nozzle_diameter, (float)layer_height, bridge ? (float)m_config.bridge_flow_ratio : 0.0f);
|
||||
}
|
||||
|
||||
@ -79,12 +83,14 @@ void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_con
|
||||
|
||||
void PrintRegion::collect_object_printing_extruders(std::vector<unsigned int> &object_extruders) const
|
||||
{
|
||||
auto num_extruders = (int)print()->config().nozzle_diameter.size();
|
||||
// PrintRegion, if used by some PrintObject, shall have all the extruders set to an existing printer extruder.
|
||||
// If not, then there must be something wrong with the Print::apply() function.
|
||||
#ifndef NDEBUG
|
||||
auto num_extruders = (int)print()->config().nozzle_diameter.size();
|
||||
assert(this->config().perimeter_extruder <= num_extruders);
|
||||
assert(this->config().infill_extruder <= num_extruders);
|
||||
assert(this->config().solid_infill_extruder <= num_extruders);
|
||||
#endif
|
||||
collect_object_printing_extruders(print()->config(), this->config(), object_extruders);
|
||||
}
|
||||
|
||||
|
@ -185,8 +185,6 @@ private:
|
||||
|
||||
SLAAutoSupports::Config m_config;
|
||||
|
||||
float m_supports_force_total = 0.f;
|
||||
|
||||
void process(const std::vector<ExPolygons>& slices, const std::vector<float>& heights);
|
||||
void uniformly_cover(const ExPolygons& islands, Structure& structure, PointGrid3D &grid3d, bool is_new_island = false, bool just_one = false);
|
||||
void project_onto_mesh(std::vector<sla::SupportPoint>& points) const;
|
||||
|
@ -676,7 +676,7 @@ std::string SLAPrint::validate() const
|
||||
if(supports_en && !builtinpad.enabled && elv < pinhead_width )
|
||||
return L(
|
||||
"Elevation is too low for object. Use the \"Pad around "
|
||||
"obect\" feature to print the object without elevation.");
|
||||
"object\" feature to print the object without elevation.");
|
||||
|
||||
if(supports_en && builtinpad.enabled &&
|
||||
cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) {
|
||||
|
@ -24,9 +24,8 @@ enum SurfaceType {
|
||||
stInternalVoid,
|
||||
// Inner/outer perimeters.
|
||||
stPerimeter,
|
||||
// Last surface type, if the SurfaceType is used as an index into a vector.
|
||||
stLast,
|
||||
stCount = stLast + 1
|
||||
// Number of SurfaceType enums.
|
||||
stCount,
|
||||
};
|
||||
|
||||
class Surface
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
|
||||
void clear() { surfaces.clear(); }
|
||||
bool empty() const { return surfaces.empty(); }
|
||||
size_t size() const { return surfaces.size(); }
|
||||
bool has(SurfaceType type) const {
|
||||
for (const Surface &surface : this->surfaces)
|
||||
if (surface.surface_type == type) return true;
|
||||
|
@ -1142,7 +1142,7 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
|
||||
Color color;
|
||||
::memcpy((void*)color.data(), (const void*)volume->color, 4 * sizeof(float));
|
||||
fprintf(fp, "\n# material volume %d\n", volumes_count);
|
||||
fprintf(fp, "usemtl material_%lld\n", 1 + std::distance(colors.begin(), colors.find(color)));
|
||||
fprintf(fp, "usemtl material_%lld\n", (long long)(1 + std::distance(colors.begin(), colors.find(color))));
|
||||
|
||||
int base_vertex_id = vertices_count + 1;
|
||||
int base_normal_id = normals_count + 1;
|
||||
@ -1242,8 +1242,8 @@ static void thick_lines_to_indexed_vertex_array(
|
||||
// calculate new XY normals
|
||||
Vec2d xy_right_normal = unscale(line.normal()).normalized();
|
||||
|
||||
int idx_a[4];
|
||||
int idx_b[4];
|
||||
int idx_a[4] = { 0, 0, 0, 0 }; // initialized to avoid warnings
|
||||
int idx_b[4] = { 0, 0, 0, 0 }; // initialized to avoid warnings
|
||||
int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6);
|
||||
|
||||
bool bottom_z_different = bottom_z_prev != bottom_z;
|
||||
|
@ -446,7 +446,7 @@ void BedShapePanel::update_shape()
|
||||
auto twopi = 2 * PI;
|
||||
auto edges = 72;
|
||||
std::vector<Vec2d> points;
|
||||
for (size_t i = 1; i <= edges; ++i) {
|
||||
for (int i = 1; i <= edges; ++i) {
|
||||
auto angle = i * twopi / edges;
|
||||
points.push_back(Vec2d(r*cos(angle), r*sin(angle)));
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
show_error(m_parent, _(L("Invalid numeric input.")));
|
||||
set_value(double_to_string(val), true);
|
||||
}
|
||||
else if (check_value && (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max ||
|
||||
else if (check_value && ((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
|
||||
m_opt.sidetext.rfind("mm ") != std::string::npos && val > 1) &&
|
||||
(m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value)))
|
||||
{
|
||||
@ -444,7 +444,7 @@ void TextCtrl::disable() { dynamic_cast<wxTextCtrl*>(window)->Disable(); dynamic
|
||||
#ifdef __WXGTK__
|
||||
void TextCtrl::change_field_value(wxEvent& event)
|
||||
{
|
||||
if (bChangedValueEvent = event.GetEventType()==wxEVT_KEY_UP)
|
||||
if (bChangedValueEvent = (event.GetEventType()==wxEVT_KEY_UP))
|
||||
on_change_field();
|
||||
event.Skip();
|
||||
};
|
||||
@ -768,7 +768,7 @@ void Choice::set_selection()
|
||||
size_t idx = 0;
|
||||
for (auto el : m_opt.enum_values)
|
||||
{
|
||||
if (el.compare(text_value) == 0)
|
||||
if (el == text_value)
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
@ -789,7 +789,7 @@ void Choice::set_selection()
|
||||
size_t idx = 0;
|
||||
for (auto el : m_opt.enum_values)
|
||||
{
|
||||
if (el.compare(text_value) == 0)
|
||||
if (el == text_value)
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
@ -804,7 +804,7 @@ void Choice::set_selection()
|
||||
size_t idx = 0;
|
||||
for (auto el : m_opt.enum_values)
|
||||
{
|
||||
if (el.compare(text_value) == 0)
|
||||
if (el == text_value)
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
@ -813,6 +813,7 @@ void Choice::set_selection()
|
||||
field->SetSelection(idx);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -823,7 +824,7 @@ void Choice::set_value(const std::string& value, bool change_event) //! Redunda
|
||||
size_t idx=0;
|
||||
for (auto el : m_opt.enum_values)
|
||||
{
|
||||
if (el.compare(value) == 0)
|
||||
if (el == value)
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
@ -856,7 +857,7 @@ void Choice::set_value(const boost::any& value, bool change_event)
|
||||
auto idx = 0;
|
||||
for (auto el : m_opt.enum_values)
|
||||
{
|
||||
if (el.compare(text_value) == 0)
|
||||
if (el == text_value)
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
@ -887,7 +888,7 @@ void Choice::set_value(const boost::any& value, bool change_event)
|
||||
size_t idx = 0;
|
||||
for (auto el : m_opt.enum_values)
|
||||
{
|
||||
if (el.compare(key) == 0)
|
||||
if (el == key)
|
||||
break;
|
||||
++idx;
|
||||
}
|
||||
|
@ -845,22 +845,23 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePrevie
|
||||
{
|
||||
auto& config = wxGetApp().preset_bundle->project_config;
|
||||
const std::vector<double>& color_print_values = config.option<ConfigOptionFloats>("colorprint_heights")->values;
|
||||
const size_t values_cnt = color_print_values.size();
|
||||
if (values_cnt > 0) {
|
||||
|
||||
if (!color_print_values.empty()) {
|
||||
std::vector<double> print_zs = canvas.get_current_print_zs(true);
|
||||
size_t z = 0;
|
||||
for (size_t i = 0; i < values_cnt; ++i)
|
||||
for (auto cp_value : color_print_values)
|
||||
{
|
||||
double prev_z = -1.0;
|
||||
for ( ; z < print_zs.size(); ++z)
|
||||
if (fabs(color_print_values[i] - print_zs[z]) < EPSILON) {
|
||||
prev_z = z > 0 ? print_zs[z - 1] : 0.;
|
||||
break;
|
||||
}
|
||||
if (prev_z < 0)
|
||||
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), cp_value - DoubleSlider::epsilon());
|
||||
|
||||
if (lower_b == print_zs.end())
|
||||
continue;
|
||||
|
||||
cp_legend_values.push_back(std::pair<double, double>(prev_z, color_print_values[i]));
|
||||
double current_z = *lower_b;
|
||||
double previous_z = lower_b == print_zs.begin() ? 0.0 : *(--lower_b);
|
||||
|
||||
// to avoid duplicate values, check adding values
|
||||
if (cp_legend_values.empty() ||
|
||||
!(cp_legend_values.back().first == previous_z && cp_legend_values.back().second == current_z) )
|
||||
cp_legend_values.push_back(std::pair<double, double>(previous_z, current_z));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -901,11 +902,11 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
|
||||
|
||||
// Disabling ClearType works, but the font returned is very different (much thicker) from the default.
|
||||
// msw_disable_cleartype(font);
|
||||
bool cleartype = is_font_cleartype(font);
|
||||
// bool cleartype = is_font_cleartype(font);
|
||||
#else
|
||||
// select default font
|
||||
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale_gl);
|
||||
bool cleartype = false;
|
||||
// bool cleartype = false;
|
||||
#endif /* __WXMSW__ */
|
||||
|
||||
memDC.SetFont(font);
|
||||
@ -1330,13 +1331,13 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
|
||||
void GLCanvas3D::update_instance_printable_state_for_object(const size_t obj_idx)
|
||||
{
|
||||
ModelObject* model_object = m_model->objects[obj_idx];
|
||||
for (int inst_idx = 0; inst_idx < model_object->instances.size(); inst_idx++)
|
||||
for (int inst_idx = 0; inst_idx < (int)model_object->instances.size(); ++inst_idx)
|
||||
{
|
||||
ModelInstance* instance = model_object->instances[inst_idx];
|
||||
|
||||
for (GLVolume* volume : m_volumes.volumes)
|
||||
{
|
||||
if ((volume->object_idx() == obj_idx) && (volume->instance_idx() == inst_idx))
|
||||
if ((volume->object_idx() == (int)obj_idx) && (volume->instance_idx() == inst_idx))
|
||||
volume->printable = instance->printable;
|
||||
}
|
||||
}
|
||||
@ -1672,7 +1673,7 @@ void GLCanvas3D::ensure_on_bed(unsigned int object_idx)
|
||||
|
||||
for (GLVolume* volume : m_volumes.volumes)
|
||||
{
|
||||
if ((volume->object_idx() == object_idx) && !volume->is_modifier)
|
||||
if ((volume->object_idx() == (int)object_idx) && !volume->is_modifier)
|
||||
{
|
||||
double min_z = volume->transformed_convex_hull_bounding_box().min(2);
|
||||
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
|
||||
@ -1968,8 +1969,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
}
|
||||
}
|
||||
|
||||
// stores the current volumes count
|
||||
size_t volumes_count = m_volumes.volumes.size();
|
||||
// // stores the current volumes count
|
||||
// size_t volumes_count = m_volumes.volumes.size();
|
||||
|
||||
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
|
||||
if (!instances[istep].empty())
|
||||
@ -1978,7 +1979,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
|
||||
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
||||
for (GLVolume* volume : m_volumes.volumes)
|
||||
if (volume->object_idx() < m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable())
|
||||
if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable())
|
||||
volume->set_sla_shift_z(shift_zs[volume->object_idx()]);
|
||||
}
|
||||
|
||||
@ -3733,7 +3734,7 @@ bool GLCanvas3D::_init_undoredo_toolbar()
|
||||
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(true, 0.5f * (left + right)); };
|
||||
item.enabling_callback = [this]()->bool {
|
||||
bool can_undo = wxGetApp().plater()->can_undo();
|
||||
unsigned int id = m_undoredo_toolbar.get_item_id("undo");
|
||||
int id = m_undoredo_toolbar.get_item_id("undo");
|
||||
|
||||
std::string curr_additional_tooltip;
|
||||
m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip);
|
||||
@ -3765,7 +3766,7 @@ bool GLCanvas3D::_init_undoredo_toolbar()
|
||||
item.right.render_callback = [this](float left, float right, float, float) { if (m_canvas != nullptr) _render_undo_redo_stack(false, 0.5f * (left + right)); };
|
||||
item.enabling_callback = [this]()->bool {
|
||||
bool can_redo = wxGetApp().plater()->can_redo();
|
||||
unsigned int id = m_undoredo_toolbar.get_item_id("redo");
|
||||
int id = m_undoredo_toolbar.get_item_id("redo");
|
||||
|
||||
std::string curr_additional_tooltip;
|
||||
m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip);
|
||||
@ -3908,7 +3909,7 @@ void GLCanvas3D::_picking_pass() const
|
||||
m_gizmos.set_hover_id(-1);
|
||||
}
|
||||
else
|
||||
m_gizmos.set_hover_id(inside && volume_id <= GLGizmoBase::BASE_ID ? (GLGizmoBase::BASE_ID - volume_id) : -1);
|
||||
m_gizmos.set_hover_id(inside && volume_id <= (int)GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - volume_id) : -1);
|
||||
|
||||
_update_volumes_hover_state();
|
||||
}
|
||||
@ -4858,7 +4859,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
||||
ctxt.print = print;
|
||||
ctxt.tool_colors = tool_colors.empty() ? nullptr : &tool_colors;
|
||||
if (print->wipe_tower_data().priming && print->config().single_extruder_multi_material_priming)
|
||||
for (int i=0; i<print->wipe_tower_data().priming.get()->size(); ++i)
|
||||
for (int i=0; i<(int)print->wipe_tower_data().priming.get()->size(); ++i)
|
||||
ctxt.priming.emplace_back(print->wipe_tower_data().priming.get()->at(i));
|
||||
if (print->wipe_tower_data().final_purge)
|
||||
ctxt.final.emplace_back(*print->wipe_tower_data().final_purge.get());
|
||||
@ -5037,7 +5038,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
||||
}
|
||||
case GCodePreviewData::Extrusion::ColorPrint:
|
||||
{
|
||||
const size_t color_cnt = tool_colors.size() / 4;
|
||||
int color_cnt = (int)tool_colors.size() / 4;
|
||||
|
||||
int val = int(value);
|
||||
while (val >= color_cnt)
|
||||
|
@ -641,11 +641,9 @@ public:
|
||||
void start_keeping_dirty() { m_keep_dirty = true; }
|
||||
void stop_keeping_dirty() { m_keep_dirty = false; }
|
||||
|
||||
unsigned int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
|
||||
void force_main_toolbar_left_action(unsigned int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
|
||||
void force_main_toolbar_right_action(unsigned int item_id) { m_main_toolbar.force_right_action(item_id, *this); }
|
||||
void get_undoredo_toolbar_additional_tooltip(unsigned int item_id, std::string& text) { return m_undoredo_toolbar.get_additional_tooltip(item_id, text); }
|
||||
void set_undoredo_toolbar_additional_tooltip(unsigned int item_id, const std::string& text) { m_undoredo_toolbar.set_additional_tooltip(item_id, text); }
|
||||
int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
|
||||
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
|
||||
void force_main_toolbar_right_action(int item_id) { m_main_toolbar.force_right_action(item_id, *this); }
|
||||
|
||||
bool has_toolpaths_to_export() const;
|
||||
void export_toolpaths_to_obj(const char* filename) const;
|
||||
|
@ -359,9 +359,7 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas)
|
||||
void GLCanvas3DManager::detect_multisample(int* attribList)
|
||||
{
|
||||
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
|
||||
const AppConfig* app_config = GUI::get_app_config();
|
||||
bool enable_multisample = wxVersion >= 30003;
|
||||
|
||||
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? MS_Enabled : MS_Disabled;
|
||||
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
|
||||
// s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
|
||||
|
@ -56,7 +56,7 @@ bool GLTexture::Compressor::unsent_compressed_data_available() const
|
||||
{
|
||||
if (m_levels.empty())
|
||||
return false;
|
||||
// Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the dat of m_levels modified by the worker thread are accessible to the calling thread.
|
||||
// Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the data of m_levels modified by the worker thread are accessible to the calling thread.
|
||||
unsigned int num_compressed = m_num_levels_compressed;
|
||||
for (unsigned int i = 0; i < num_compressed; ++ i)
|
||||
if (! m_levels[i].sent_to_gpu && ! m_levels[i].compressed_data.empty())
|
||||
@ -89,8 +89,8 @@ void GLTexture::Compressor::send_compressed_data_to_gpu()
|
||||
}
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
if (num_compressed == (unsigned int)m_levels.size())
|
||||
// Finalize the worker thread, close it.
|
||||
if (num_compressed == (int)m_levels.size())
|
||||
// Finalize the worker thread, close it.
|
||||
this->reset();
|
||||
}
|
||||
|
||||
|
@ -345,9 +345,9 @@ bool GLToolbar::is_any_item_pressed() const
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int GLToolbar::get_item_id(const std::string& name) const
|
||||
int GLToolbar::get_item_id(const std::string& name) const
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
for (int i = 0; i < (int)m_items.size(); ++i)
|
||||
{
|
||||
if (m_items[i]->get_name() == name)
|
||||
return i;
|
||||
@ -356,19 +356,9 @@ unsigned int GLToolbar::get_item_id(const std::string& name) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GLToolbar::force_left_action(unsigned int item_id, GLCanvas3D& parent)
|
||||
void GLToolbar::get_additional_tooltip(int item_id, std::string& text)
|
||||
{
|
||||
do_action(GLToolbarItem::Left, item_id, parent, false);
|
||||
}
|
||||
|
||||
void GLToolbar::force_right_action(unsigned int item_id, GLCanvas3D& parent)
|
||||
{
|
||||
do_action(GLToolbarItem::Right, item_id, parent, false);
|
||||
}
|
||||
|
||||
void GLToolbar::get_additional_tooltip(unsigned int item_id, std::string& text)
|
||||
{
|
||||
if (item_id < (unsigned int)m_items.size())
|
||||
if ((0 <= item_id) && (item_id < (int)m_items.size()))
|
||||
{
|
||||
GLToolbarItem* item = m_items[item_id];
|
||||
if (item != nullptr)
|
||||
@ -381,9 +371,9 @@ void GLToolbar::get_additional_tooltip(unsigned int item_id, std::string& text)
|
||||
text = L("");
|
||||
}
|
||||
|
||||
void GLToolbar::set_additional_tooltip(unsigned int item_id, const std::string& text)
|
||||
void GLToolbar::set_additional_tooltip(int item_id, const std::string& text)
|
||||
{
|
||||
if (item_id < (unsigned int)m_items.size())
|
||||
if ((0 <= item_id) && (item_id < (int)m_items.size()))
|
||||
{
|
||||
GLToolbarItem* item = m_items[item_id];
|
||||
if (item != nullptr)
|
||||
@ -466,7 +456,7 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
|
||||
{
|
||||
// mouse is inside an icon
|
||||
do_action(GLToolbarItem::Left, (unsigned int)item_id, parent, true);
|
||||
do_action(GLToolbarItem::Left, item_id, parent, true);
|
||||
parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
@ -483,7 +473,7 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
|
||||
{
|
||||
// mouse is inside an icon
|
||||
do_action(GLToolbarItem::Right, (unsigned int)item_id, parent, true);
|
||||
do_action(GLToolbarItem::Right, item_id, parent, true);
|
||||
parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
@ -556,11 +546,11 @@ float GLToolbar::get_main_size() const
|
||||
return size * m_layout.scale;
|
||||
}
|
||||
|
||||
void GLToolbar::do_action(GLToolbarItem::EActionType type, unsigned int item_id, GLCanvas3D& parent, bool check_hover)
|
||||
void GLToolbar::do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover)
|
||||
{
|
||||
if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id))
|
||||
{
|
||||
if (item_id < (unsigned int)m_items.size())
|
||||
if ((0 <= item_id) && (item_id < (int)m_items.size()))
|
||||
{
|
||||
GLToolbarItem* item = m_items[item_id];
|
||||
if ((item != nullptr) && !item->is_separator() && (!check_hover || item->is_hovered()))
|
||||
@ -1246,7 +1236,7 @@ bool GLToolbar::update_items_enabled_state()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
for (int i = 0; i < (int)m_items.size(); ++i)
|
||||
{
|
||||
GLToolbarItem* item = m_items[i];
|
||||
ret |= item->update_enabled_state();
|
||||
|
@ -254,7 +254,7 @@ private:
|
||||
|
||||
MouseCapture m_mouse_capture;
|
||||
std::string m_tooltip;
|
||||
unsigned int m_pressed_toggable_id;
|
||||
int m_pressed_toggable_id;
|
||||
|
||||
public:
|
||||
GLToolbar(EType type, const std::string& name);
|
||||
@ -293,15 +293,15 @@ public:
|
||||
|
||||
bool is_any_item_pressed() const;
|
||||
|
||||
unsigned int get_item_id(const std::string& name) const;
|
||||
int get_item_id(const std::string& name) const;
|
||||
|
||||
void force_left_action(unsigned int item_id, GLCanvas3D& parent);
|
||||
void force_right_action(unsigned int item_id, GLCanvas3D& parent);
|
||||
void force_left_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Left, item_id, parent, false); }
|
||||
void force_right_action(int item_id, GLCanvas3D& parent) { do_action(GLToolbarItem::Right, item_id, parent, false); }
|
||||
|
||||
const std::string& get_tooltip() const { return m_tooltip; }
|
||||
|
||||
void get_additional_tooltip(unsigned int item_id, std::string& text);
|
||||
void set_additional_tooltip(unsigned int item_id, const std::string& text);
|
||||
void get_additional_tooltip(int item_id, std::string& text);
|
||||
void set_additional_tooltip(int item_id, const std::string& text);
|
||||
|
||||
// returns true if any item changed its state
|
||||
bool update_items_state();
|
||||
@ -317,7 +317,7 @@ private:
|
||||
float get_height_horizontal() const;
|
||||
float get_height_vertical() const;
|
||||
float get_main_size() const;
|
||||
void do_action(GLToolbarItem::EActionType type, unsigned int item_id, GLCanvas3D& parent, bool check_hover);
|
||||
void do_action(GLToolbarItem::EActionType type, int item_id, GLCanvas3D& parent, bool check_hover);
|
||||
std::string update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
std::string update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
std::string update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
|
@ -262,7 +262,7 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
||||
}
|
||||
catch (const std::exception & /* e */)
|
||||
{
|
||||
int i = 0;//no reason, just experiment
|
||||
// int i = 0;//no reason, just experiment
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,8 +302,9 @@ bool GUI_App::on_init_inner()
|
||||
* change min hight of object list to the normal min value (15 * wxGetApp().em_unit())
|
||||
* after first whole Mainframe updating/layouting
|
||||
*/
|
||||
if (obj_list()->GetMinSize().GetY() > 15 * em_unit())
|
||||
obj_list()->SetMinSize(wxSize(-1, 15 * em_unit()));
|
||||
const int list_min_height = 15 * em_unit();
|
||||
if (obj_list()->GetMinSize().GetY() > list_min_height)
|
||||
obj_list()->SetMinSize(wxSize(-1, list_min_height));
|
||||
|
||||
update_mode(); // update view mode after fix of the object_list size
|
||||
|
||||
@ -474,8 +475,9 @@ void GUI_App::recreate_GUI()
|
||||
* change min hight of object list to the normal min value (15 * wxGetApp().em_unit())
|
||||
* after first whole Mainframe updating/layouting
|
||||
*/
|
||||
if (obj_list()->GetMinSize().GetY() > 15 * em_unit())
|
||||
obj_list()->SetMinSize(wxSize(-1, 15 * em_unit()));
|
||||
const int list_min_height = 15 * em_unit();
|
||||
if (obj_list()->GetMinSize().GetY() > list_min_height)
|
||||
obj_list()->SetMinSize(wxSize(-1, list_min_height));
|
||||
|
||||
update_mode();
|
||||
|
||||
@ -908,11 +910,13 @@ bool GUI_App::check_unsaved_changes(const wxString &header)
|
||||
wxString dirty;
|
||||
PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
for (Tab *tab : tabs_list)
|
||||
if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty())
|
||||
if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty()) {
|
||||
if (dirty.empty())
|
||||
dirty = tab->title();
|
||||
else
|
||||
dirty += wxString(", ") + tab->title();
|
||||
}
|
||||
|
||||
if (dirty.empty())
|
||||
// No changes, the application may close or reload presets.
|
||||
return true;
|
||||
@ -1085,7 +1089,7 @@ void GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &na
|
||||
|
||||
void GUI_App::window_pos_sanitize(wxTopLevelWindow* window)
|
||||
{
|
||||
unsigned display_idx = wxDisplay::GetFromWindow(window);
|
||||
/*unsigned*/int display_idx = wxDisplay::GetFromWindow(window);
|
||||
wxRect display;
|
||||
if (display_idx == wxNOT_FOUND) {
|
||||
display = wxDisplay(0u).GetClientArea();
|
||||
|
@ -29,7 +29,7 @@ namespace GUI
|
||||
wxDEFINE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
|
||||
|
||||
// pt_FFF
|
||||
SettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
|
||||
static SettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
|
||||
{
|
||||
{ L("Layers and Perimeters"), { "layer_height" , "perimeters", "top_solid_layers", "bottom_solid_layers" } },
|
||||
{ L("Infill") , { "fill_density", "fill_pattern" } },
|
||||
@ -40,13 +40,13 @@ SettingsBundle FREQ_SETTINGS_BUNDLE_FFF =
|
||||
};
|
||||
|
||||
// pt_SLA
|
||||
SettingsBundle FREQ_SETTINGS_BUNDLE_SLA =
|
||||
static SettingsBundle FREQ_SETTINGS_BUNDLE_SLA =
|
||||
{
|
||||
{ L("Pad and Support") , { "supports_enable", "pad_enable" } }
|
||||
};
|
||||
|
||||
// Note: id accords to type of the sub-object (adding volume), so sequence of the menu items is important
|
||||
std::vector<std::pair<std::string, std::string>> ADD_VOLUME_MENU_ITEMS = {
|
||||
static std::vector<std::pair<std::string, std::string>> ADD_VOLUME_MENU_ITEMS = {
|
||||
// menu_item Name menu_item bitmap name
|
||||
{L("Add part"), "add_part" }, // ~ModelVolumeType::MODEL_PART
|
||||
{L("Add modifier"), "add_modifier"}, // ~ModelVolumeType::PARAMETER_MODIFIER
|
||||
@ -126,7 +126,7 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||
#ifdef __WXMSW__
|
||||
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
|
||||
int new_selected_column = -1;
|
||||
#endif __WXMSW__
|
||||
#endif //__WXMSW__
|
||||
if (wxGetKeyState(WXK_SHIFT))
|
||||
{
|
||||
wxDataViewItemArray sels;
|
||||
@ -149,12 +149,12 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||
wxUIActionSimulator sim;
|
||||
sim.Char(WXK_RETURN);
|
||||
}
|
||||
#endif __WXMSW__
|
||||
#endif //__WXMSW__
|
||||
m_last_selected_item = new_selected_item;
|
||||
}
|
||||
#ifdef __WXMSW__
|
||||
m_last_selected_column = new_selected_column;
|
||||
#endif __WXMSW__
|
||||
#endif //__WXMSW__
|
||||
|
||||
selection_changed();
|
||||
#ifndef __WXMSW__
|
||||
@ -192,7 +192,7 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->undo(); }, wxID_UNDO);
|
||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->redo(); }, wxID_REDO);
|
||||
}
|
||||
#else __WXOSX__
|
||||
#else //__WXOSX__
|
||||
Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
|
||||
#endif
|
||||
|
||||
@ -281,9 +281,9 @@ void ObjectList::create_popup_menus()
|
||||
create_instance_popupmenu(&m_menu_instance);
|
||||
}
|
||||
|
||||
void ObjectList::get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& input_item/* = wxDataViewItem(0)*/)
|
||||
void ObjectList::get_selected_item_indexes(int& obj_idx, int& vol_idx, const wxDataViewItem& input_item/* = wxDataViewItem(nullptr)*/)
|
||||
{
|
||||
const wxDataViewItem item = input_item == wxDataViewItem(0) ? GetSelection() : input_item;
|
||||
const wxDataViewItem item = input_item == wxDataViewItem(nullptr) ? GetSelection() : input_item;
|
||||
|
||||
if (!item)
|
||||
{
|
||||
@ -737,7 +737,7 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol
|
||||
if (items.size() > 1)
|
||||
{
|
||||
m_selection_mode = smVolume;
|
||||
m_last_selected_item = wxDataViewItem(0);
|
||||
m_last_selected_item = wxDataViewItem(nullptr);
|
||||
}
|
||||
|
||||
select_items(items);
|
||||
@ -844,7 +844,7 @@ void ObjectList::show_context_menu()
|
||||
|
||||
wxMenu* menu = type & itInstance ? &m_menu_instance :
|
||||
type & itLayer ? &m_menu_layer :
|
||||
m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part :
|
||||
m_objects_model->GetParent(item) != wxDataViewItem(nullptr) ? &m_menu_part :
|
||||
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
|
||||
|
||||
if (!(type & itInstance))
|
||||
@ -915,9 +915,9 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
|
||||
|
||||
const bool mult_sel = multiple_selection();
|
||||
|
||||
if (mult_sel && !selected_instances_of_same_object() ||
|
||||
!mult_sel && (GetSelection() != item ||
|
||||
m_objects_model->GetParent(item) == wxDataViewItem(0) ) ) {
|
||||
if ((mult_sel && !selected_instances_of_same_object()) ||
|
||||
(!mult_sel && (GetSelection() != item)) ||
|
||||
m_objects_model->GetParent(item) == wxDataViewItem(nullptr) ) {
|
||||
event.Veto();
|
||||
return;
|
||||
}
|
||||
@ -962,10 +962,10 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
|
||||
|
||||
bool ObjectList::can_drop(const wxDataViewItem& item) const
|
||||
{
|
||||
return m_dragged_data.type() == itInstance && !item.IsOk() ||
|
||||
m_dragged_data.type() == itVolume && item.IsOk() &&
|
||||
return (m_dragged_data.type() == itInstance && !item.IsOk()) ||
|
||||
(m_dragged_data.type() == itVolume && item.IsOk() &&
|
||||
m_objects_model->GetItemType(item) == itVolume &&
|
||||
m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item);
|
||||
m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item));
|
||||
}
|
||||
|
||||
void ObjectList::OnDropPossible(wxDataViewEvent &event)
|
||||
@ -1331,7 +1331,7 @@ void ObjectList::append_menu_items_add_volume(wxMenu* menu)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int type = mode == comExpert ? 0 : 1 ; type < ADD_VOLUME_MENU_ITEMS.size(); type++)
|
||||
for (size_t type = (mode == comExpert ? 0 : 1) ; type < ADD_VOLUME_MENU_ITEMS.size(); type++)
|
||||
{
|
||||
auto& item = ADD_VOLUME_MENU_ITEMS[type];
|
||||
|
||||
@ -1402,7 +1402,7 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
|
||||
// Create new items for settings popupmenu
|
||||
|
||||
if (printer_technology() == ptFFF ||
|
||||
menu->GetMenuItems().size() > 0 && !menu->GetMenuItems().back()->IsSeparator())
|
||||
(menu->GetMenuItems().size() > 0 && !menu->GetMenuItems().back()->IsSeparator()))
|
||||
menu->SetFirstSeparator();
|
||||
|
||||
// Add frequently settings
|
||||
@ -1435,9 +1435,9 @@ wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWind
|
||||
[this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent);
|
||||
}
|
||||
|
||||
wxMenuItem* ObjectList::append_menu_item_printable(wxMenu* menu, wxWindow* parent)
|
||||
wxMenuItem* ObjectList::append_menu_item_printable(wxMenu* menu, wxWindow* /*parent*/)
|
||||
{
|
||||
return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [this](wxCommandEvent&) {
|
||||
return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [](wxCommandEvent&) {
|
||||
wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state();
|
||||
}, menu);
|
||||
}
|
||||
@ -1510,7 +1510,7 @@ void ObjectList::append_menu_item_delete(wxMenu* menu)
|
||||
void ObjectList::append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu)
|
||||
{
|
||||
append_menu_item(menu, wxID_ANY, _(L("Scale to print volume")), _(L("Scale the selected object to fit the print volume")),
|
||||
[this](wxCommandEvent&) { wxGetApp().plater()->scale_selection_to_fit_print_volume(); }, "", menu);
|
||||
[](wxCommandEvent&) { wxGetApp().plater()->scale_selection_to_fit_print_volume(); }, "", menu);
|
||||
}
|
||||
|
||||
void ObjectList::create_object_popupmenu(wxMenu *menu)
|
||||
@ -1576,7 +1576,7 @@ void ObjectList::create_instance_popupmenu(wxMenu*menu)
|
||||
* 2. Separate selected instances from the initial object to the separated object,
|
||||
* if some (not all) instances are selected
|
||||
*/
|
||||
wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) {
|
||||
wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) {
|
||||
// evt.Enable(can_split_instances()); }, m_menu_item_split_instances->GetId());
|
||||
evt.SetText(wxGetApp().plater()->canvas3D()->get_selection().is_single_full_object() ?
|
||||
_(L("Set as a Separated Objects")) : _(L("Set as a Separated Object")));
|
||||
@ -1588,7 +1588,7 @@ wxMenu* ObjectList::create_settings_popupmenu(wxMenu *parent_menu)
|
||||
wxMenu *menu = new wxMenu;
|
||||
|
||||
settings_menu_hierarchy settings_menu;
|
||||
const bool is_part = m_objects_model->GetParent(GetSelection()) != wxDataViewItem(0);
|
||||
const bool is_part = m_objects_model->GetParent(GetSelection()) != wxDataViewItem(nullptr);
|
||||
get_options_menu(settings_menu, is_part);
|
||||
|
||||
for (auto cat : settings_menu) {
|
||||
@ -1681,7 +1681,7 @@ void ObjectList::load_part( ModelObject* model_object,
|
||||
|
||||
wxArrayString input_files;
|
||||
wxGetApp().import_model(parent, input_files);
|
||||
for (int i = 0; i < input_files.size(); ++i) {
|
||||
for (size_t i = 0; i < input_files.size(); ++i) {
|
||||
std::string input_file = input_files.Item(i).ToUTF8().data();
|
||||
|
||||
Model model;
|
||||
@ -1719,7 +1719,7 @@ void ObjectList::load_part( ModelObject* model_object,
|
||||
|
||||
void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type)
|
||||
{
|
||||
const auto obj_idx = get_selected_obj_idx();
|
||||
const int obj_idx = get_selected_obj_idx();
|
||||
if (obj_idx < 0)
|
||||
return;
|
||||
|
||||
@ -1852,9 +1852,9 @@ void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
|
||||
{
|
||||
const bool is_layer_settings = m_objects_model->GetItemType(parent_item) == itLayer;
|
||||
|
||||
const int opt_cnt = m_config->keys().size();
|
||||
if (opt_cnt == 1 && m_config->has("extruder") ||
|
||||
is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height"))
|
||||
const size_t opt_cnt = m_config->keys().size();
|
||||
if ((opt_cnt == 1 && m_config->has("extruder")) ||
|
||||
(is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height")))
|
||||
return;
|
||||
|
||||
take_snapshot(_(L("Delete Settings")));
|
||||
@ -2052,13 +2052,13 @@ wxDataViewItem ObjectList::add_layer_root_item(const wxDataViewItem obj_item)
|
||||
if (obj_idx < 0 ||
|
||||
object(obj_idx)->layer_config_ranges.empty() ||
|
||||
printer_technology() == ptSLA)
|
||||
return wxDataViewItem(0);
|
||||
return wxDataViewItem(nullptr);
|
||||
|
||||
// create LayerRoot item
|
||||
wxDataViewItem layers_item = m_objects_model->AddLayersRoot(obj_item);
|
||||
|
||||
// and create Layer item(s) according to the layer_config_ranges
|
||||
for (const auto range : object(obj_idx)->layer_config_ranges)
|
||||
for (const auto& range : object(obj_idx)->layer_config_ranges)
|
||||
add_layer_item(range.first, layers_item);
|
||||
|
||||
Expand(layers_item);
|
||||
@ -2150,7 +2150,7 @@ void ObjectList::part_selection_changed()
|
||||
|
||||
const auto item = GetSelection();
|
||||
|
||||
if ( multiple_selection() || item && m_objects_model->GetItemType(item) == itInstanceRoot )
|
||||
if ( multiple_selection() || (item && m_objects_model->GetItemType(item) == itInstanceRoot ))
|
||||
{
|
||||
og_name = _(L("Group manipulation"));
|
||||
|
||||
@ -2162,7 +2162,7 @@ void ObjectList::part_selection_changed()
|
||||
{
|
||||
if (item)
|
||||
{
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(nullptr)) {
|
||||
obj_idx = m_objects_model->GetIdByItem(item);
|
||||
og_name = _(L("Object manipulation"));
|
||||
m_config = &(*m_objects)[obj_idx]->config;
|
||||
@ -2281,7 +2281,7 @@ SettingsBundle ObjectList::get_item_settings_bundle(const DynamicPrintConfig* co
|
||||
// Add new SettingsItem for parent_item if it doesn't exist, or just update a digest according to new config
|
||||
wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const DynamicPrintConfig* config)
|
||||
{
|
||||
wxDataViewItem ret = wxDataViewItem(0);
|
||||
wxDataViewItem ret = wxDataViewItem(nullptr);
|
||||
|
||||
if (!parent_item)
|
||||
return ret;
|
||||
@ -2337,7 +2337,7 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
|
||||
if (model_object->instances.size()>1)
|
||||
{
|
||||
std::vector<bool> print_idicator(model_object->instances.size());
|
||||
for (int i = 0; i < model_object->instances.size(); ++i)
|
||||
for (size_t i = 0; i < model_object->instances.size(); ++i)
|
||||
print_idicator[i] = model_object->instances[i]->printable;
|
||||
|
||||
const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
|
||||
@ -2364,7 +2364,7 @@ void ObjectList::delete_object_from_list()
|
||||
auto item = GetSelection();
|
||||
if (!item)
|
||||
return;
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(nullptr))
|
||||
select_item(m_objects_model->Delete(item));
|
||||
else
|
||||
select_item(m_objects_model->Delete(m_objects_model->GetParent(item)));
|
||||
@ -2521,7 +2521,7 @@ void ObjectList::remove()
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
|
||||
wxDataViewItem parent = wxDataViewItem(0);
|
||||
wxDataViewItem parent = wxDataViewItem(nullptr);
|
||||
|
||||
if (sels.Count() == 1)
|
||||
parent = delete_item(GetSelection());
|
||||
@ -2588,7 +2588,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
|
||||
{
|
||||
take_snapshot(_(L("Add Height Range")));
|
||||
|
||||
const t_layer_height_range& new_range = { last_range.second, last_range.second + 2.0f };
|
||||
const t_layer_height_range& new_range = { last_range.second, last_range.second + 2. };
|
||||
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||
add_layer_item(new_range, layers_item);
|
||||
}
|
||||
@ -2611,7 +2611,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
|
||||
if (delta < get_min_layer_height(old_config.opt_int("extruder"))/*0.05f*/) // next range division has no sense
|
||||
return;
|
||||
|
||||
const coordf_t midl_layer = next_range.first + 0.5f * delta;
|
||||
const coordf_t midl_layer = next_range.first + 0.5 * delta;
|
||||
|
||||
t_layer_height_range new_range = { midl_layer, next_range.second };
|
||||
|
||||
@ -2711,7 +2711,7 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
|
||||
|
||||
if (root_item.IsOk())
|
||||
// create Layer item(s) according to the layer_config_ranges
|
||||
for (const auto r : ranges)
|
||||
for (const auto& r : ranges)
|
||||
add_layer_item(r.first, root_item);
|
||||
|
||||
select_item(sel_type&itLayer ? m_objects_model->GetItemByLayerRange(obj_idx, new_range) : root_item);
|
||||
@ -3028,7 +3028,7 @@ void ObjectList::select_item_all_children()
|
||||
|
||||
// There is no selection before OR some object is selected => select all objects
|
||||
if (!GetSelection() || m_objects_model->GetItemType(GetSelection()) == itObject) {
|
||||
for (int i = 0; i < m_objects->size(); i++)
|
||||
for (size_t i = 0; i < m_objects->size(); i++)
|
||||
sels.Add(m_objects_model->GetItemById(i));
|
||||
m_selection_mode = smInstance;
|
||||
}
|
||||
@ -3054,7 +3054,7 @@ void ObjectList::update_selection_mode()
|
||||
// All items are unselected
|
||||
if (!GetSelection())
|
||||
{
|
||||
m_last_selected_item = wxDataViewItem(0);
|
||||
m_last_selected_item = wxDataViewItem(nullptr);
|
||||
m_selection_mode = smUndef;
|
||||
return;
|
||||
}
|
||||
@ -3096,9 +3096,9 @@ bool ObjectList::check_last_selection(wxString& msg_str)
|
||||
if (impossible_multi_selection(itVolume, smVolume) ||
|
||||
impossible_multi_selection(itLayer, smLayer ) ||
|
||||
type & itSettings ||
|
||||
type & itVolume && !(m_selection_mode & smVolume ) ||
|
||||
type & itLayer && !(m_selection_mode & smLayer ) ||
|
||||
type & itInstance && !(m_selection_mode & smInstance)
|
||||
(type & itVolume && !(m_selection_mode & smVolume )) ||
|
||||
(type & itLayer && !(m_selection_mode & smLayer )) ||
|
||||
(type & itInstance && !(m_selection_mode & smInstance))
|
||||
)
|
||||
{
|
||||
// Inform user why selection isn't complited
|
||||
@ -3151,7 +3151,7 @@ void ObjectList::fix_multiselection_conflicts()
|
||||
|
||||
const ItemType item_type = m_selection_mode & smVolume ? itVolume : itLayer;
|
||||
|
||||
for (const auto child : children)
|
||||
for (const auto& child : children)
|
||||
if (IsSelected(child) && m_objects_model->GetItemType(child) & item_type)
|
||||
sels.Add(child);
|
||||
|
||||
@ -3161,7 +3161,7 @@ void ObjectList::fix_multiselection_conflicts()
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto item : sels)
|
||||
for (const auto& item : sels)
|
||||
{
|
||||
if (!IsSelected(item)) // if this item is unselected now (from previous actions)
|
||||
continue;
|
||||
@ -3172,13 +3172,13 @@ void ObjectList::fix_multiselection_conflicts()
|
||||
}
|
||||
|
||||
const wxDataViewItem& parent = m_objects_model->GetParent(item);
|
||||
if (parent != wxDataViewItem(0) && IsSelected(parent))
|
||||
if (parent != wxDataViewItem(nullptr) && IsSelected(parent))
|
||||
Unselect(parent);
|
||||
else
|
||||
{
|
||||
wxDataViewItemArray unsels;
|
||||
m_objects_model->GetAllChildren(item, unsels);
|
||||
for (const auto unsel_item : unsels)
|
||||
for (const auto& unsel_item : unsels)
|
||||
Unselect(unsel_item);
|
||||
}
|
||||
|
||||
@ -3193,7 +3193,7 @@ void ObjectList::fix_multiselection_conflicts()
|
||||
show_info(this, msg_string, _(L("Info")));
|
||||
|
||||
if (!IsSelected(m_last_selected_item))
|
||||
m_last_selected_item = wxDataViewItem(0);
|
||||
m_last_selected_item = wxDataViewItem(nullptr);
|
||||
|
||||
m_prevent_list_events = false;
|
||||
}
|
||||
@ -3334,7 +3334,7 @@ void ObjectList::update_object_list_by_printer_technology()
|
||||
GetSelections(sel); // stash selection
|
||||
|
||||
wxDataViewItemArray object_items;
|
||||
m_objects_model->GetChildren(wxDataViewItem(0), object_items);
|
||||
m_objects_model->GetChildren(wxDataViewItem(nullptr), object_items);
|
||||
|
||||
for (auto& object_item : object_items) {
|
||||
// Update Settings Item for object
|
||||
@ -3405,7 +3405,7 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set
|
||||
|
||||
// create new object from selected instance
|
||||
ModelObject* model_object = (*m_objects)[obj_idx]->get_model()->add_object(*(*m_objects)[obj_idx]);
|
||||
for (int inst_idx = model_object->instances.size() - 1; inst_idx >= 0; inst_idx--)
|
||||
for (int inst_idx = int(model_object->instances.size()) - 1; inst_idx >= 0; inst_idx--)
|
||||
{
|
||||
if (find(inst_idxs.begin(), inst_idxs.end(), inst_idx) != inst_idxs.end())
|
||||
continue;
|
||||
@ -3599,7 +3599,7 @@ void ObjectList::OnEditingStarted(wxDataViewEvent &event)
|
||||
{
|
||||
m_last_selected_column = -1;
|
||||
}
|
||||
#endif __WXMSW__
|
||||
#endif //__WXMSW__
|
||||
|
||||
void ObjectList::OnEditingDone(wxDataViewEvent &event)
|
||||
{
|
||||
@ -3618,7 +3618,7 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event)
|
||||
// Workaround for entering the column editing mode on Windows. Simulate keyboard enter when another column of the active line is selected.
|
||||
// Here the last active column is forgotten, so when leaving the editing mode, the next mouse click will not enter the editing mode of the newly selected column.
|
||||
m_last_selected_column = -1;
|
||||
#endif __WXMSW__
|
||||
#endif //__WXMSW__
|
||||
}
|
||||
|
||||
void ObjectList::show_multi_selection_menu()
|
||||
|
@ -116,7 +116,7 @@ bool ObjectSettings::update_settings_list()
|
||||
|
||||
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
||||
optgroup->label_width = 15;
|
||||
optgroup->sidetext_width = 5.5;
|
||||
optgroup->sidetext_width = 5;
|
||||
|
||||
optgroup->m_on_change = [this, config](const t_config_option_key& opt_id, const boost::any& value) {
|
||||
this->update_config_values(config);
|
||||
@ -241,4 +241,4 @@ void ObjectSettings::msw_rescale()
|
||||
}
|
||||
|
||||
} //namespace GUI
|
||||
} //namespace Slic3r
|
||||
} //namespace Slic3r
|
||||
|
@ -5,11 +5,11 @@
|
||||
#include <vector>
|
||||
#include <wx/panel.h>
|
||||
#include "wxExtensions.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
class wxBoxSizer;
|
||||
|
||||
namespace Slic3r {
|
||||
class DynamicPrintConfig;
|
||||
namespace GUI {
|
||||
class ConfigOptionsGroup;
|
||||
|
||||
|
@ -640,9 +640,10 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
|
||||
bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min();
|
||||
bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max();
|
||||
|
||||
std::vector<std::pair<int, double>> values;
|
||||
fill_slider_values(values, layers_z);
|
||||
m_slider->SetSliderValues(values);
|
||||
std::vector<double> &ticks_from_config = (wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights"))->values;
|
||||
check_slider_values(ticks_from_config, layers_z);
|
||||
|
||||
m_slider->SetSliderValues(layers_z);
|
||||
assert(m_slider->GetMinValue() == 0);
|
||||
m_slider->SetMaxValue(layers_z.empty() ? 0 : layers_z.size() - 1);
|
||||
|
||||
@ -662,9 +663,6 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
|
||||
}
|
||||
m_slider->SetSelectionSpan(idx_low, idx_high);
|
||||
|
||||
const auto& config = wxGetApp().preset_bundle->project_config;
|
||||
const std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
|
||||
|
||||
m_slider->SetTicksValues(ticks_from_config);
|
||||
|
||||
bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF);
|
||||
@ -676,26 +674,18 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
|
||||
m_slider->EnableTickManipulation(color_print_enable);
|
||||
}
|
||||
|
||||
void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,
|
||||
void Preview::check_slider_values(std::vector<double>& ticks_from_config,
|
||||
const std::vector<double> &layers_z)
|
||||
{
|
||||
values.clear();
|
||||
for (int i = 0; i < layers_z.size(); ++i)
|
||||
{
|
||||
values.push_back(std::pair<int, double>(i + 1, layers_z[i]));
|
||||
}
|
||||
|
||||
// All ticks that would end up outside the slider range should be erased.
|
||||
// TODO: this should be placed into more appropriate part of code,
|
||||
// this function is e.g. not called when the last object is deleted
|
||||
std::vector<double> &ticks_from_config = (wxGetApp().preset_bundle->project_config.option<ConfigOptionFloats>("colorprint_heights"))->values;
|
||||
unsigned int old_size = ticks_from_config.size();
|
||||
ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(),
|
||||
[values](double val)
|
||||
[layers_z](double val)
|
||||
{
|
||||
return (values.back().second < val &&
|
||||
// we can't ignore tick on last layer
|
||||
fabs(values.back().second - val) > DoubleSlider::epsilon());
|
||||
auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val - DoubleSlider::epsilon());
|
||||
return it == layers_z.end();
|
||||
}),
|
||||
ticks_from_config.end());
|
||||
if (ticks_from_config.size() != old_size)
|
||||
|
@ -155,7 +155,7 @@ private:
|
||||
// Create/Update/Reset double slider on 3dPreview
|
||||
void create_double_slider();
|
||||
void update_double_slider(const std::vector<double>& layers_z, bool keep_z_range = false);
|
||||
void fill_slider_values(std::vector<std::pair<int, double>> &values,
|
||||
void check_slider_values(std::vector<double> &ticks_from_config,
|
||||
const std::vector<double> &layers_z);
|
||||
void reset_double_slider();
|
||||
// update DoubleSlider after keyDown in canvas
|
||||
|
@ -69,7 +69,6 @@ public:
|
||||
enum EState
|
||||
{
|
||||
Off,
|
||||
Hover,
|
||||
On,
|
||||
Num_States
|
||||
};
|
||||
|
@ -44,12 +44,12 @@ public:
|
||||
Vec3d get_flattening_normal() const;
|
||||
|
||||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable() const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
virtual bool on_is_activable() const override;
|
||||
virtual void on_start_dragging() override;
|
||||
virtual void on_render() const override;
|
||||
virtual void on_render_for_picking() const override;
|
||||
virtual void on_set_state() override;
|
||||
};
|
||||
|
||||
|
@ -87,16 +87,12 @@ protected:
|
||||
virtual void on_set_state()
|
||||
{
|
||||
for (GLGizmoRotate& g : m_gizmos)
|
||||
{
|
||||
g.set_state(m_state);
|
||||
}
|
||||
}
|
||||
virtual void on_set_hover_id()
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
|
||||
}
|
||||
}
|
||||
virtual void on_enable_grabber(unsigned int id)
|
||||
{
|
||||
|
@ -329,6 +329,7 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
||||
case X: { local_offset_vec = local_offset * Vec3d::UnitX(); break; }
|
||||
case Y: { local_offset_vec = local_offset * Vec3d::UnitY(); break; }
|
||||
case Z: { local_offset_vec = local_offset * Vec3d::UnitZ(); break; }
|
||||
default: break;
|
||||
}
|
||||
|
||||
m_offset = m_offsets_transform * local_offset_vec;
|
||||
|
@ -12,7 +12,9 @@
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectSettings.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/PresetBundle.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/Tesselate.hpp"
|
||||
|
||||
|
||||
@ -306,7 +308,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
||||
}
|
||||
else {
|
||||
render_color[3] = 1.f;
|
||||
if ((m_hover_id == i && m_editing_mode)) { // ignore hover state unless editing mode is active
|
||||
if ((size_t(m_hover_id) == i && m_editing_mode)) { // ignore hover state unless editing mode is active
|
||||
render_color[0] = 0.f;
|
||||
render_color[1] = 1.0f;
|
||||
render_color[2] = 1.0f;
|
||||
@ -328,7 +330,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
||||
|
||||
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(support_point.pos(0), support_point.pos(1), support_point.pos(2)));
|
||||
glsafe(::glTranslatef(support_point.pos(0), support_point.pos(1), support_point.pos(2)));
|
||||
glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data()));
|
||||
|
||||
if (vol->is_left_handed())
|
||||
@ -345,16 +347,16 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
||||
Eigen::AngleAxisd aa(q);
|
||||
glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)));
|
||||
|
||||
const float cone_radius = 0.25f; // mm
|
||||
const float cone_height = 0.75f;
|
||||
const double cone_radius = 0.25; // mm
|
||||
const double cone_height = 0.75;
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslatef(0.f, 0.f, support_point.head_front_radius * RenderPointScale));
|
||||
::gluCylinder(m_quadric, 0.f, cone_radius, cone_height, 24, 1);
|
||||
::gluCylinder(m_quadric, 0., cone_radius, cone_height, 24, 1);
|
||||
glsafe(::glTranslatef(0.f, 0.f, cone_height));
|
||||
::gluDisk(m_quadric, 0.0, cone_radius, 24, 1);
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
::gluSphere(m_quadric, support_point.head_front_radius * RenderPointScale, 24, 12);
|
||||
::gluSphere(m_quadric, (double)support_point.head_front_radius * RenderPointScale, 24, 12);
|
||||
if (vol->is_left_handed())
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
@ -775,7 +777,7 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::update_cache_entry_normal(unsigned int i) const
|
||||
void GLGizmoSlaSupports::update_cache_entry_normal(size_t i) const
|
||||
{
|
||||
int idx = 0;
|
||||
Eigen::Matrix<float, 1, 3> pp = m_editing_cache[i].support_point.pos;
|
||||
@ -1098,9 +1100,6 @@ std::string GLGizmoSlaSupports::on_get_name() const
|
||||
|
||||
void GLGizmoSlaSupports::on_set_state()
|
||||
{
|
||||
if (m_state == Hover)
|
||||
return;
|
||||
|
||||
// m_model_object pointer can be invalid (for instance because of undo/redo action),
|
||||
// we should recover it from the object id
|
||||
m_model_object = nullptr;
|
||||
@ -1111,6 +1110,9 @@ void GLGizmoSlaSupports::on_set_state()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state == m_old_state)
|
||||
return;
|
||||
|
||||
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
|
||||
if (is_mesh_update_necessary())
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "slic3r/GUI/I18N.hpp" // ...and redefine again when we are done with the igl code
|
||||
|
||||
#include "libslic3r/SLA/SLACommon.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include <wx/dialog.h>
|
||||
|
||||
#include <cereal/types/vector.hpp>
|
||||
@ -31,7 +30,7 @@ private:
|
||||
ObjectID m_model_object_id = 0;
|
||||
int m_active_instance = -1;
|
||||
float m_active_instance_bb_radius; // to cache the bb
|
||||
mutable float m_z_shift = 0.f;
|
||||
mutable double m_z_shift = 0.f;
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
|
||||
|
||||
const float RenderPointScale = 1.f;
|
||||
@ -78,7 +77,7 @@ private:
|
||||
|
||||
public:
|
||||
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
virtual ~GLGizmoSlaSupports();
|
||||
~GLGizmoSlaSupports() override;
|
||||
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
void delete_selected_points(bool force = false);
|
||||
@ -90,21 +89,19 @@ public:
|
||||
void reslice_SLA_supports(bool postpone_error_messages = false) const;
|
||||
|
||||
private:
|
||||
bool on_init();
|
||||
void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
bool on_init() override;
|
||||
void on_update(const UpdateData& data) override;
|
||||
void on_render() const override;
|
||||
void on_render_for_picking() const override;
|
||||
|
||||
//void render_selection_rectangle() const;
|
||||
void render_points(const Selection& selection, bool picking = false) const;
|
||||
void render_clipping_plane(const Selection& selection) const;
|
||||
bool is_mesh_update_necessary() const;
|
||||
void update_mesh();
|
||||
void update_cache_entry_normal(unsigned int i) const;
|
||||
void update_cache_entry_normal(size_t i) const;
|
||||
bool unsaved_changes() const;
|
||||
|
||||
EState m_no_hover_state = Off;
|
||||
EState m_no_hover_old_state = Off;
|
||||
bool m_lock_unique_islands = false;
|
||||
bool m_editing_mode = false; // Is editing mode active?
|
||||
bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes).
|
||||
@ -157,20 +154,21 @@ private:
|
||||
|
||||
protected:
|
||||
void on_set_state() override;
|
||||
virtual void on_set_hover_id()
|
||||
void on_set_hover_id() override
|
||||
|
||||
{
|
||||
if (! m_editing_mode || (int)m_editing_cache.size() <= m_hover_id)
|
||||
m_hover_id = -1;
|
||||
}
|
||||
void on_start_dragging() override;
|
||||
void on_stop_dragging() override;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable() const;
|
||||
virtual bool on_is_selectable() const;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) override;
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const override;
|
||||
std::string on_get_name() const override;
|
||||
bool on_is_activable() const override;
|
||||
bool on_is_selectable() const override;
|
||||
void on_load(cereal::BinaryInputArchive& ar) override;
|
||||
void on_save(cereal::BinaryOutputArchive& ar) const override;
|
||||
};
|
||||
|
||||
|
||||
|
@ -29,9 +29,49 @@ GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
|
||||
{
|
||||
}
|
||||
|
||||
GLGizmosManager::~GLGizmosManager()
|
||||
std::vector<size_t> GLGizmosManager::get_selectable_idxs() const
|
||||
{
|
||||
reset();
|
||||
std::vector<size_t> out;
|
||||
for (size_t i=0; i<m_gizmos.size(); ++i)
|
||||
if (m_gizmos[i]->is_selectable())
|
||||
out.push_back(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<size_t> GLGizmosManager::get_activable_idxs() const
|
||||
{
|
||||
std::vector<size_t> out;
|
||||
for (size_t i=0; i<m_gizmos.size(); ++i)
|
||||
if (m_gizmos[i]->is_activable())
|
||||
out.push_back(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
|
||||
{
|
||||
if (! m_enabled)
|
||||
return Undefined;
|
||||
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float top_y = 0.5f * (cnv_h - height) + scaled_border;
|
||||
|
||||
// is mouse horizontally in the area?
|
||||
if ((scaled_border <= (float)mouse_pos(0) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size))) {
|
||||
// which icon is it on?
|
||||
size_t from_top = (size_t)((float)mouse_pos(1) - top_y)/scaled_stride_y;
|
||||
// is it really on the icon or already past the border?
|
||||
if ((float)mouse_pos(1) <= top_y + from_top*scaled_stride_y + scaled_icons_size) {
|
||||
std::vector<size_t> selectable = get_selectable_idxs();
|
||||
if (from_top < selectable.size())
|
||||
return selectable[from_top];
|
||||
}
|
||||
}
|
||||
return Undefined;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::init()
|
||||
@ -45,77 +85,25 @@ bool GLGizmosManager::init()
|
||||
if (!m_background_texture.metadata.filename.empty())
|
||||
{
|
||||
if (!m_background_texture.texture.load_from_file(resources_dir() + "/icons/" + m_background_texture.metadata.filename, false, GLTexture::SingleThreaded, false))
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gizmos.emplace_back(new GLGizmoMove3D(m_parent, "move.svg", 0));
|
||||
m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "scale.svg", 1));
|
||||
m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2));
|
||||
m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3));
|
||||
m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4));
|
||||
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 5));
|
||||
|
||||
for (auto& gizmo : m_gizmos) {
|
||||
if (! gizmo->init()) {
|
||||
m_gizmos.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GLGizmoBase* gizmo = new GLGizmoMove3D(m_parent, "move.svg", 0);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
if (!gizmo->init())
|
||||
return false;
|
||||
|
||||
m_gizmos.insert(GizmosMap::value_type(Move, gizmo));
|
||||
|
||||
gizmo = new GLGizmoScale3D(m_parent, "scale.svg", 1);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
if (!gizmo->init())
|
||||
return false;
|
||||
|
||||
m_gizmos.insert(GizmosMap::value_type(Scale, gizmo));
|
||||
|
||||
gizmo = new GLGizmoRotate3D(m_parent, "rotate.svg", 2);
|
||||
if (gizmo == nullptr)
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gizmo->init())
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo));
|
||||
|
||||
gizmo = new GLGizmoFlatten(m_parent, "place.svg", 3);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
if (!gizmo->init()) {
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gizmos.insert(GizmosMap::value_type(Flatten, gizmo));
|
||||
|
||||
gizmo = new GLGizmoCut(m_parent, "cut.svg", 4);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
if (!gizmo->init()) {
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gizmos.insert(GizmosMap::value_type(Cut, gizmo));
|
||||
|
||||
gizmo = new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 5);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
if (!gizmo->init()) {
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gizmos.insert(GizmosMap::value_type(SlaSupports, gizmo));
|
||||
m_current = Undefined;
|
||||
m_hover = Undefined;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -140,65 +128,39 @@ void GLGizmosManager::set_overlay_scale(float scale)
|
||||
|
||||
void GLGizmosManager::refresh_on_off_state()
|
||||
{
|
||||
if (m_serializing)
|
||||
if (m_serializing || m_current == Undefined || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
GizmosMap::iterator it = m_gizmos.find(m_current);
|
||||
if ((it != m_gizmos.end()) && (it->second != nullptr))
|
||||
{
|
||||
if (!it->second->is_activable())
|
||||
{
|
||||
it->second->set_state(GLGizmoBase::Off);
|
||||
m_current = Undefined;
|
||||
}
|
||||
}
|
||||
if (m_current != Undefined && ! m_gizmos[m_current]->is_activable())
|
||||
activate_gizmo(Undefined);
|
||||
}
|
||||
|
||||
void GLGizmosManager::reset_all_states()
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (! m_enabled || m_serializing)
|
||||
return;
|
||||
|
||||
if (m_serializing)
|
||||
return;
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if (it->second != nullptr)
|
||||
{
|
||||
it->second->set_state(GLGizmoBase::Off);
|
||||
it->second->set_hover_id(-1);
|
||||
}
|
||||
}
|
||||
|
||||
m_current = Undefined;
|
||||
activate_gizmo(Undefined);
|
||||
m_hover = Undefined;
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_hover_id(int id)
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_current == Undefined)
|
||||
return;
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second != nullptr) && (it->second->get_state() == GLGizmoBase::On))
|
||||
it->second->set_hover_id(id);
|
||||
}
|
||||
m_gizmos[m_current]->set_hover_id(id);
|
||||
}
|
||||
|
||||
void GLGizmosManager::enable_grabber(EType type, unsigned int id, bool enable)
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || type == Undefined || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(type);
|
||||
if (it != m_gizmos.end())
|
||||
{
|
||||
if (enable)
|
||||
it->second->enable_grabber(id);
|
||||
else
|
||||
it->second->disable_grabber(id);
|
||||
}
|
||||
if (enable)
|
||||
m_gizmos[type]->enable_grabber(id);
|
||||
else
|
||||
m_gizmos[type]->disable_grabber(id);
|
||||
}
|
||||
|
||||
void GLGizmosManager::update(const Linef3& mouse_ray, const Point& mouse_pos)
|
||||
@ -269,8 +231,9 @@ bool GLGizmosManager::is_running() const
|
||||
if (!m_enabled)
|
||||
return false;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
|
||||
//GLGizmoBase* curr = get_current();
|
||||
//return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
|
||||
return m_current != Undefined;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::handle_shortcut(int key)
|
||||
@ -283,43 +246,12 @@ bool GLGizmosManager::handle_shortcut(int key)
|
||||
|
||||
bool handled = false;
|
||||
|
||||
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
for (size_t idx : get_selectable_idxs()) {
|
||||
int it_key = m_gizmos[idx]->get_shortcut_key();
|
||||
|
||||
int it_key = it->second->get_shortcut_key();
|
||||
|
||||
if (it->second->is_activable() && ((it_key == key - 64) || (it_key == key - 96)))
|
||||
{
|
||||
if ((it->second->get_state() == GLGizmoBase::On))
|
||||
{
|
||||
it->second->set_state(GLGizmoBase::Off);
|
||||
if (it->second->get_state() == GLGizmoBase::Off) {
|
||||
m_current = Undefined;
|
||||
}
|
||||
if (m_gizmos[idx]->is_activable() && ((it_key == key - 64) || (it_key == key - 96))) {
|
||||
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
||||
handled = true;
|
||||
}
|
||||
else if ((it->second->get_state() == GLGizmoBase::Off))
|
||||
{
|
||||
// Before turning anything on, turn everything else off to see if
|
||||
// nobody refuses. Only then activate the gizmo.
|
||||
bool can_open = true;
|
||||
for (GizmosMap::iterator i = m_gizmos.begin(); i != m_gizmos.end(); ++i) {
|
||||
if (i->first != it->first) {
|
||||
if (m_current == i->first && i->second->get_state() != GLGizmoBase::Off ) {
|
||||
i->second->set_state(GLGizmoBase::Off);
|
||||
if (i->second->get_state() != GLGizmoBase::Off)
|
||||
can_open = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (can_open) {
|
||||
it->second->set_state(GLGizmoBase::On);
|
||||
m_current = it->first;
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,31 +260,25 @@ bool GLGizmosManager::handle_shortcut(int key)
|
||||
|
||||
bool GLGizmosManager::is_dragging() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (! m_enabled || m_current == Undefined)
|
||||
return false;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
return (curr != nullptr) ? curr->is_dragging() : false;
|
||||
return m_gizmos[m_current]->is_dragging();
|
||||
}
|
||||
|
||||
void GLGizmosManager::start_dragging()
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (! m_enabled || m_current == Undefined)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->start_dragging();
|
||||
m_gizmos[m_current]->start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmosManager::stop_dragging()
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (! m_enabled || m_current == Undefined)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->stop_dragging();
|
||||
m_gizmos[m_current]->stop_dragging();
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_displacement() const
|
||||
@ -360,8 +286,7 @@ Vec3d GLGizmosManager::get_displacement() const
|
||||
if (!m_enabled)
|
||||
return Vec3d::Zero();
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(Move);
|
||||
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoMove3D*>(it->second)->get_displacement() : Vec3d::Zero();
|
||||
return dynamic_cast<GLGizmoMove3D*>(m_gizmos[Move].get())->get_displacement();
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_scale() const
|
||||
@ -369,126 +294,101 @@ Vec3d GLGizmosManager::get_scale() const
|
||||
if (!m_enabled)
|
||||
return Vec3d::Ones();
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(Scale);
|
||||
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoScale3D*>(it->second)->get_scale() : Vec3d::Ones();
|
||||
return dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->get_scale();
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_scale(const Vec3d& scale)
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(Scale);
|
||||
if (it != m_gizmos.end())
|
||||
reinterpret_cast<GLGizmoScale3D*>(it->second)->set_scale(scale);
|
||||
dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->set_scale(scale);
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_scale_offset() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return Vec3d::Zero();
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(Scale);
|
||||
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoScale3D*>(it->second)->get_offset() : Vec3d::Zero();
|
||||
return dynamic_cast<GLGizmoScale3D*>(m_gizmos[Scale].get())->get_offset();
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_rotation() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return Vec3d::Zero();
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
|
||||
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoRotate3D*>(it->second)->get_rotation() : Vec3d::Zero();
|
||||
return dynamic_cast<GLGizmoRotate3D*>(m_gizmos[Rotate].get())->get_rotation();
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_rotation(const Vec3d& rotation)
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
|
||||
if (it != m_gizmos.end())
|
||||
reinterpret_cast<GLGizmoRotate3D*>(it->second)->set_rotation(rotation);
|
||||
dynamic_cast<GLGizmoRotate3D*>(m_gizmos[Rotate].get())->set_rotation(rotation);
|
||||
}
|
||||
|
||||
Vec3d GLGizmosManager::get_flattening_normal() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return Vec3d::Zero();
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(Flatten);
|
||||
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_normal() : Vec3d::Zero();
|
||||
return dynamic_cast<GLGizmoFlatten*>(m_gizmos[Flatten].get())->get_flattening_normal();
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_flattening_data(const ModelObject* model_object)
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(Flatten);
|
||||
if (it != m_gizmos.end())
|
||||
reinterpret_cast<GLGizmoFlatten*>(it->second)->set_flattening_data(model_object);
|
||||
dynamic_cast<GLGizmoFlatten*>(m_gizmos[Flatten].get())->set_flattening_data(model_object);
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return;
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
|
||||
if (it != m_gizmos.end())
|
||||
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->set_sla_support_data(model_object, m_parent.get_selection());
|
||||
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->set_sla_support_data(model_object, m_parent.get_selection());
|
||||
}
|
||||
|
||||
// Returns true if the gizmo used the event to do something, false otherwise.
|
||||
bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down)
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_gizmos.empty())
|
||||
return false;
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
|
||||
if (it != m_gizmos.end())
|
||||
return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
|
||||
return false;
|
||||
return dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
}
|
||||
|
||||
ClippingPlane GLGizmosManager::get_sla_clipping_plane() const
|
||||
{
|
||||
if (!m_enabled || m_current != SlaSupports)
|
||||
if (!m_enabled || m_current != SlaSupports || m_gizmos.empty())
|
||||
return ClippingPlane::ClipsNothing();
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
|
||||
if (it != m_gizmos.end())
|
||||
return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->get_sla_clipping_plane();
|
||||
|
||||
return ClippingPlane::ClipsNothing();
|
||||
return dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->get_sla_clipping_plane();
|
||||
}
|
||||
|
||||
bool GLGizmosManager::wants_reslice_supports_on_undo() const
|
||||
{
|
||||
return (m_current == SlaSupports
|
||||
&& dynamic_cast<const GLGizmoSlaSupports*>(m_gizmos.at(SlaSupports))->has_backend_supports());
|
||||
&& dynamic_cast<const GLGizmoSlaSupports*>(m_gizmos.at(SlaSupports).get())->has_backend_supports());
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_current_gizmo() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_current == Undefined)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->render();
|
||||
m_gizmos[m_current]->render();
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_current_gizmo_for_picking_pass() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (! m_enabled || m_current == Undefined)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->render_for_picking();
|
||||
m_gizmos[m_current]->render_for_picking();
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_overlay() const
|
||||
@ -547,7 +447,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||
// if the button down was done on this toolbar, prevent from dragging into the scene
|
||||
processed = true;
|
||||
|
||||
if (!overlay_contains_mouse(mouse_pos))
|
||||
if (get_gizmo_idx_from_mouse(mouse_pos) == Undefined)
|
||||
{
|
||||
// mouse is outside the toolbar
|
||||
m_tooltip = "";
|
||||
@ -557,14 +457,12 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||
if ((m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
|
||||
// the gizmo got the event and took some action, there is no need to do anything more
|
||||
processed = true;
|
||||
else if (!selection.is_empty() && grabber_contains_mouse())
|
||||
{
|
||||
else if (!selection.is_empty() && grabber_contains_mouse()) {
|
||||
update_data();
|
||||
selection.start_dragging();
|
||||
start_dragging();
|
||||
|
||||
if (m_current == Flatten)
|
||||
{
|
||||
if (m_current == Flatten) {
|
||||
// Rotate the object so the normal points downward:
|
||||
m_parent.do_flatten(get_flattening_normal(), L("Gizmo-Place on Face"));
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
@ -634,25 +532,14 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||
}
|
||||
else if (evt.LeftUp() && is_dragging())
|
||||
{
|
||||
switch (m_current)
|
||||
{
|
||||
case Move:
|
||||
{
|
||||
m_parent.do_move(L("Gizmo-Move"));
|
||||
break;
|
||||
}
|
||||
case Scale:
|
||||
{
|
||||
m_parent.do_scale(L("Gizmo-Scale"));
|
||||
break;
|
||||
}
|
||||
case Rotate:
|
||||
{
|
||||
m_parent.do_rotate(L("Gizmo-Rotate"));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
switch (m_current) {
|
||||
case Move : m_parent.do_move(L("Gizmo-Move"));
|
||||
break;
|
||||
case Scale : m_parent.do_scale(L("Gizmo-Scale"));
|
||||
break;
|
||||
case Rotate : m_parent.do_rotate(L("Gizmo-Rotate"));
|
||||
break;
|
||||
default : break;
|
||||
}
|
||||
|
||||
stop_dragging();
|
||||
@ -842,7 +729,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
||||
{
|
||||
if (m_current == SlaSupports)
|
||||
{
|
||||
GLGizmoSlaSupports* gizmo = reinterpret_cast<GLGizmoSlaSupports*>(get_current());
|
||||
GLGizmoSlaSupports* gizmo = dynamic_cast<GLGizmoSlaSupports*>(get_current());
|
||||
|
||||
if (keyCode == WXK_SHIFT)
|
||||
{
|
||||
@ -863,7 +750,8 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
||||
}
|
||||
else if (evt.GetEventType() == wxEVT_KEY_DOWN)
|
||||
{
|
||||
if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) && reinterpret_cast<GLGizmoSlaSupports*>(get_current())->is_in_editing_mode())
|
||||
if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT))
|
||||
&& dynamic_cast<GLGizmoSlaSupports*>(get_current())->is_in_editing_mode())
|
||||
{
|
||||
// m_parent.set_cursor(GLCanvas3D::Cross);
|
||||
processed = true;
|
||||
@ -882,18 +770,7 @@ void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot)
|
||||
m_serializing = false;
|
||||
if (m_current == SlaSupports
|
||||
&& snapshot.snapshot_data.flags & UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS)
|
||||
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports])->reslice_SLA_supports(true);
|
||||
}
|
||||
|
||||
void GLGizmosManager::reset()
|
||||
{
|
||||
for (GizmosMap::value_type& gizmo : m_gizmos)
|
||||
{
|
||||
delete gizmo.second;
|
||||
gizmo.second = nullptr;
|
||||
}
|
||||
|
||||
m_gizmos.clear();
|
||||
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->reslice_SLA_supports(true);
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_background(float left, float top, float right, float bottom, float border) const
|
||||
@ -911,7 +788,7 @@ void GLGizmosManager::render_background(float left, float top, float right, floa
|
||||
float internal_top = top - border;
|
||||
float internal_bottom = bottom + border;
|
||||
|
||||
float left_uv = 0.0f;
|
||||
// float left_uv = 0.0f;
|
||||
float right_uv = 1.0f;
|
||||
float top_uv = 1.0f;
|
||||
float bottom_uv = 0.0f;
|
||||
@ -981,33 +858,32 @@ void GLGizmosManager::do_render_overlay() const
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale * inv_zoom;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
unsigned int icons_texture_id = m_icons_texture.get_id();
|
||||
unsigned int tex_width = m_icons_texture.get_width();
|
||||
unsigned int tex_height = m_icons_texture.get_height();
|
||||
float inv_tex_width = (tex_width != 0) ? 1.0f / (float)tex_width : 0.0f;
|
||||
float inv_tex_height = (tex_height != 0) ? 1.0f / (float)tex_height : 0.0f;
|
||||
int tex_width = m_icons_texture.get_width();
|
||||
int tex_height = m_icons_texture.get_height();
|
||||
float inv_tex_width = (tex_width != 0) ? 1.0f / tex_width : 0.0f;
|
||||
float inv_tex_height = (tex_height != 0) ? 1.0f / tex_height : 0.0f;
|
||||
|
||||
if ((icons_texture_id == 0) || (tex_width <= 0) || (tex_height <= 0))
|
||||
return;
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
for (size_t idx : get_selectable_idxs())
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
GLGizmoBase* gizmo = m_gizmos[idx].get();
|
||||
|
||||
unsigned int sprite_id = it->second->get_sprite_id();
|
||||
GLGizmoBase::EState state = it->second->get_state();
|
||||
unsigned int sprite_id = gizmo->get_sprite_id();
|
||||
int icon_idx = m_current == idx ? 2 : (m_hover == idx ? 1 : 0);
|
||||
|
||||
float u_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_width;
|
||||
float v_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_height;
|
||||
float v_top = sprite_id * v_icon_size;
|
||||
float u_left = state * u_icon_size;
|
||||
float u_left = icon_idx * u_icon_size;
|
||||
float v_bottom = v_top + v_icon_size;
|
||||
float u_right = u_left + u_icon_size;
|
||||
|
||||
GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + scaled_icons_size, top_y - scaled_icons_size, top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
|
||||
if (it->second->get_state() == GLGizmoBase::On) {
|
||||
float toolbar_top = (float)cnv_h - m_parent.get_view_toolbar_height();
|
||||
it->second->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top);
|
||||
if (idx == m_current) {
|
||||
float toolbar_top = cnv_h - m_parent.get_view_toolbar_height();
|
||||
gizmo->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top);
|
||||
}
|
||||
top_y -= scaled_stride_y;
|
||||
}
|
||||
@ -1021,13 +897,14 @@ float GLGizmosManager::get_total_overlay_height() const
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float height = 2.0f * scaled_border;
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
/*for (size_t idx=0; idx<m_gizmos.size(); ++idx)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
if ((m_gizmos[idx] == nullptr) || !m_gizmos[idx]->is_selectable())
|
||||
continue;
|
||||
|
||||
height += scaled_stride_y;
|
||||
}
|
||||
}*/
|
||||
height += get_selectable_idxs().size() * scaled_stride_y;
|
||||
|
||||
return height - scaled_gap_y;
|
||||
}
|
||||
@ -1039,19 +916,21 @@ float GLGizmosManager::get_total_overlay_width() const
|
||||
|
||||
GLGizmoBase* GLGizmosManager::get_current() const
|
||||
{
|
||||
GizmosMap::const_iterator it = m_gizmos.find(m_current);
|
||||
return (it != m_gizmos.end()) ? it->second : nullptr;
|
||||
if (m_current==Undefined || m_gizmos.empty())
|
||||
return nullptr;
|
||||
else
|
||||
return m_gizmos[m_current].get();
|
||||
}
|
||||
|
||||
bool GLGizmosManager::generate_icons_texture() const
|
||||
{
|
||||
std::string path = resources_dir() + "/icons/";
|
||||
std::vector<std::string> filenames;
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
for (size_t idx=0; idx<m_gizmos.size(); ++idx)
|
||||
{
|
||||
if (it->second != nullptr)
|
||||
if (m_gizmos[idx] != nullptr)
|
||||
{
|
||||
const std::string& icon_filename = it->second->get_icon_filename();
|
||||
const std::string& icon_filename = m_gizmos[idx]->get_icon_filename();
|
||||
if (!icon_filename.empty())
|
||||
filenames.push_back(path + icon_filename);
|
||||
}
|
||||
@ -1074,74 +953,9 @@ void GLGizmosManager::update_on_off_state(const Vec2d& mouse_pos)
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float top_y = 0.5f * (cnv_h - height) + scaled_border;
|
||||
|
||||
auto inside = [scaled_border, scaled_icons_size, &mouse_pos](float top_y) {
|
||||
return (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
|
||||
};
|
||||
|
||||
bool could_activate = true;
|
||||
for (std::pair<const GLGizmosManager::EType, GLGizmoBase*> &type_and_gizmo : m_gizmos)
|
||||
{
|
||||
GLGizmoBase *gizmo = type_and_gizmo.second;
|
||||
if ((gizmo == nullptr) || !gizmo->is_selectable())
|
||||
continue;
|
||||
|
||||
if (! (gizmo->is_activable() && inside(top_y))) {
|
||||
gizmo->set_state(GLGizmoBase::Off);
|
||||
if (gizmo->get_state() != GLGizmoBase::Off) {
|
||||
// Gizmo refused to leave it's active state. Don't try to select
|
||||
could_activate = false;
|
||||
}
|
||||
}
|
||||
|
||||
top_y += scaled_stride_y;
|
||||
}
|
||||
|
||||
// We may change m_current soon. If we did it during following loop, gizmos that take undo/redo snapshots
|
||||
// in their on_set_state function could snapshot a state with the new gizmo already active.
|
||||
// Therefore, just remember what needs to be done and actually change m_current afterwards.
|
||||
EType new_current = m_current;
|
||||
top_y = 0.5f * (cnv_h - height) + scaled_border;
|
||||
for (std::pair<const GLGizmosManager::EType, GLGizmoBase*> &type_and_gizmo : m_gizmos)
|
||||
{
|
||||
GLGizmoBase *gizmo = type_and_gizmo.second;
|
||||
if ((gizmo == nullptr) || !gizmo->is_selectable())
|
||||
continue;
|
||||
|
||||
if (gizmo->is_activable() && inside(top_y))
|
||||
{
|
||||
if ((gizmo->get_state() == GLGizmoBase::On))
|
||||
{
|
||||
gizmo->set_state(GLGizmoBase::Off);
|
||||
if (gizmo->get_state() == GLGizmoBase::Off) {
|
||||
gizmo->set_state(GLGizmoBase::Hover);
|
||||
new_current = Undefined;
|
||||
}
|
||||
}
|
||||
else if ((gizmo->get_state() == GLGizmoBase::Hover) && could_activate)
|
||||
{
|
||||
gizmo->set_state(GLGizmoBase::On);
|
||||
new_current = type_and_gizmo.first;
|
||||
}
|
||||
}
|
||||
|
||||
top_y += scaled_stride_y;
|
||||
}
|
||||
m_current = new_current;
|
||||
|
||||
if (could_activate) {
|
||||
GizmosMap::iterator it = m_gizmos.find(m_current);
|
||||
if ((it != m_gizmos.end()) && (it->second != nullptr) && (it->second->get_state() != GLGizmoBase::On))
|
||||
it->second->set_state(GLGizmoBase::On);
|
||||
}
|
||||
size_t idx = get_gizmo_idx_from_mouse(mouse_pos);
|
||||
if (idx != Undefined && m_gizmos[idx]->is_activable() && m_hover == idx)
|
||||
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
||||
}
|
||||
|
||||
std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos)
|
||||
@ -1151,60 +965,37 @@ std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos)
|
||||
if (!m_enabled)
|
||||
return name;
|
||||
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float top_y = 0.5f * (cnv_h - height) + scaled_border;
|
||||
m_hover = Undefined;
|
||||
|
||||
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
size_t idx = get_gizmo_idx_from_mouse(mouse_pos);
|
||||
if (idx != Undefined) {
|
||||
name = m_gizmos[idx]->get_name();
|
||||
|
||||
bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
|
||||
if (inside)
|
||||
name = it->second->get_name();
|
||||
|
||||
if (it->second->is_activable() && (it->second->get_state() != GLGizmoBase::On))
|
||||
it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
|
||||
|
||||
top_y += scaled_stride_y;
|
||||
if (m_gizmos[idx]->is_activable())
|
||||
m_hover = (EType)idx;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::overlay_contains_mouse(const Vec2d& mouse_pos) const
|
||||
void GLGizmosManager::activate_gizmo(EType type)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return false;
|
||||
if (m_gizmos.empty() || m_current == type)
|
||||
return;
|
||||
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float top_y = 0.5f * (cnv_h - height) + scaled_border;
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
if ((scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
|
||||
return true;
|
||||
|
||||
top_y += scaled_stride_y;
|
||||
if (m_current != Undefined) {
|
||||
m_gizmos[m_current]->set_state(GLGizmoBase::Off);
|
||||
if (m_gizmos[m_current]->get_state() != GLGizmoBase::Off)
|
||||
return; // gizmo refused to be turned off, do nothing.
|
||||
}
|
||||
|
||||
return false;
|
||||
if (type != Undefined)
|
||||
m_gizmos[type]->set_state(GLGizmoBase::On);
|
||||
|
||||
m_current = type;
|
||||
}
|
||||
|
||||
|
||||
bool GLGizmosManager::grabber_contains_mouse() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
|
@ -54,25 +54,30 @@ public:
|
||||
|
||||
enum EType : unsigned char
|
||||
{
|
||||
Undefined,
|
||||
Move,
|
||||
Scale,
|
||||
Rotate,
|
||||
Flatten,
|
||||
Cut,
|
||||
SlaSupports,
|
||||
Num_Types
|
||||
Undefined
|
||||
};
|
||||
|
||||
private:
|
||||
GLCanvas3D& m_parent;
|
||||
bool m_enabled;
|
||||
typedef std::map<EType, GLGizmoBase*> GizmosMap;
|
||||
GizmosMap m_gizmos;
|
||||
std::vector<std::unique_ptr<GLGizmoBase>> m_gizmos;
|
||||
mutable GLTexture m_icons_texture;
|
||||
mutable bool m_icons_texture_dirty;
|
||||
BackgroundTexture m_background_texture;
|
||||
EType m_current;
|
||||
EType m_hover;
|
||||
|
||||
std::vector<size_t> get_selectable_idxs() const;
|
||||
std::vector<size_t> get_activable_idxs() const;
|
||||
size_t get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const;
|
||||
|
||||
void activate_gizmo(EType type);
|
||||
|
||||
float m_overlay_icons_size;
|
||||
float m_overlay_scale;
|
||||
@ -98,7 +103,6 @@ private:
|
||||
|
||||
public:
|
||||
explicit GLGizmosManager(GLCanvas3D& parent);
|
||||
~GLGizmosManager();
|
||||
|
||||
bool init();
|
||||
|
||||
@ -112,16 +116,8 @@ public:
|
||||
|
||||
ar(m_current);
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it) {
|
||||
GLGizmoBase* gizmo = it->second;
|
||||
if (gizmo != nullptr) {
|
||||
gizmo->set_hover_id(-1);
|
||||
gizmo->set_state((it->second == curr) ? GLGizmoBase::On : GLGizmoBase::Off);
|
||||
if (gizmo == curr)
|
||||
gizmo->load(ar);
|
||||
}
|
||||
}
|
||||
if (m_current != Undefined)
|
||||
m_gizmos[m_current]->load(ar);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
@ -132,9 +128,8 @@ public:
|
||||
|
||||
ar(m_current);
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->save(ar);
|
||||
if (m_current != Undefined && !m_gizmos.empty())
|
||||
m_gizmos[m_current]->save(ar);
|
||||
}
|
||||
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
@ -195,8 +190,6 @@ public:
|
||||
void update_after_undo_redo(const UndoRedo::Snapshot& snapshot);
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
void render_background(float left, float top, float right, float bottom, float border) const;
|
||||
void do_render_overlay() const;
|
||||
|
||||
@ -209,7 +202,6 @@ private:
|
||||
|
||||
void update_on_off_state(const Vec2d& mouse_pos);
|
||||
std::string update_hover_state(const Vec2d& mouse_pos);
|
||||
bool overlay_contains_mouse(const Vec2d& mouse_pos) const;
|
||||
bool grabber_contains_mouse() const;
|
||||
};
|
||||
|
||||
|
@ -50,8 +50,9 @@ class MainFrame : public DPIFrame
|
||||
wxString m_qs_last_input_file = wxEmptyString;
|
||||
wxString m_qs_last_output_file = wxEmptyString;
|
||||
wxString m_last_config = wxEmptyString;
|
||||
|
||||
wxMenuItem* m_menu_item_repeat { nullptr };
|
||||
#if 0
|
||||
wxMenuItem* m_menu_item_repeat { nullptr }; // doesn't used now
|
||||
#endif
|
||||
wxMenuItem* m_menu_item_reslice_now { nullptr };
|
||||
|
||||
PrintHostQueueDialog *m_printhost_queue_dlg;
|
||||
|
@ -457,8 +457,9 @@ void ConfigOptionsGroup::Show(const bool show)
|
||||
bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) {
|
||||
if (m_options_mode.empty())
|
||||
return true;
|
||||
if (m_grid_sizer->GetEffectiveRowsCount() != m_options_mode.size() &&
|
||||
m_options_mode.size() == 1)
|
||||
int opt_mode_size = m_options_mode.size();
|
||||
if (m_grid_sizer->GetEffectiveRowsCount() != opt_mode_size &&
|
||||
opt_mode_size == 1)
|
||||
return m_options_mode[0] <= mode;
|
||||
|
||||
Show(true);
|
||||
@ -476,7 +477,7 @@ bool ConfigOptionsGroup::update_visibility(ConfigOptionMode mode) {
|
||||
coef+= cols;
|
||||
}
|
||||
|
||||
if (hidden_row_cnt == m_options_mode.size()) {
|
||||
if (hidden_row_cnt == opt_mode_size) {
|
||||
sizer->ShowItems(false);
|
||||
return false;
|
||||
}
|
||||
|
@ -510,24 +510,27 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
|
||||
option.opt.sidetext = "";
|
||||
line.append_option(option);
|
||||
|
||||
auto wiping_dialog_btn = [config, this](wxWindow* parent) {
|
||||
auto wiping_dialog_btn = [this](wxWindow* parent) {
|
||||
m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
m_wiping_dialog_button->SetFont(wxGetApp().normal_font());
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(m_wiping_dialog_button, 0, wxALIGN_CENTER_VERTICAL);
|
||||
m_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e)
|
||||
{
|
||||
auto &config = wxGetApp().preset_bundle->project_config;
|
||||
const std::vector<double> &init_matrix = (config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values;
|
||||
const std::vector<double> &init_extruders = (config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
|
||||
auto &project_config = wxGetApp().preset_bundle->project_config;
|
||||
const std::vector<double> &init_matrix = (project_config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values;
|
||||
const std::vector<double> &init_extruders = (project_config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
|
||||
|
||||
WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders));
|
||||
const DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
const std::vector<std::string> &extruder_colours = (config->option<ConfigOptionStrings>("extruder_colour"))->values;
|
||||
|
||||
WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders), extruder_colours);
|
||||
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
std::vector<float> matrix = dlg.get_matrix();
|
||||
std::vector<float> extruders = dlg.get_extruders();
|
||||
(config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values = std::vector<double>(matrix.begin(), matrix.end());
|
||||
(config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values = std::vector<double>(extruders.begin(), extruders.end());
|
||||
(project_config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values = std::vector<double>(matrix.begin(), matrix.end());
|
||||
(project_config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values = std::vector<double>(extruders.begin(), extruders.end());
|
||||
wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent));
|
||||
}
|
||||
}));
|
||||
@ -1072,8 +1075,6 @@ void Sidebar::show_info_sizer()
|
||||
return;
|
||||
}
|
||||
|
||||
const ModelInstance* model_instance = !model_object->instances.empty() ? model_object->instances.front() : nullptr;
|
||||
|
||||
auto size = model_object->bounding_box().size();
|
||||
p->object_info->info_size->SetLabel(wxString::Format("%.2f x %.2f x %.2f",size(0), size(1), size(2)));
|
||||
p->object_info->info_materials->SetLabel(wxString::Format("%d", static_cast<int>(model_object->materials_count())));
|
||||
@ -2284,20 +2285,20 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
|
||||
if (! is_project_file) {
|
||||
if (model.looks_like_multipart_object()) {
|
||||
wxMessageDialog dlg(q, _(L(
|
||||
wxMessageDialog msg_dlg(q, _(L(
|
||||
"This file contains several objects positioned at multiple heights. "
|
||||
"Instead of considering them as multiple objects, should I consider\n"
|
||||
"this file as a single object having multiple parts?\n"
|
||||
)), _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES) {
|
||||
if (msg_dlg.ShowModal() == wxID_YES) {
|
||||
model.convert_multipart_object(nozzle_dmrs->values.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf) && model_has_advanced_features(model)) {
|
||||
wxMessageDialog dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?\n")),
|
||||
wxMessageDialog msg_dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?\n")),
|
||||
_(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
if (msg_dlg.ShowModal() == wxID_YES)
|
||||
{
|
||||
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
|
||||
view3D->set_as_dirty();
|
||||
@ -2336,12 +2337,12 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
}
|
||||
|
||||
if (new_model != nullptr && new_model->objects.size() > 1) {
|
||||
wxMessageDialog dlg(q, _(L(
|
||||
wxMessageDialog msg_dlg(q, _(L(
|
||||
"Multiple objects were loaded for a multi-material printer.\n"
|
||||
"Instead of considering them as multiple objects, should I consider\n"
|
||||
"these files to represent a single object having multiple parts?\n"
|
||||
)), _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES) {
|
||||
if (msg_dlg.ShowModal() == wxID_YES) {
|
||||
new_model->convert_multipart_object(nozzle_dmrs->values.size());
|
||||
}
|
||||
|
||||
@ -3260,6 +3261,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
||||
else
|
||||
this->update_sla_scene();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
} else if (evt.status.flags & PrintBase::SlicingStatus::RELOAD_SLA_PREVIEW) {
|
||||
// Update the SLA preview. Only called if not RELOAD_SLA_SUPPORT_POINTS, as the block above will refresh the preview anyways.
|
||||
@ -3279,6 +3281,7 @@ void Plater::priv::on_slicing_completed(wxCommandEvent &)
|
||||
else
|
||||
this->update_sla_scene();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3325,6 +3328,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||
else
|
||||
this->update_sla_scene();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if (canceled) {
|
||||
|
@ -697,6 +697,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
config.option<ConfigOptionString>("default_sla_print_profile", true);
|
||||
config.option<ConfigOptionString>("default_sla_material_profile", true);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// 1) Create a name from the file name.
|
||||
@ -805,6 +806,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
load_preset(this->sla_materials, 1, "sla_material_settings_id");
|
||||
load_preset(this->printers, 2, "printer_settings_id");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
this->update_compatible(false);
|
||||
@ -1349,6 +1351,7 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible)
|
||||
[&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; });
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
|
||||
double bridge_flow_ratio = print_config.opt_float("bridge_flow_ratio");
|
||||
double perimeter_speed = print_config.opt_float("perimeter_speed");
|
||||
double external_perimeter_speed = print_config.get_abs_value("external_perimeter_speed", perimeter_speed);
|
||||
double gap_fill_speed = print_config.opt_float("gap_fill_speed");
|
||||
// double gap_fill_speed = print_config.opt_float("gap_fill_speed");
|
||||
double infill_speed = print_config.opt_float("infill_speed");
|
||||
double small_perimeter_speed = print_config.get_abs_value("small_perimeter_speed", perimeter_speed);
|
||||
double solid_infill_speed = print_config.get_abs_value("solid_infill_speed", infill_speed);
|
||||
@ -123,7 +123,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
|
||||
// Current filament values
|
||||
double filament_diameter = filament_config.opt_float("filament_diameter", 0);
|
||||
double filament_crossection = M_PI * 0.25 * filament_diameter * filament_diameter;
|
||||
double extrusion_multiplier = filament_config.opt_float("extrusion_multiplier", 0);
|
||||
// double extrusion_multiplier = filament_config.opt_float("extrusion_multiplier", 0);
|
||||
// The following value will be annotated by this hint, so it does not take part in the calculation.
|
||||
// double filament_max_volumetric_speed = filament_config.opt_float("filament_max_volumetric_speed", 0);
|
||||
|
||||
|
@ -310,7 +310,7 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx)
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
GLVolume* v = (*m_volumes)[i];
|
||||
if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx))
|
||||
if ((v->object_idx() == (int)object_idx) && (v->volume_idx() == (int)volume_idx))
|
||||
do_remove_volume(i);
|
||||
}
|
||||
|
||||
@ -992,7 +992,7 @@ void Selection::translate(unsigned int object_idx, const Vec3d& displacement)
|
||||
for (unsigned int i : m_list)
|
||||
{
|
||||
GLVolume* v = (*m_volumes)[i];
|
||||
if (v->object_idx() == object_idx)
|
||||
if (v->object_idx() == (int)object_idx)
|
||||
v->set_instance_offset(v->get_instance_offset() + displacement);
|
||||
}
|
||||
|
||||
@ -1037,7 +1037,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
|
||||
for (unsigned int i : m_list)
|
||||
{
|
||||
GLVolume* v = (*m_volumes)[i];
|
||||
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
|
||||
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
|
||||
v->set_instance_offset(v->get_instance_offset() + displacement);
|
||||
}
|
||||
|
||||
@ -1063,7 +1063,7 @@ void Selection::translate(unsigned int object_idx, unsigned int instance_idx, co
|
||||
continue;
|
||||
|
||||
GLVolume* v = (*m_volumes)[j];
|
||||
if ((v->object_idx() != object_idx) || (v->instance_idx() != instance_idx))
|
||||
if ((v->object_idx() != object_idx) || (v->instance_idx() != (int)instance_idx))
|
||||
continue;
|
||||
|
||||
v->set_instance_offset(v->get_instance_offset() + displacement);
|
||||
@ -1154,7 +1154,7 @@ void Selection::erase()
|
||||
for (const ItemForDelete& i : items_set) {
|
||||
if (i.type == ItemType::itVolume) {
|
||||
const int vol_in_obj_cnt = volumes_in_obj.find(i.obj_idx) == volumes_in_obj.end() ? 0 : volumes_in_obj.at(i.obj_idx);
|
||||
if (vol_in_obj_cnt == m_model->objects[i.obj_idx]->volumes.size()) {
|
||||
if (vol_in_obj_cnt == (int)m_model->objects[i.obj_idx]->volumes.size()) {
|
||||
if (i.sub_obj_idx == vol_in_obj_cnt - 1)
|
||||
items.emplace_back(ItemType::itObject, i.obj_idx, 0);
|
||||
continue;
|
||||
@ -1389,7 +1389,7 @@ std::vector<unsigned int> Selection::get_volume_idxs_from_object(unsigned int ob
|
||||
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
if ((*m_volumes)[i]->object_idx() == object_idx)
|
||||
if ((*m_volumes)[i]->object_idx() == (int)object_idx)
|
||||
idxs.push_back(i);
|
||||
}
|
||||
|
||||
@ -1403,7 +1403,7 @@ std::vector<unsigned int> Selection::get_volume_idxs_from_instance(unsigned int
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
const GLVolume* v = (*m_volumes)[i];
|
||||
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
|
||||
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
|
||||
idxs.push_back(i);
|
||||
}
|
||||
|
||||
@ -1417,9 +1417,9 @@ std::vector<unsigned int> Selection::get_volume_idxs_from_volume(unsigned int ob
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
const GLVolume* v = (*m_volumes)[i];
|
||||
if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx))
|
||||
if ((v->object_idx() == (int)object_idx) && (v->volume_idx() == (int)volume_idx))
|
||||
{
|
||||
if ((instance_idx != -1) && (v->instance_idx() == instance_idx))
|
||||
if (((int)instance_idx != -1) && (v->instance_idx() == (int)instance_idx))
|
||||
idxs.push_back(i);
|
||||
}
|
||||
}
|
||||
@ -1607,7 +1607,7 @@ void Selection::update_type()
|
||||
}
|
||||
else
|
||||
{
|
||||
int sels_cntr = 0;
|
||||
unsigned int sels_cntr = 0;
|
||||
for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it)
|
||||
{
|
||||
const ModelObject* model_object = m_model->objects[it->first];
|
||||
@ -1759,7 +1759,7 @@ void Selection::do_remove_instance(unsigned int object_idx, unsigned int instanc
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
GLVolume* v = (*m_volumes)[i];
|
||||
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
|
||||
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
|
||||
do_remove_volume(i);
|
||||
}
|
||||
}
|
||||
@ -1769,7 +1769,7 @@ void Selection::do_remove_object(unsigned int object_idx)
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
GLVolume* v = (*m_volumes)[i];
|
||||
if (v->object_idx() == object_idx)
|
||||
if (v->object_idx() == (int)object_idx)
|
||||
do_remove_volume(i);
|
||||
}
|
||||
}
|
||||
@ -1836,7 +1836,6 @@ void Selection::render_synchronized_volumes() const
|
||||
{
|
||||
const GLVolume* volume = (*m_volumes)[i];
|
||||
int object_idx = volume->object_idx();
|
||||
int instance_idx = volume->instance_idx();
|
||||
int volume_idx = volume->volume_idx();
|
||||
for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j)
|
||||
{
|
||||
|
@ -995,6 +995,7 @@ void Tab::update_preset_description_line()
|
||||
description_line += "\n\n\t" + _(L("default SLA print profile")) + ": \n\t\t" + default_sla_print_profile;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1263,251 +1264,9 @@ void TabPrint::update()
|
||||
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA)
|
||||
return; // ys_FIXME
|
||||
|
||||
/*
|
||||
// #ys_FIXME_to_delete
|
||||
//! Temporary workaround for the correct updates of the TextCtrl (like "layer_height"):
|
||||
// KillFocus() for the wxSpinCtrl use CallAfter function. So,
|
||||
// to except the duplicate call of the update() after dialog->ShowModal(),
|
||||
// let check if this process is already started.
|
||||
if (is_msg_dlg_already_exist)
|
||||
return;
|
||||
*/
|
||||
|
||||
m_update_cnt++;
|
||||
// Freeze();
|
||||
|
||||
/* #ys_FIXME_delete_after_testing (refactoring)
|
||||
*
|
||||
// layer_height shouldn't be equal to zero
|
||||
if (m_config->opt_float("layer_height") < EPSILON)
|
||||
{
|
||||
const wxString msg_text = _(L("Zero layer height is not valid.\n\nThe layer height will be reset to 0.01."));
|
||||
wxMessageDialog dialog(parent(), msg_text, _(L("Layer height")), wxICON_WARNING | wxOK);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
is_msg_dlg_already_exist = true;
|
||||
dialog.ShowModal();
|
||||
new_conf.set_key_value("layer_height", new ConfigOptionFloat(0.01));
|
||||
load_config(new_conf);
|
||||
is_msg_dlg_already_exist = false;
|
||||
}
|
||||
|
||||
if (fabs(m_config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value - 0) < EPSILON)
|
||||
{
|
||||
const wxString msg_text = _(L("Zero first layer height is not valid.\n\nThe first layer height will be reset to 0.01."));
|
||||
wxMessageDialog dialog(parent(), msg_text, _(L("First layer height")), wxICON_WARNING | wxOK);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
is_msg_dlg_already_exist = true;
|
||||
dialog.ShowModal();
|
||||
new_conf.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.01, false));
|
||||
load_config(new_conf);
|
||||
is_msg_dlg_already_exist = false;
|
||||
}
|
||||
|
||||
double fill_density = m_config->option<ConfigOptionPercent>("fill_density")->value;
|
||||
|
||||
if (m_config->opt_bool("spiral_vase") &&
|
||||
!(m_config->opt_int("perimeters") == 1 && m_config->opt_int("top_solid_layers") == 0 &&
|
||||
fill_density == 0)) {
|
||||
wxString msg_text = _(L("The Spiral Vase mode requires:\n"
|
||||
"- one perimeter\n"
|
||||
"- no top solid layers\n"
|
||||
"- 0% fill density\n"
|
||||
"- no support material\n"
|
||||
"- no ensure_vertical_shell_thickness\n"
|
||||
"\nShall I adjust those settings in order to enable Spiral Vase?"));
|
||||
wxMessageDialog dialog(parent(), msg_text, _(L("Spiral Vase")), wxICON_WARNING | wxYES | wxNO);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
new_conf.set_key_value("perimeters", new ConfigOptionInt(1));
|
||||
new_conf.set_key_value("top_solid_layers", new ConfigOptionInt(0));
|
||||
new_conf.set_key_value("fill_density", new ConfigOptionPercent(0));
|
||||
new_conf.set_key_value("support_material", new ConfigOptionBool(false));
|
||||
new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0));
|
||||
new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(false));
|
||||
fill_density = 0;
|
||||
}
|
||||
else {
|
||||
new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false));
|
||||
}
|
||||
load_config(new_conf);
|
||||
on_value_change("fill_density", fill_density);
|
||||
}
|
||||
|
||||
if (m_config->opt_bool("wipe_tower") && m_config->opt_bool("support_material") &&
|
||||
m_config->opt_float("support_material_contact_distance") > 0. &&
|
||||
(m_config->opt_int("support_material_extruder") != 0 || m_config->opt_int("support_material_interface_extruder") != 0)) {
|
||||
wxString msg_text = _(L("The Wipe Tower currently supports the non-soluble supports only\n"
|
||||
"if they are printed with the current extruder without triggering a tool change.\n"
|
||||
"(both support_material_extruder and support_material_interface_extruder need to be set to 0).\n"
|
||||
"\nShall I adjust those settings in order to enable the Wipe Tower?"));
|
||||
wxMessageDialog dialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
new_conf.set_key_value("support_material_extruder", new ConfigOptionInt(0));
|
||||
new_conf.set_key_value("support_material_interface_extruder", new ConfigOptionInt(0));
|
||||
}
|
||||
else
|
||||
new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false));
|
||||
load_config(new_conf);
|
||||
}
|
||||
|
||||
if (m_config->opt_bool("wipe_tower") && m_config->opt_bool("support_material") &&
|
||||
m_config->opt_float("support_material_contact_distance") == 0 &&
|
||||
!m_config->opt_bool("support_material_synchronize_layers")) {
|
||||
wxString msg_text = _(L("For the Wipe Tower to work with the soluble supports, the support layers\n"
|
||||
"need to be synchronized with the object layers.\n"
|
||||
"\nShall I synchronize support layers in order to enable the Wipe Tower?"));
|
||||
wxMessageDialog dialog(parent(), msg_text, _(L("Wipe Tower")), wxICON_WARNING | wxYES | wxNO);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
new_conf.set_key_value("support_material_synchronize_layers", new ConfigOptionBool(true));
|
||||
}
|
||||
else
|
||||
new_conf.set_key_value("wipe_tower", new ConfigOptionBool(false));
|
||||
load_config(new_conf);
|
||||
}
|
||||
|
||||
if (m_config->opt_bool("support_material")) {
|
||||
// Ask only once.
|
||||
if (!m_support_material_overhangs_queried) {
|
||||
m_support_material_overhangs_queried = true;
|
||||
if (!m_config->opt_bool("overhangs")/* != 1* /) {
|
||||
wxString msg_text = _(L("Supports work better, if the following feature is enabled:\n"
|
||||
"- Detect bridging perimeters\n"
|
||||
"\nShall I adjust those settings for supports?"));
|
||||
wxMessageDialog dialog(parent(), msg_text, _(L("Support Generator")), wxICON_WARNING | wxYES | wxNO | wxCANCEL);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
auto answer = dialog.ShowModal();
|
||||
if (answer == wxID_YES) {
|
||||
// Enable "detect bridging perimeters".
|
||||
new_conf.set_key_value("overhangs", new ConfigOptionBool(true));
|
||||
} else if (answer == wxID_NO) {
|
||||
// Do nothing, leave supports on and "detect bridging perimeters" off.
|
||||
} else if (answer == wxID_CANCEL) {
|
||||
// Disable supports.
|
||||
new_conf.set_key_value("support_material", new ConfigOptionBool(false));
|
||||
m_support_material_overhangs_queried = false;
|
||||
}
|
||||
load_config(new_conf);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_support_material_overhangs_queried = false;
|
||||
}
|
||||
|
||||
if (m_config->option<ConfigOptionPercent>("fill_density")->value == 100) {
|
||||
auto fill_pattern = m_config->option<ConfigOptionEnum<InfillPattern>>("fill_pattern")->value;
|
||||
std::string str_fill_pattern = "";
|
||||
t_config_enum_values map_names = m_config->option<ConfigOptionEnum<InfillPattern>>("fill_pattern")->get_enum_values();
|
||||
for (auto it : map_names) {
|
||||
if (fill_pattern == it.second) {
|
||||
str_fill_pattern = it.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!str_fill_pattern.empty()) {
|
||||
const std::vector<std::string> &external_fill_pattern = m_config->def()->get("top_fill_pattern")->enum_values;
|
||||
bool correct_100p_fill = false;
|
||||
for (const std::string &fill : external_fill_pattern)
|
||||
{
|
||||
if (str_fill_pattern == fill)
|
||||
correct_100p_fill = true;
|
||||
}
|
||||
// get fill_pattern name from enum_labels for using this one at dialog_msg
|
||||
str_fill_pattern = _utf8(m_config->def()->get("fill_pattern")->enum_labels[fill_pattern]);
|
||||
if (!correct_100p_fill) {
|
||||
wxString msg_text = GUI::from_u8((boost::format(_utf8(L("The %1% infill pattern is not supposed to work at 100%% density.\n\n"
|
||||
"Shall I switch to rectilinear fill pattern?"))) % str_fill_pattern).str());
|
||||
wxMessageDialog dialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_YES) {
|
||||
new_conf.set_key_value("fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
|
||||
fill_density = 100;
|
||||
}
|
||||
else
|
||||
fill_density = m_presets->get_selected_preset().config.option<ConfigOptionPercent>("fill_density")->value;
|
||||
new_conf.set_key_value("fill_density", new ConfigOptionPercent(fill_density));
|
||||
load_config(new_conf);
|
||||
on_value_change("fill_density", fill_density);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool have_perimeters = m_config->opt_int("perimeters") > 0;
|
||||
for (auto el : {"extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
||||
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" })
|
||||
get_field(el)->toggle(have_perimeters);
|
||||
|
||||
bool have_infill = m_config->option<ConfigOptionPercent>("fill_density")->value > 0;
|
||||
// infill_extruder uses the same logic as in Print::extruders()
|
||||
for (auto el : {"fill_pattern", "infill_every_layers", "infill_only_where_needed",
|
||||
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" })
|
||||
get_field(el)->toggle(have_infill);
|
||||
|
||||
bool have_solid_infill = m_config->opt_int("top_solid_layers") > 0 || m_config->opt_int("bottom_solid_layers") > 0;
|
||||
// solid_infill_extruder uses the same logic as in Print::extruders()
|
||||
for (auto el : {"top_fill_pattern", "bottom_fill_pattern", "infill_first", "solid_infill_extruder",
|
||||
"solid_infill_extrusion_width", "solid_infill_speed" })
|
||||
get_field(el)->toggle(have_solid_infill);
|
||||
|
||||
for (auto el : {"fill_angle", "bridge_angle", "infill_extrusion_width",
|
||||
"infill_speed", "bridge_speed" })
|
||||
get_field(el)->toggle(have_infill || have_solid_infill);
|
||||
|
||||
get_field("gap_fill_speed")->toggle(have_perimeters && have_infill);
|
||||
|
||||
bool have_top_solid_infill = m_config->opt_int("top_solid_layers") > 0;
|
||||
for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" })
|
||||
get_field(el)->toggle(have_top_solid_infill);
|
||||
|
||||
bool have_default_acceleration = m_config->opt_float("default_acceleration") > 0;
|
||||
for (auto el : {"perimeter_acceleration", "infill_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration" })
|
||||
get_field(el)->toggle(have_default_acceleration);
|
||||
|
||||
bool have_skirt = m_config->opt_int("skirts") > 0 || m_config->opt_float("min_skirt_length") > 0;
|
||||
for (auto el : { "skirt_distance", "skirt_height" })
|
||||
get_field(el)->toggle(have_skirt);
|
||||
|
||||
bool have_brim = m_config->opt_float("brim_width") > 0;
|
||||
// perimeter_extruder uses the same logic as in Print::extruders()
|
||||
get_field("perimeter_extruder")->toggle(have_perimeters || have_brim);
|
||||
|
||||
bool have_raft = m_config->opt_int("raft_layers") > 0;
|
||||
bool have_support_material = m_config->opt_bool("support_material") || have_raft;
|
||||
bool have_support_material_auto = have_support_material && m_config->opt_bool("support_material_auto");
|
||||
bool have_support_interface = m_config->opt_int("support_material_interface_layers") > 0;
|
||||
bool have_support_soluble = have_support_material && m_config->opt_float("support_material_contact_distance") == 0;
|
||||
for (auto el : {"support_material_pattern", "support_material_with_sheath",
|
||||
"support_material_spacing", "support_material_angle", "support_material_interface_layers",
|
||||
"dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance",
|
||||
"support_material_xy_spacing" })
|
||||
get_field(el)->toggle(have_support_material);
|
||||
get_field("support_material_threshold")->toggle(have_support_material_auto);
|
||||
|
||||
for (auto el : {"support_material_interface_spacing", "support_material_interface_extruder",
|
||||
"support_material_interface_speed", "support_material_interface_contact_loops" })
|
||||
get_field(el)->toggle(have_support_material && have_support_interface);
|
||||
get_field("support_material_synchronize_layers")->toggle(have_support_soluble);
|
||||
|
||||
get_field("perimeter_extrusion_width")->toggle(have_perimeters || have_skirt || have_brim);
|
||||
get_field("support_material_extruder")->toggle(have_support_material || have_skirt);
|
||||
get_field("support_material_speed")->toggle(have_support_material || have_brim || have_skirt);
|
||||
|
||||
bool have_sequential_printing = m_config->opt_bool("complete_objects");
|
||||
for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" })
|
||||
get_field(el)->toggle(have_sequential_printing);
|
||||
|
||||
bool have_ooze_prevention = m_config->opt_bool("ooze_prevention");
|
||||
get_field("standby_temperature_delta")->toggle(have_ooze_prevention);
|
||||
|
||||
bool have_wipe_tower = m_config->opt_bool("wipe_tower");
|
||||
for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging"})
|
||||
get_field(el)->toggle(have_wipe_tower);
|
||||
*/
|
||||
|
||||
m_config_manipulation.update_print_fff_config(m_config, true);
|
||||
|
||||
m_recommended_thin_wall_thickness_description_line->SetText(
|
||||
@ -3826,84 +3585,6 @@ void TabSLAPrint::update()
|
||||
|
||||
m_update_cnt++;
|
||||
|
||||
/* #ys_FIXME_delete_after_testing (refactoring)
|
||||
*
|
||||
bool supports_en = m_config->opt_bool("supports_enable");
|
||||
|
||||
get_field("support_head_front_diameter")->toggle(supports_en);
|
||||
get_field("support_head_penetration")->toggle(supports_en);
|
||||
get_field("support_head_width")->toggle(supports_en);
|
||||
get_field("support_pillar_diameter")->toggle(supports_en);
|
||||
get_field("support_pillar_connection_mode")->toggle(supports_en);
|
||||
get_field("support_buildplate_only")->toggle(supports_en);
|
||||
get_field("support_base_diameter")->toggle(supports_en);
|
||||
get_field("support_base_height")->toggle(supports_en);
|
||||
get_field("support_base_safety_distance")->toggle(supports_en);
|
||||
get_field("support_critical_angle")->toggle(supports_en);
|
||||
get_field("support_max_bridge_length")->toggle(supports_en);
|
||||
get_field("support_max_pillar_link_distance")->toggle(supports_en);
|
||||
get_field("support_points_density_relative")->toggle(supports_en);
|
||||
get_field("support_points_minimal_distance")->toggle(supports_en);
|
||||
|
||||
bool pad_en = m_config->opt_bool("pad_enable");
|
||||
|
||||
get_field("pad_wall_thickness")->toggle(pad_en);
|
||||
get_field("pad_wall_height")->toggle(pad_en);
|
||||
get_field("pad_max_merge_distance")->toggle(pad_en);
|
||||
// get_field("pad_edge_radius")->toggle(supports_en);
|
||||
get_field("pad_wall_slope")->toggle(pad_en);
|
||||
get_field("pad_around_object")->toggle(pad_en);
|
||||
|
||||
double head_penetration = m_config->opt_float("support_head_penetration");
|
||||
double head_width = m_config->opt_float("support_head_width");
|
||||
if (head_penetration > head_width) {
|
||||
wxString msg_text = _(
|
||||
L("Head penetration should not be greater than the head width."));
|
||||
|
||||
wxMessageDialog dialog(parent(),
|
||||
msg_text,
|
||||
_(L("Invalid Head penetration")),
|
||||
wxICON_WARNING | wxOK);
|
||||
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_OK) {
|
||||
new_conf.set_key_value("support_head_penetration",
|
||||
new ConfigOptionFloat(head_width));
|
||||
}
|
||||
|
||||
load_config(new_conf);
|
||||
}
|
||||
|
||||
double pinhead_d = m_config->opt_float("support_head_front_diameter");
|
||||
double pillar_d = m_config->opt_float("support_pillar_diameter");
|
||||
if (pinhead_d > pillar_d) {
|
||||
wxString msg_text = _(L(
|
||||
"Pinhead diameter should be smaller than the pillar diameter."));
|
||||
|
||||
wxMessageDialog dialog (parent(),
|
||||
msg_text,
|
||||
_(L("Invalid pinhead diameter")),
|
||||
wxICON_WARNING | wxOK);
|
||||
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog.ShowModal() == wxID_OK) {
|
||||
new_conf.set_key_value("support_head_front_diameter",
|
||||
new ConfigOptionFloat(pillar_d / 2.0));
|
||||
}
|
||||
|
||||
load_config(new_conf);
|
||||
}
|
||||
|
||||
bool has_suppad = pad_en && supports_en;
|
||||
bool zero_elev = m_config->opt_bool("pad_around_object") && has_suppad;
|
||||
|
||||
get_field("support_object_elevation")->toggle(supports_en && !zero_elev);
|
||||
get_field("pad_object_gap")->toggle(zero_elev);
|
||||
get_field("pad_object_connector_stride")->toggle(zero_elev);
|
||||
get_field("pad_object_connector_width")->toggle(zero_elev);
|
||||
get_field("pad_object_connector_penetration")->toggle(zero_elev);
|
||||
*/
|
||||
|
||||
m_config_manipulation.update_print_sla_config(m_config, true);
|
||||
m_update_cnt--;
|
||||
|
||||
|
@ -321,7 +321,6 @@ protected:
|
||||
|
||||
class TabPrint : public Tab
|
||||
{
|
||||
bool is_msg_dlg_already_exist {false};
|
||||
public:
|
||||
TabPrint(wxNotebook* parent) :
|
||||
// Tab(parent, _(L("Print Settings")), L("print")) {}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include "WipeTowerDialog.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
@ -137,11 +138,11 @@ std::string RammingPanel::get_parameters()
|
||||
|
||||
|
||||
// Parent dialog for purging volume adjustments - it fathers WipingPanel widget (that contains all controls) and a button to toggle simple/advanced mode:
|
||||
WipingDialog::WipingDialog(wxWindow* parent,const std::vector<float>& matrix, const std::vector<float>& extruders)
|
||||
WipingDialog::WipingDialog(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours)
|
||||
: wxDialog(parent, wxID_ANY, _(L("Wipe tower - Purging volume adjustment")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/)
|
||||
{
|
||||
auto widget_button = new wxButton(this,wxID_ANY,"-",wxPoint(0,0),wxDefaultSize);
|
||||
m_panel_wiping = new WipingPanel(this,matrix,extruders, widget_button);
|
||||
m_panel_wiping = new WipingPanel(this,matrix,extruders, extruder_colours, widget_button);
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
@ -180,7 +181,7 @@ void WipingPanel::format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_
|
||||
}
|
||||
|
||||
// This panel contains all control widgets for both simple and advanced mode (these reside in separate sizers)
|
||||
WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, wxButton* widget_button)
|
||||
WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours, wxButton* widget_button)
|
||||
: wxPanel(parent,wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxBORDER_RAISED*/)
|
||||
{
|
||||
m_widget_button = widget_button; // pointer to the button in parent dialog
|
||||
@ -188,6 +189,12 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
|
||||
|
||||
m_number_of_extruders = (int)(sqrt(matrix.size())+0.001);
|
||||
|
||||
for (const std::string& color : extruder_colours) {
|
||||
unsigned char rgb[3];
|
||||
Slic3r::PresetBundle::parse_color(color, rgb);
|
||||
m_colours.push_back(wxColor(rgb[0], rgb[1], rgb[2]));
|
||||
}
|
||||
|
||||
// Create two switched panels with their own sizers
|
||||
m_sizer_simple = new wxBoxSizer(wxVERTICAL);
|
||||
m_sizer_advanced = new wxBoxSizer(wxVERTICAL);
|
||||
@ -211,14 +218,36 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
|
||||
edit_boxes[i][j]->SetValue(wxString("") << int(matrix[m_number_of_extruders*j + i]));
|
||||
}
|
||||
}
|
||||
|
||||
const int clr_icon_side = edit_boxes.front().front()->GetSize().y;
|
||||
const auto icon_size = wxSize(clr_icon_side, clr_icon_side);
|
||||
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("")));
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i)
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j)
|
||||
m_gridsizer_advanced->Add(edit_boxes[j][i], 0);
|
||||
}
|
||||
auto hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
hsizer->AddSpacer(20);
|
||||
hsizer->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER);
|
||||
wxWindow* w = new wxWindow(m_page_advanced, wxID_ANY, wxDefaultPosition, icon_size, wxBORDER_SIMPLE);
|
||||
w->SetCanFocus(false);
|
||||
w->SetBackgroundColour(m_colours[i]);
|
||||
hsizer->AddStretchSpacer();
|
||||
hsizer->Add(w);
|
||||
m_gridsizer_advanced->Add(hsizer, 1, wxEXPAND);
|
||||
}
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
auto hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxWindow* w = new wxWindow(m_page_advanced, wxID_ANY, wxDefaultPosition, icon_size, wxBORDER_SIMPLE);
|
||||
w->SetCanFocus(false);
|
||||
w->SetBackgroundColour(m_colours[i]);
|
||||
hsizer->AddSpacer(20);
|
||||
hsizer->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
hsizer->AddStretchSpacer();
|
||||
hsizer->Add(w);
|
||||
m_gridsizer_advanced->Add(hsizer, 1, wxEXPAND);
|
||||
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j)
|
||||
m_gridsizer_advanced->Add(edit_boxes[j][i], 0);
|
||||
}
|
||||
|
||||
// collect and format sizer
|
||||
format_sizer(m_sizer_advanced, m_page_advanced, m_gridsizer_advanced,
|
||||
@ -237,7 +266,16 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
m_old.push_back(new wxSpinCtrl(m_page_simple,wxID_ANY,wxEmptyString,wxDefaultPosition, wxSize(ITEM_WIDTH(), -1),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,300,extruders[2*i]));
|
||||
m_new.push_back(new wxSpinCtrl(m_page_simple,wxID_ANY,wxEmptyString,wxDefaultPosition, wxSize(ITEM_WIDTH(), -1),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,300,extruders[2*i+1]));
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("Tool #"))) << i + 1 << ": "), 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
auto hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxWindow* w = new wxWindow(m_page_simple, wxID_ANY, wxDefaultPosition, icon_size, wxBORDER_SIMPLE);
|
||||
w->SetCanFocus(false);
|
||||
w->SetBackgroundColour(m_colours[i]);
|
||||
hsizer->Add(w, wxALIGN_CENTER_VERTICAL);
|
||||
hsizer->AddSpacer(10);
|
||||
hsizer->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("Tool #"))) << i + 1 << ": "), 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
gridsizer_simple->Add(hsizer, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(m_old.back(),0);
|
||||
gridsizer_simple->Add(m_new.back(),0);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ private:
|
||||
|
||||
class WipingPanel : public wxPanel {
|
||||
public:
|
||||
WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, wxButton* widget_button);
|
||||
WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours, wxButton* widget_button);
|
||||
std::vector<float> read_matrix_values();
|
||||
std::vector<float> read_extruders_values();
|
||||
void toggle_advanced(bool user_action = false);
|
||||
@ -59,6 +59,7 @@ private:
|
||||
std::vector<wxSpinCtrl*> m_old;
|
||||
std::vector<wxSpinCtrl*> m_new;
|
||||
std::vector<std::vector<wxTextCtrl*>> edit_boxes;
|
||||
std::vector<wxColour> m_colours;
|
||||
unsigned int m_number_of_extruders = 0;
|
||||
bool m_advanced = false;
|
||||
wxPanel* m_page_simple = nullptr;
|
||||
@ -76,7 +77,7 @@ private:
|
||||
|
||||
class WipingDialog : public wxDialog {
|
||||
public:
|
||||
WipingDialog(wxWindow* parent,const std::vector<float>& matrix, const std::vector<float>& extruders);
|
||||
WipingDialog(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, const std::vector<std::string>& extruder_colours);
|
||||
std::vector<float> get_matrix() const { return m_output_matrix; }
|
||||
std::vector<float> get_extruders() const { return m_output_extruders; }
|
||||
|
||||
|
@ -752,7 +752,7 @@ static bool append_root_node(ObjectDataViewModelNode *parent_node,
|
||||
|
||||
if (inst_root_id < 0) {
|
||||
if ((root_type&itInstanceRoot) ||
|
||||
(root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0)
|
||||
( (root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0) )
|
||||
parent_node->Append(*root_node);
|
||||
else if (root_type&itLayerRoot)
|
||||
parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
|
||||
@ -1379,7 +1379,12 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
|
||||
type = itUndef;
|
||||
|
||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
if (!node || node->GetIdx() <-1 || node->GetIdx() == -1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/)))
|
||||
if (!node ||
|
||||
node->GetIdx() <-1 ||
|
||||
( node->GetIdx() == -1 &&
|
||||
!(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/))
|
||||
)
|
||||
)
|
||||
return;
|
||||
|
||||
idx = node->GetIdx();
|
||||
@ -2187,9 +2192,9 @@ double DoubleSlider::get_double_value(const SelectedSlider& selection)
|
||||
return 0.0;
|
||||
if (m_values.size() <= m_higher_value) {
|
||||
correct_higher_value();
|
||||
return m_values.back().second;
|
||||
return m_values.back();
|
||||
}
|
||||
return m_values[selection == ssLower ? m_lower_value : m_higher_value].second;
|
||||
return m_values[selection == ssLower ? m_lower_value : m_higher_value];
|
||||
}
|
||||
|
||||
std::vector<double> DoubleSlider::GetTicksValues() const
|
||||
@ -2201,7 +2206,7 @@ std::vector<double> DoubleSlider::GetTicksValues() const
|
||||
for (int tick : m_ticks) {
|
||||
if (tick > val_size)
|
||||
break;
|
||||
values.push_back(m_values[tick].second);
|
||||
values.push_back(m_values[tick]);
|
||||
}
|
||||
|
||||
return values;
|
||||
@ -2215,14 +2220,13 @@ void DoubleSlider::SetTicksValues(const std::vector<double>& heights)
|
||||
const bool was_empty = m_ticks.empty();
|
||||
|
||||
m_ticks.clear();
|
||||
unsigned int i = 0;
|
||||
for (auto h : heights) {
|
||||
while (i < m_values.size() && m_values[i].second - epsilon()/*1e-6*/ < h)
|
||||
++i;
|
||||
// don't miss last layer if it is
|
||||
if (i == m_values.size() && fabs(m_values[i-1].second - h) > epsilon())
|
||||
return;
|
||||
m_ticks.insert(i-1);
|
||||
auto it = std::lower_bound(m_values.begin(), m_values.end(), h - epsilon());
|
||||
|
||||
if (it == m_values.end())
|
||||
continue;
|
||||
|
||||
m_ticks.insert(it-m_values.begin());
|
||||
}
|
||||
|
||||
if (!was_empty && m_ticks.empty())
|
||||
@ -2342,13 +2346,14 @@ wxString DoubleSlider::get_label(const SelectedSlider& selection) const
|
||||
|
||||
const wxString str = m_values.empty() ?
|
||||
wxNumberFormatter::ToString(m_label_koef*value, 2, wxNumberFormatter::Style_None) :
|
||||
wxNumberFormatter::ToString(m_values[value].second, 2, wxNumberFormatter::Style_None);
|
||||
return wxString::Format("%s\n(%d)", str, m_values.empty() ? value : m_values[value].first);
|
||||
wxNumberFormatter::ToString(m_values[value], 2, wxNumberFormatter::Style_None);
|
||||
return wxString::Format("%s\n(%d)", str, m_values.empty() ? value : value+1);
|
||||
}
|
||||
|
||||
void DoubleSlider::draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const
|
||||
{
|
||||
if ((m_is_one_layer || m_higher_value==m_lower_value) && selection != m_selection || !selection)
|
||||
if ( selection == ssUndef ||
|
||||
((m_is_one_layer || m_higher_value==m_lower_value) && selection != m_selection) )
|
||||
return;
|
||||
wxCoord text_width, text_height;
|
||||
const wxString label = get_label(selection);
|
||||
@ -2680,7 +2685,7 @@ void DoubleSlider::correct_lower_value()
|
||||
else if (m_lower_value > m_max_value)
|
||||
m_lower_value = m_max_value;
|
||||
|
||||
if (m_lower_value >= m_higher_value && m_lower_value <= m_max_value || m_is_one_layer)
|
||||
if ((m_lower_value >= m_higher_value && m_lower_value <= m_max_value) || m_is_one_layer)
|
||||
m_higher_value = m_lower_value;
|
||||
}
|
||||
|
||||
@ -2691,7 +2696,7 @@ void DoubleSlider::correct_higher_value()
|
||||
else if (m_higher_value < m_min_value)
|
||||
m_higher_value = m_min_value;
|
||||
|
||||
if (m_higher_value <= m_lower_value && m_higher_value >= m_min_value || m_is_one_layer)
|
||||
if ((m_higher_value <= m_lower_value && m_higher_value >= m_min_value) || m_is_one_layer)
|
||||
m_lower_value = m_higher_value;
|
||||
}
|
||||
|
||||
|
@ -385,9 +385,9 @@ class ObjectDataViewModel :public wxDataViewModel
|
||||
{
|
||||
std::vector<ObjectDataViewModelNode*> m_objects;
|
||||
std::vector<wxBitmap*> m_volume_bmps;
|
||||
wxBitmap* m_warning_bmp;
|
||||
wxBitmap* m_warning_bmp { nullptr };
|
||||
|
||||
wxDataViewCtrl* m_ctrl{ nullptr };
|
||||
wxDataViewCtrl* m_ctrl { nullptr };
|
||||
|
||||
public:
|
||||
ObjectDataViewModel();
|
||||
@ -720,15 +720,17 @@ public:
|
||||
const wxString& name = wxEmptyString);
|
||||
~DoubleSlider() {}
|
||||
|
||||
// permissible error for layer height
|
||||
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
|
||||
* So, let use same value as a permissible error for layer height.
|
||||
*/
|
||||
static double epsilon() { return 0.0011;}
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
int GetMinValue() const { return m_min_value; }
|
||||
int GetMaxValue() const { return m_max_value; }
|
||||
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value].second; }
|
||||
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value].second; }
|
||||
double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value]; }
|
||||
double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value]; }
|
||||
int GetLowerValue() const { return m_lower_value; }
|
||||
int GetHigherValue() const { return m_higher_value; }
|
||||
int GetActiveValue() const;
|
||||
@ -744,7 +746,7 @@ public:
|
||||
void SetKoefForLabels(const double koef) {
|
||||
m_label_koef = koef;
|
||||
}
|
||||
void SetSliderValues(const std::vector<std::pair<int, double>>& values) {
|
||||
void SetSliderValues(const std::vector<double>& values) {
|
||||
m_values = values;
|
||||
}
|
||||
void ChangeOneLayerLock();
|
||||
@ -865,7 +867,7 @@ private:
|
||||
std::vector<wxPen*> m_line_pens;
|
||||
std::vector<wxPen*> m_segm_pens;
|
||||
std::set<int> m_ticks;
|
||||
std::vector<std::pair<int,double>> m_values;
|
||||
std::vector<double> m_values;
|
||||
};
|
||||
|
||||
|
||||
|
@ -65,13 +65,6 @@ new_from_type(CLASS, type)
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
void
|
||||
make_fill(CLASS, layer_region, out_append)
|
||||
char* CLASS;
|
||||
LayerRegion* layer_region;
|
||||
ExtrusionEntityCollection* out_append;
|
||||
CODE:
|
||||
make_fill(*layer_region, *out_append);
|
||||
%}
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user