Merge branch 'master' into fs_emboss

This commit is contained in:
Filip Sykala - NTB T15p 2023-03-15 10:15:46 +01:00
commit f331bb5edf
33 changed files with 1408 additions and 1141 deletions

View File

@ -13,8 +13,8 @@ if (UNIX AND NOT APPLE) # wxWidgets will not use char as the underlying type for
endif()
prusaslicer_add_cmake_project(wxWidgets
URL https://github.com/prusa3d/wxWidgets/archive/4fd2120c913c20c3bb66ee9d01d8ff5087a8b90a.zip
URL_HASH SHA256=5b59e8b4dccf73e109c6588f6a69bcfe4e02e930af53c43d5d1329c1f3d83ec9
URL https://github.com/prusa3d/wxWidgets/archive/0b49beaacce17d90f0c370ecd73221abd089667a.zip
URL_HASH SHA256=8fa978a76d6bd811b30eecc5124186b9ad54290b820f3a354e85bfa9dae6a5ce
DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG dep_NanoSVG
CMAKE_ARGS
-DwxBUILD_PRECOMP=ON

View File

@ -871,7 +871,7 @@ template<class P> auto rcend(const P& p) -> decltype(_backward(cbegin(p)))
template<class P> TPoint<P> front(const P& p) { return *shapelike::cbegin(p); }
template<class P> TPoint<P> back (const P& p) {
return *backward(shapelike::cend(p));
return *std::prev(shapelike::cend(p));
}
// Optional, does nothing by default

View File

@ -157,26 +157,34 @@ template<class RawShape> class EdgeCache {
void createCache(const RawShape& sh) {
{ // For the contour
auto first = shapelike::cbegin(sh);
auto next = std::next(first);
auto endit = shapelike::cend(sh);
auto first = sl::cbegin(sh);
auto endit = sl::cend(sh);
auto next = first == endit ? endit : std::next(first);
contour_.distances.reserve(shapelike::contourVertexCount(sh));
contour_.distances.reserve(sl::contourVertexCount(sh));
while(next != endit) {
contour_.emap.emplace_back(*(first++), *(next++));
contour_.full_distance += length(contour_.emap.back());
contour_.distances.emplace_back(contour_.full_distance);
}
if constexpr (ClosureTypeV<RawShape> == Closure::OPEN) {
if (sl::contourVertexCount(sh) > 0) {
contour_.emap.emplace_back(sl::back(sh), sl::front(sh));
contour_.full_distance += length(contour_.emap.back());
contour_.distances.emplace_back(contour_.full_distance);
}
}
}
for(auto& h : shapelike::holes(sh)) { // For the holes
auto first = h.begin();
auto next = std::next(first);
auto endit = h.end();
auto first = sl::cbegin(h);
auto endit = sl::cend(h);
auto next = first == endit ? endit :std::next(first);
ContourCache hc;
hc.distances.reserve(endit - first);
hc.distances.reserve(sl::contourVertexCount(h));
while(next != endit) {
hc.emap.emplace_back(*(first++), *(next++));
@ -184,6 +192,14 @@ template<class RawShape> class EdgeCache {
hc.distances.emplace_back(hc.full_distance);
}
if constexpr (ClosureTypeV<RawShape> == Closure::OPEN) {
if (sl::contourVertexCount(h) > 0) {
hc.emap.emplace_back(sl::back(sh), sl::front(sh));
hc.full_distance += length(hc.emap.back());
hc.distances.emplace_back(hc.full_distance);
}
}
holes_.emplace_back(std::move(hc));
}
}
@ -206,7 +222,6 @@ template<class RawShape> class EdgeCache {
contour_.corners.reserve(N / S + 1);
contour_.corners.emplace_back(0.0);
auto N_1 = N-1;
contour_.corners.emplace_back(0.0);
for(size_t i = 0; i < N_1; i += S) {
contour_.corners.emplace_back(
contour_.distances.at(i) / contour_.full_distance);

View File

@ -16,6 +16,7 @@
#include "FillLightning.hpp"
#include "FillConcentric.hpp"
#include "FillEnsuring.hpp"
#include "Polygon.hpp"
namespace Slic3r {
@ -486,14 +487,6 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
size_t first_object_layer_id = this->object()->get_layer(0)->id();
for (SurfaceFill &surface_fill : surface_fills) {
//skip patterns for which additional input is nullptr
switch (surface_fill.params.pattern) {
case ipLightning: if (lightning_generator == nullptr) continue; break;
case ipAdaptiveCubic: if (adaptive_fill_octree == nullptr) continue; break;
case ipSupportCubic: if (support_fill_octree == nullptr) continue; break;
default: break;
}
// 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);
@ -647,7 +640,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
#endif
}
Polylines Layer::generate_sparse_infill_polylines_for_anchoring() const
Polylines Layer::generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator) const
{
std::vector<SurfaceFill> surface_fills = group_fills(*this);
const Slic3r::BoundingBox bbox = this->object()->bounding_box();
@ -656,14 +649,17 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring() const
Polylines sparse_infill_polylines{};
for (SurfaceFill &surface_fill : surface_fills) {
// skip patterns for which additional input is nullptr
if (surface_fill.surface.surface_type != stInternal) {
continue;
}
switch (surface_fill.params.pattern) {
case ipLightning: continue; break;
case ipAdaptiveCubic: continue; break;
case ipSupportCubic: continue; break;
case ipCount: continue; break;
case ipSupportBase: continue; break;
case ipEnsuring: continue; break;
case ipLightning:
case ipAdaptiveCubic:
case ipSupportCubic:
case ipRectilinear:
case ipMonotonic:
case ipMonotonicLines:
@ -688,10 +684,16 @@ Polylines Layer::generate_sparse_infill_polylines_for_anchoring() const
f->layer_id = this->id();
f->z = this->print_z;
f->angle = surface_fill.params.angle;
// f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->adapt_fill_octree = (surface_fill.params.pattern == ipSupportCubic) ? support_fill_octree : adaptive_fill_octree;
f->print_config = &this->object()->print()->config();
f->print_object_config = &this->object()->config();
if (surface_fill.params.pattern == ipLightning) {
auto *lf = dynamic_cast<FillLightning::Filler *>(f.get());
lf->generator = lightning_generator;
lf->num_raft_layers = this->object()->slicing_parameters().raft_layers();
}
// calculate flow spacing for infill pattern generation
double link_max_length = 0.;
if (!surface_fill.params.bridge) {

View File

@ -368,8 +368,12 @@ public:
void make_perimeters();
// Phony version of make_fills() without parameters for Perl integration only.
void make_fills() { this->make_fills(nullptr, nullptr, nullptr); }
void make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive::Octree* support_fill_octree, FillLightning::Generator* lightning_generator);
Polylines generate_sparse_infill_polylines_for_anchoring() const;
void make_fills(FillAdaptive::Octree *adaptive_fill_octree,
FillAdaptive::Octree *support_fill_octree,
FillLightning::Generator *lightning_generator);
Polylines generate_sparse_infill_polylines_for_anchoring(FillAdaptive::Octree *adaptive_fill_octree,
FillAdaptive::Octree *support_fill_octree,
FillLightning::Generator* lightning_generator) const;
void make_ironing();
void export_region_slices_to_svg(const char *path) const;

View File

@ -378,7 +378,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
const double custom_angle = this->region().config().bridge_angle.value;
const auto params = Algorithm::RegionExpansionParameters::build(expansion_bottom_bridge, expansion_step, max_nr_expansion_steps);
bridges.surfaces = custom_angle > 0 ?
expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, shells, params, custom_angle) :
expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, shells, params, Geometry::deg2rad(custom_angle)) :
expand_bridges_detect_orientations(m_fill_surfaces.surfaces, shells, params);
BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done";
#if 0

View File

@ -1500,7 +1500,7 @@ void ModelObject::process_connector_cut(ModelVolume* volume, const Transform3d&
// Perform cut
TriangleMesh upper_mesh, lower_mesh;
process_volume_cut(volume, instance_matrix, cut_matrix, attributes, upper_mesh, lower_mesh);
process_volume_cut(volume, Transform3d::Identity(), cut_matrix, attributes, upper_mesh, lower_mesh);
// add small Z offset to better preview
upper_mesh.translate((-0.05 * Vec3d::UnitZ()).cast<float>());

View File

@ -234,6 +234,7 @@ namespace client
delete m_data.s;
m_type = TYPE_EMPTY;
}
~expr() { reset(); }
enum Type {
TYPE_EMPTY = 0,

View File

@ -267,29 +267,34 @@ ThickLines ThickPolyline::thicklines() const
// Removes the given distance from the end of the ThickPolyline
void ThickPolyline::clip_end(double distance)
{
while (distance > 0) {
Vec2d last_point = this->last_point().cast<double>();
coordf_t last_width = this->width.back();
this->points.pop_back();
this->width.pop_back();
if (this->points.empty())
break;
Vec2d vec = this->last_point().cast<double>() - last_point;
coordf_t width_diff = this->width.back() - last_width;
double vec_length_sqr = vec.squaredNorm();
if (vec_length_sqr > distance * distance) {
double t = (distance / std::sqrt(vec_length_sqr));
this->points.emplace_back((last_point + vec * t).cast<coord_t>());
this->width.emplace_back(last_width + width_diff * t);
assert(this->width.size() == (this->points.size() - 1) * 2);
return;
} else
if (! this->empty()) {
assert(this->width.size() == (this->points.size() - 1) * 2);
while (distance > 0) {
Vec2d last_point = this->last_point().cast<double>();
this->points.pop_back();
if (this->points.empty()) {
assert(this->width.empty());
break;
}
coordf_t last_width = this->width.back();
this->width.pop_back();
distance -= std::sqrt(vec_length_sqr);
Vec2d vec = this->last_point().cast<double>() - last_point;
coordf_t width_diff = this->width.back() - last_width;
double vec_length_sqr = vec.squaredNorm();
if (vec_length_sqr > distance * distance) {
double t = (distance / std::sqrt(vec_length_sqr));
this->points.emplace_back((last_point + vec * t).cast<coord_t>());
this->width.emplace_back(last_width + width_diff * t);
assert(this->width.size() == (this->points.size() - 1) * 2);
return;
} else
this->width.pop_back();
distance -= std::sqrt(vec_length_sqr);
}
}
assert(this->width.size() == (this->points.size() - 1) * 2);
assert(this->points.empty() ? this->width.empty() : this->width.size() == (this->points.size() - 1) * 2);
}
void ThickPolyline::start_at_index(int index)

View File

@ -187,6 +187,7 @@ struct ThickPolyline {
const Point& last_point() const { return this->points.back(); }
size_t size() const { return this->points.size(); }
bool is_valid() const { return this->points.size() >= 2; }
bool empty() const { return this->points.empty(); }
double length() const { return Slic3r::length(this->points); }
void clear() { this->points.clear(); this->width.clear(); }

View File

@ -452,7 +452,7 @@ static std::vector<std::string> s_Preset_print_options {
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops",
"support_material_contact_distance", "support_material_bottom_contact_distance",
"support_material_buildplate_only",
"support_tree_angle", "support_tree_angle_slow", "support_tree_branch_diameter", "support_tree_branch_diameter_angle", "support_tree_top_rate", "support_tree_tip_diameter",
"support_tree_angle", "support_tree_angle_slow", "support_tree_branch_diameter", "support_tree_branch_diameter_angle", "support_tree_top_rate", "support_tree_branch_distance", "support_tree_tip_diameter",
"dont_support_bridges", "thick_bridges", "notes", "complete_objects", "extruder_clearance_radius",
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "gcode_substitutions", "perimeter_extruder",
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",

View File

@ -1185,7 +1185,7 @@ void Print::alert_when_supports_needed()
case SupportSpotsGenerator::SupportPointCause::WeakObjectPart: message = L("thin fragile section"); break;
}
return (critical ? "!" : "") + message;
return message;
};
// vector of pairs of object and its issues, where each issue is a pair of type and critical flag

View File

@ -1,6 +1,8 @@
#ifndef slic3r_Print_hpp_
#define slic3r_Print_hpp_
#include "Fill/FillAdaptive.hpp"
#include "Fill/FillLightning.hpp"
#include "PrintBase.hpp"
#include "BoundingBox.hpp"
@ -385,7 +387,8 @@ private:
void discover_horizontal_shells();
void combine_infill();
void _generate_support_material();
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> prepare_adaptive_infill_data();
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> prepare_adaptive_infill_data(
const std::vector<std::pair<const Surface*, float>>& surfaces_w_bottom_z) const;
FillLightning::GeneratorPtr prepare_lightning_infill_data();
// XYZ in scaled coordinates
@ -410,6 +413,9 @@ private:
// this is set to true when LayerRegion->slices is split in top/internal/bottom
// so that next call to make_perimeters() performs a union() before computing loops
bool m_typed_slices = false;
std::pair<FillAdaptive::OctreePtr, FillAdaptive::OctreePtr> m_adaptive_fill_octrees;
FillLightning::GeneratorPtr m_lightning_generator;
};
struct WipeTowerData

View File

@ -2910,6 +2910,18 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(5));
// Tree Support Branch Distance
// How far apart the branches need to be when they touch the model. Making this distance small will cause
// the tree support to touch the model at more points, causing better overhang but making support harder to remove.
def = this->add("support_tree_branch_distance", coFloat);
def->label = L("Branch Distance");
def->category = L("Support material");
def->tooltip = L("How far apart the branches need to be when they touch the model. "
"Making this distance small will cause the tree support to touch the model at more points, "
"causing better overhang but making support harder to remove.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(1.));
def = this->add("support_tree_top_rate", coPercent);
def->label = L("Branch Density");
def->category = L("Support material");
@ -2921,7 +2933,7 @@ void PrintConfigDef::init_fff_params()
def->min = 5;
def->max_literal = 35;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionPercent(30));
def->set_default_value(new ConfigOptionPercent(15));
def = this->add("temperature", coInts);
def->label = L("Other layers");

View File

@ -555,6 +555,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloat, support_tree_branch_diameter))
((ConfigOptionFloat, support_tree_branch_diameter_angle))
((ConfigOptionPercent, support_tree_top_rate))
((ConfigOptionFloat, support_tree_branch_distance))
((ConfigOptionFloat, support_tree_tip_diameter))
// The rest
((ConfigOptionBool, thick_bridges))

File diff suppressed because it is too large Load Diff

View File

@ -89,7 +89,7 @@ TreeSupportMeshGroupSettings::TreeSupportMeshGroupSettings(const PrintObject &pr
// this->minimum_support_area =
// this->minimum_bottom_area =
// this->support_offset =
// this->support_tree_branch_distance = 2.5 * line_width ??
this->support_tree_branch_distance = scaled<coord_t>(config.support_tree_branch_distance.value);
this->support_tree_angle = std::clamp<double>(config.support_tree_angle * M_PI / 180., 0., 0.5 * M_PI - EPSILON);
this->support_tree_angle_slow = std::clamp<double>(config.support_tree_angle_slow * M_PI / 180., 0., this->support_tree_angle - EPSILON);
this->support_tree_branch_diameter = scaled<coord_t>(config.support_tree_branch_diameter.value);
@ -329,6 +329,7 @@ void TreeModelVolumes::precalculate(const PrintObject& print_object, const coord
for (int k = int(j - 1); k >= int(i); -- k) {
std::string legend = format("radius-%1%", unscaled<float>(sorted[k].first.first));
expolygons_with_attributes.push_back({ union_ex(sorted[k].second), SVG::ExPolygonAttributes(legend, std::string(colors[(k - int(i)) % num_colors]), 1.) });
SVG::export_expolygons(debug_out_path("treesupport_cache-%s-%d-%s.svg", name.data(), sorted[i].first.second, legend.c_str()), { expolygons_with_attributes.back() });
}
// Render the range of per radius collision polygons into a common SVG.
SVG::export_expolygons(debug_out_path("treesupport_cache-%s-%d.svg", name.data(), sorted[i].first.second), expolygons_with_attributes);
@ -416,9 +417,6 @@ const Polygons& TreeModelVolumes::getAvoidance(const coord_t orig_radius, LayerI
const Polygons& TreeModelVolumes::getPlaceableAreas(const coord_t orig_radius, LayerIndex layer_idx, std::function<void()> throw_on_cancel) const
{
if (orig_radius == 0)
return this->getCollision(0, layer_idx, true);
const coord_t radius = ceilRadius(orig_radius);
if (std::optional<std::reference_wrapper<const Polygons>> result = m_placeable_areas_cache.getArea({ radius, layer_idx }); result)
return (*result).get();
@ -426,7 +424,11 @@ const Polygons& TreeModelVolumes::getPlaceableAreas(const coord_t orig_radius, L
BOOST_LOG_TRIVIAL(error_level_not_in_cache) << "Had to calculate Placeable Areas at radius " << radius << " and layer " << layer_idx << ", but precalculate was called. Performance may suffer!";
tree_supports_show_error("Not precalculated Placeable areas requested."sv, false);
}
const_cast<TreeModelVolumes*>(this)->calculatePlaceables(radius, layer_idx, throw_on_cancel);
if (orig_radius == 0)
// Placable areas for radius 0 are calculated in the general collision code.
return this->getCollision(0, layer_idx, true);
else
const_cast<TreeModelVolumes*>(this)->calculatePlaceables(radius, layer_idx, throw_on_cancel);
return getPlaceableAreas(orig_radius, layer_idx, throw_on_cancel);
}
@ -470,6 +472,7 @@ void TreeModelVolumes::calculateCollision(const std::vector<RadiusLayerPair> &ke
});
}
// Calculate collisions and placable areas for radius and for layer 0 to max_layer_idx inclusive.
void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex max_layer_idx, std::function<void()> throw_on_cancel)
{
// assert(radius == this->ceilRadius(radius));
@ -480,12 +483,14 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
std::sort(layer_outline_indices.begin(), layer_outline_indices.end(),
[this](size_t i, size_t j) { return m_layer_outlines[i].second.size() < m_layer_outlines[j].second.size(); });
const LayerIndex min_layer_last = m_collision_cache.getMaxCalculatedLayer(radius);
std::vector<Polygons> data(max_layer_idx + 1 - min_layer_last, Polygons{});
// Layer range for which the collisions will be calculated.
LayerPolygonCache data;
data.allocate(m_collision_cache.getMaxCalculatedLayer(radius) + 1, max_layer_idx + 1);
const bool calculate_placable = m_support_rests_on_model && radius == 0;
std::vector<Polygons> data_placeable;
LayerPolygonCache data_placeable;
if (calculate_placable)
data_placeable = std::vector<Polygons>(max_layer_idx + 1 - min_layer_last, Polygons{});
data_placeable.allocate(data.idx_begin, data.idx_end);
for (size_t outline_idx : layer_outline_indices)
if (const std::vector<Polygons> &outlines = m_layer_outlines[outline_idx].second; ! outlines.empty()) {
@ -493,8 +498,6 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
const coord_t layer_height = settings.layer_height;
const int z_distance_bottom_layers = int(round(double(settings.support_bottom_distance) / double(layer_height)));
const int z_distance_top_layers = int(round(double(settings.support_top_distance) / double(layer_height)));
const LayerIndex max_required_layer = std::min<LayerIndex>(outlines.size(), max_layer_idx + std::max(coord_t(1), z_distance_top_layers));
const LayerIndex min_layer_bottom = std::max<LayerIndex>(0, min_layer_last - int(z_distance_bottom_layers));
const coord_t xy_distance = outline_idx == m_current_outline_idx ? m_current_min_xy_dist :
// technically this causes collision for the normal xy_distance to be larger by m_current_min_xy_dist_delta for all
// not currently processing meshes as this delta will be added at request time.
@ -505,35 +508,40 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
settings.support_xy_distance;
// 1) Calculate offsets of collision areas in parallel.
std::vector<Polygons> collision_areas_offsetted(max_required_layer + 1 - min_layer_bottom);
tbb::parallel_for(tbb::blocked_range<LayerIndex>(min_layer_bottom, max_required_layer + 1),
[&outlines, &machine_border = std::as_const(m_machine_border), offset_value = radius + xy_distance, min_layer_bottom, &collision_areas_offsetted, &throw_on_cancel]
LayerPolygonCache collision_areas_offsetted;
collision_areas_offsetted.allocate(
std::max<LayerIndex>(0, data.idx_begin - z_distance_bottom_layers),
std::min<LayerIndex>(outlines.size(), data.idx_end + z_distance_top_layers));
tbb::parallel_for(tbb::blocked_range<LayerIndex>(collision_areas_offsetted.idx_begin, collision_areas_offsetted.idx_end),
[&outlines, &machine_border = std::as_const(m_machine_border), offset_value = radius + xy_distance, &collision_areas_offsetted, &throw_on_cancel]
(const tbb::blocked_range<LayerIndex> &range) {
for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++ layer_idx) {
Polygons collision_areas = machine_border;
append(collision_areas, outlines[layer_idx]);
// jtRound is not needed here, as the overshoot can not cause errors in the algorithm, because no assumptions are made about the model.
// if a key does not exist when it is accessed it is added!
collision_areas_offsetted[layer_idx - min_layer_bottom] = offset_value == 0 ? union_(collision_areas) : offset(union_ex(collision_areas), offset_value, ClipperLib::jtMiter, 1.2);
collision_areas_offsetted[layer_idx] = offset_value == 0 ?
union_(collision_areas) :
offset(union_ex(collision_areas), offset_value, ClipperLib::jtMiter, 1.2);
throw_on_cancel();
}
});
// 2) Sum over top / bottom ranges.
const bool last = outline_idx == layer_outline_indices.size();
tbb::parallel_for(tbb::blocked_range<LayerIndex>(min_layer_last + 1, max_layer_idx + 1),
[&collision_areas_offsetted, &outlines, &machine_border = m_machine_border, &anti_overhang = m_anti_overhang, min_layer_bottom, radius,
xy_distance, z_distance_bottom_layers, z_distance_top_layers, min_resolution = m_min_resolution, &data, min_layer_last, last, &throw_on_cancel]
(const tbb::blocked_range<LayerIndex>& range) {
for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++layer_idx) {
const bool processing_last_mesh = outline_idx == layer_outline_indices.size();
tbb::parallel_for(tbb::blocked_range<LayerIndex>(data.idx_begin, data.idx_end),
[&collision_areas_offsetted, &outlines, &machine_border = m_machine_border, &anti_overhang = m_anti_overhang, radius,
xy_distance, z_distance_bottom_layers, z_distance_top_layers, min_resolution = m_min_resolution, &data, processing_last_mesh, &throw_on_cancel]
(const tbb::blocked_range<LayerIndex>& range) {
for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++ layer_idx) {
Polygons collisions;
for (int i = -z_distance_bottom_layers; i <= z_distance_top_layers; ++ i) {
int j = layer_idx + i - min_layer_bottom;
if (j >= 0 && j < int(collision_areas_offsetted.size()) && i <= 0)
for (int i = - z_distance_bottom_layers; i <= 0; ++ i)
if (int j = layer_idx + i; collision_areas_offsetted.has(j))
append(collisions, collision_areas_offsetted[j]);
else if (j >= 0 && layer_idx + i < int(outlines.size()) && i > 0) {
for (int i = 1; i <= z_distance_top_layers; ++ i)
if (int j = layer_idx + i; j < int(outlines.size())) {
Polygons collision_areas_original = machine_border;
append(collision_areas_original, outlines[layer_idx + i]);
append(collision_areas_original, outlines[j]);
// If just the collision (including the xy distance) of the layers above is accumulated, it leads to the
// following issue:
@ -566,37 +574,37 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
// the conditional -0.5 ensures that plastic can never touch on the diagonal
// downward when the z_distance_top_layers = 1. It is assumed to be better to
// not support an overhang<90 degree than to risk fusing to it.
collision_areas_original = offset(union_ex(collision_areas_original), radius + required_range_x, ClipperLib::jtMiter, 1.2);
append(collisions, collision_areas_original);
append(collisions, offset(union_ex(collision_areas_original), radius + required_range_x, ClipperLib::jtMiter, 1.2));
}
}
collisions = last && layer_idx < int(anti_overhang.size()) ? union_(collisions, offset(union_ex(anti_overhang[layer_idx]), radius, ClipperLib::jtMiter, 1.2)) : union_(collisions);
auto &dst = data[layer_idx - (min_layer_last + 1)];
if (last) {
collisions = processing_last_mesh && layer_idx < int(anti_overhang.size()) ?
union_(collisions, offset(union_ex(anti_overhang[layer_idx]), radius, ClipperLib::jtMiter, 1.2)) :
union_(collisions);
auto &dst = data[layer_idx];
if (processing_last_mesh) {
if (! dst.empty())
collisions = union_(collisions, dst);
dst = polygons_simplify(collisions, min_resolution);
} else
append(dst, collisions);
append(dst, std::move(collisions));
throw_on_cancel();
}
});
// 3) Optionally calculate placables.
if (calculate_placable) {
// Calculating both the collision areas and placable areas.
tbb::parallel_for(tbb::blocked_range<LayerIndex>(std::max(min_layer_last + 1, z_distance_bottom_layers + 1), max_layer_idx + 1),
[&collision_areas_offsetted, &anti_overhang = m_anti_overhang, min_layer_bottom, z_distance_bottom_layers, last, min_resolution = m_min_resolution, &data_placeable, min_layer_last, &throw_on_cancel]
// Now calculate the placable areas.
tbb::parallel_for(tbb::blocked_range<LayerIndex>(std::max(data.idx_begin, 1), data.idx_end),
[&collision_areas_offsetted, &anti_overhang = m_anti_overhang, processing_last_mesh,
min_resolution = m_min_resolution, &data_placeable, &throw_on_cancel]
(const tbb::blocked_range<LayerIndex>& range) {
for (LayerIndex layer_idx = range.begin(); layer_idx != range.end(); ++ layer_idx) {
LayerIndex layer_idx_below = layer_idx - (z_distance_bottom_layers + 1) - min_layer_bottom;
LayerIndex layer_idx_below = layer_idx - 1;
assert(layer_idx_below >= 0);
auto &current = collision_areas_offsetted[layer_idx - min_layer_bottom];
auto &below = collision_areas_offsetted[layer_idx_below];
auto placable = diff(below, layer_idx < int(anti_overhang.size()) ? union_(current, anti_overhang[layer_idx - (z_distance_bottom_layers + 1)]) : current);
auto &dst = data_placeable[layer_idx - (min_layer_last + 1)];
if (last) {
const Polygons &current = collision_areas_offsetted[layer_idx];
const Polygons &below = collision_areas_offsetted[layer_idx_below];
Polygons placable = diff(below, layer_idx_below < int(anti_overhang.size()) ? union_(current, anti_overhang[layer_idx_below]) : current);
auto &dst = data_placeable[layer_idx];
if (processing_last_mesh) {
if (! dst.empty())
placable = union_(placable, dst);
dst = polygons_simplify(placable, min_resolution);
@ -619,9 +627,9 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
}
#endif
throw_on_cancel();
m_collision_cache.insert(std::move(data), min_layer_last + 1, radius);
m_collision_cache.insert(std::move(data), radius);
if (calculate_placable)
m_placeable_areas_cache.insert(std::move(data_placeable), min_layer_last + 1, radius);
m_placeable_areas_cache.insert(std::move(data_placeable), radius);
}
void TreeModelVolumes::calculateCollisionHolefree(const std::vector<RadiusLayerPair> &keys, std::function<void()> throw_on_cancel)

View File

@ -328,6 +328,26 @@ public:
}
private:
// Caching polygons for a range of layers.
struct LayerPolygonCache {
std::vector<Polygons> polygons;
LayerIndex idx_begin;
LayerIndex idx_end;
void allocate(LayerIndex aidx_begin, LayerIndex aidx_end) {
this->idx_begin = aidx_begin;
this->idx_end = aidx_end;
this->polygons.assign(aidx_end - aidx_begin, {});
}
LayerIndex begin() const { return idx_begin; }
LayerIndex end() const { return idx_end; }
size_t size() const { return polygons.size(); }
bool has(LayerIndex idx) const { return idx >= idx_begin && idx < idx_end; }
Polygons& operator[](LayerIndex idx) { return polygons[idx + idx_begin]; }
};
/*!
* \brief Convenience typedef for the keys to the caches
*/
@ -363,6 +383,13 @@ private:
for (auto &d : in)
m_data[first_layer_idx ++].emplace(radius, std::move(d));
}
void insert(LayerPolygonCache &&in, coord_t radius) {
std::lock_guard<std::mutex> guard(m_mutex);
LayerIndex i = in.idx_begin;
allocate_layers(i + LayerIndex(in.size()));
for (auto &d : in.polygons)
m_data[i ++].emplace(radius, std::move(d));
}
/*!
* \brief Checks a cache for a given RadiusLayerPair and returns it if it is found
* \param key RadiusLayerPair of the requested areas. The radius will be calculated up to the provided layer.

File diff suppressed because it is too large Load Diff

View File

@ -122,7 +122,7 @@ struct SupportElementStateBits {
bool use_min_xy_dist : 1;
/*!
* \brief True if this Element or any parent provides support to a support roof.
* \brief True if this Element or any parent (element above) provides support to a support roof.
*/
bool supports_roof : 1;
@ -193,7 +193,7 @@ struct SupportElementState : public SupportElementStateBits
double elephant_foot_increases;
/*!
* \brief The element trys not to move until this dtt is reached, is set to 0 if the element had to move.
* \brief The element tries to not move until this dtt is reached, is set to 0 if the element had to move.
*/
uint32_t dont_move_until;
@ -218,6 +218,8 @@ struct SupportElementState : public SupportElementStateBits
dst.skip_ovalisation = false;
return dst;
}
[[nodiscard]] bool locked() const { return this->distance_to_top < this->dont_move_until; }
};
struct SupportElement

View File

@ -34,6 +34,10 @@
// #define SLIC3R_DEBUG_SLICE_PROCESSING
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
#define DEBUG_INTERSECTIONLINE
#endif
#if defined(SLIC3R_DEBUG) || defined(SLIC3R_DEBUG_SLICE_PROCESSING)
#include "SVG.hpp"
#endif
@ -125,7 +129,7 @@ public:
};
uint32_t flags { 0 };
#if DEBUG_INTERSECTIONLINE
#ifdef DEBUG_INTERSECTIONLINE
enum class Source {
BottomPlane,
TopPlane,
@ -1446,19 +1450,19 @@ static std::vector<Polygons> make_slab_loops(
for (const IntersectionLine &l : lines.at_slice[slice_below])
if (l.edge_type != IntersectionLine::FacetEdgeType::Top) {
in.emplace_back(l);
#if DEBUG_INTERSECTIONLINE
#ifdef DEBUG_INTERSECTIONLINE
in.back().source = IntersectionLine::Source::BottomPlane;
#endif // DEBUG_INTERSECTIONLINE
}
}
{
// Edges in between slice_below and slice_above.
#if DEBUG_INTERSECTIONLINE
#ifdef DEBUG_INTERSECTIONLINE
size_t old_size = in.size();
#endif // DEBUG_INTERSECTIONLINE
// Edge IDs of end points on in-between lines that touch the layer above are already increased with num_edges.
append(in, lines.between_slices[line_idx]);
#if DEBUG_INTERSECTIONLINE
#ifdef DEBUG_INTERSECTIONLINE
for (auto it = in.begin() + old_size; it != in.end(); ++ it) {
assert(it->edge_type == IntersectionLine::FacetEdgeType::Slab);
it->source = IntersectionLine::Source::Slab;
@ -1476,7 +1480,7 @@ static std::vector<Polygons> make_slab_loops(
l.edge_a_id += num_edges;
if (l.edge_b_id >= 0)
l.edge_b_id += num_edges;
#if DEBUG_INTERSECTIONLINE
#ifdef DEBUG_INTERSECTIONLINE
l.source = IntersectionLine::Source::TopPlane;
#endif // DEBUG_INTERSECTIONLINE
}

View File

@ -157,26 +157,23 @@ Point Bed3D::point_projection(const Point& point) const
return m_polygon.point_projection(point);
}
void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes, bool show_texture)
void Bed3D::render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_texture)
{
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, show_axes, show_texture, false);
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, show_texture, false);
}
void Bed3D::render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor)
{
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, false, false, true);
render_internal(canvas, view_matrix, projection_matrix, bottom, scale_factor, false, true);
}
void Bed3D::render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor,
bool show_axes, bool show_texture, bool picking)
bool show_texture, bool picking)
{
m_scale_factor = scale_factor;
glsafe(::glEnable(GL_DEPTH_TEST));
if (show_axes)
render_axes();
m_model.model.set_color(picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR);
switch (m_type)
@ -366,9 +363,6 @@ std::tuple<Bed3D::Type, std::string, std::string> Bed3D::detect_type(const Point
void Bed3D::render_axes()
{
if (!m_show_axes)
return;
if (m_build_volume.valid())
#if ENABLE_WORLD_COORDINATE
m_axes.render(Transform3d::Identity(), 0.25f);

View File

@ -84,7 +84,6 @@ private:
#endif // ENABLE_WORLD_COORDINATE
float m_scale_factor{ 1.0f };
bool m_show_axes{ true };
public:
Bed3D() = default;
@ -112,9 +111,8 @@ public:
bool contains(const Point& point) const;
Point point_projection(const Point& point) const;
void toggle_show_axes() { m_show_axes = !m_show_axes; }
void render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_axes, bool show_texture);
void render(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor, bool show_texture);
void render_axes();
void render_for_picking(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor);
private:
@ -125,8 +123,7 @@ private:
void init_contourlines();
static std::tuple<Type, std::string, std::string> detect_type(const Pointfs& shape);
void render_internal(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, float scale_factor,
bool show_axes, bool show_texture, bool picking);
void render_axes();
bool show_texture, bool picking);
void render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture);
void render_texture(bool bottom, GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix);
void render_model(const Transform3d& view_matrix, const Transform3d& projection_matrix);

View File

@ -291,7 +291,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
(config->opt_bool("support_material") ||
config->opt_int("support_material_enforce_layers") > 0);
for (const std::string& key : { "support_tree_angle", "support_tree_angle_slow", "support_tree_branch_diameter",
"support_tree_branch_diameter_angle", "support_tree_tip_diameter", "support_tree_top_rate" })
"support_tree_branch_diameter_angle", "support_tree_tip_diameter", "support_tree_branch_distance", "support_tree_top_rate" })
toggle_field(key, has_organic_supports);
for (auto el : { "support_material_bottom_interface_layers", "support_material_interface_spacing", "support_material_interface_extruder",

View File

@ -206,7 +206,7 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
reduce_stack(stack, struct_size);
}
if (!file.has_extension() && stack.size() == struct_size)
stack.push_back(avc->get_model()->AddFile((stack.empty() ? std::shared_ptr<ArchiveViewNode>(nullptr) : stack.back()), GUI::format_wxstr(file.filename().string()), true)); // filename string to wstring?
stack.push_back(avc->get_model()->AddFile((stack.empty() ? std::shared_ptr<ArchiveViewNode>(nullptr) : stack.back()), boost::nowide::widen(file.filename().string()), true)); // filename string to wstring?
return struct_size + 1;
};
@ -223,7 +223,7 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
path = boost::filesystem::path(extra.substr(0, extra_size));
} else {
wxString wname = boost::nowide::widen(stat.m_filename);
std::string name = GUI::format(wname);
std::string name = boost::nowide::narrow(wname);
path = boost::filesystem::path(name);
}
assert(!path.empty());
@ -247,7 +247,7 @@ FileArchiveDialog::FileArchiveDialog(wxWindow* parent_window, mz_zip_archive* ar
if (!stack.empty())
parent = stack.back();
if (std::regex_match(path.extension().string(), pattern_drop)) { // this leaves out non-compatible files
m_avc->get_model()->AddFile(parent, GUI::format_wxstr(path.filename().string()), false)->set_fullpath(/*std::move(path)*/path); // filename string to wstring?
m_avc->get_model()->AddFile(parent, boost::nowide::widen(path.filename().string()), false)->set_fullpath(/*std::move(path)*/path); // filename string to wstring?
entry_count++;
}
}

View File

@ -1573,8 +1573,10 @@ void GLCanvas3D::render()
_render_objects(GLVolumeCollection::ERenderType::Opaque);
_render_sla_slices();
_render_selection();
if (m_show_bed_axes)
_render_bed_axes();
if (is_looking_downward)
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), false, true);
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), false);
if (!m_main_toolbar.is_enabled())
_render_gcode();
_render_objects(GLVolumeCollection::ERenderType::Transparent);
@ -1597,7 +1599,7 @@ void GLCanvas3D::render()
_render_selection_sidebar_hints();
_render_current_gizmo();
if (!is_looking_downward)
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), true, true);
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), true);
#if ENABLE_RAYCAST_PICKING_DEBUG
if (m_picking_enabled && !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging())
@ -2355,7 +2357,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
#else /* __APPLE__ */
case WXK_CONTROL_D:
#endif /* __APPLE__ */
m_bed.toggle_show_axes();
m_show_bed_axes = !m_show_bed_axes;
m_dirty = true;
break;
#ifdef __APPLE__
@ -4423,7 +4425,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
glsafe(::glDisable(GL_DEPTH_TEST));
if (thumbnail_params.show_bed)
_render_bed(view_matrix, projection_matrix, !camera.is_looking_downward(), false);
_render_bed(view_matrix, projection_matrix, !camera.is_looking_downward());
// restore background color
if (thumbnail_params.transparent_background)
@ -5477,7 +5479,7 @@ void GLCanvas3D::_render_background()
glsafe(::glEnable(GL_DEPTH_TEST));
}
void GLCanvas3D::_render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes)
void GLCanvas3D::_render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom)
{
float scale_factor = 1.0;
#if ENABLE_RETINA_GL
@ -5491,7 +5493,12 @@ void GLCanvas3D::_render_bed(const Transform3d& view_matrix, const Transform3d&
&& m_gizmos.get_current_type() != GLGizmosManager::Seam
&& m_gizmos.get_current_type() != GLGizmosManager::MmuSegmentation);
m_bed.render(*this, view_matrix, projection_matrix, bottom, scale_factor, show_axes, show_texture);
m_bed.render(*this, view_matrix, projection_matrix, bottom, scale_factor, show_texture);
}
void GLCanvas3D::_render_bed_axes()
{
m_bed.render_axes();
}
void GLCanvas3D::_render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom)

View File

@ -522,6 +522,7 @@ private:
ECursorType m_cursor_type;
GLSelectionRectangle m_rectangle_selection;
std::vector<int> m_hover_volume_idxs;
bool m_show_bed_axes{ true };
// Following variable is obsolete and it should be safe to remove it.
// I just don't want to do it now before a release (Lukas Matena 24.3.2019)
@ -984,7 +985,8 @@ private:
void _picking_pass();
void _rectangular_selection_picking_pass();
void _render_background();
void _render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes);
void _render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom);
void _render_bed_axes();
void _render_bed_for_picking(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom);
void _render_objects(GLVolumeCollection::ERenderType type);
void _render_gcode();

View File

@ -2305,18 +2305,6 @@ bool GUI_App::load_language(wxString language, bool initial)
// Override language at the active wxTranslations class (which is stored in the active m_wxLocale)
// to load possibly different dictionary, for example, load Czech dictionary for Slovak language.
wxTranslations::Get()->SetLanguage(language_dict);
{
// ysFIXME after fix for wxWidgets issue (https://github.com/wxWidgets/wxWidgets/issues/23210)
// UKR Localization specific workaround till the wxWidgets doesn't fixed:
// From wxWidgets 3.1.6 calls setlocation(0, wxInfoLanguage->LocaleTag), see (https://github.com/prusa3d/wxWidgets/commit/deef116a09748796711d1e3509965ee208dcdf0b#diff-7de25e9a71c4dce61bbf76492c589623d5b93fd1bb105ceaf0662075d15f4472),
// where LocaleTag is a Tag of locale in BCP 47 - like notation.
// For Ukrainian Language LocaleTag is "uk".
// But setlocale(0, "uk") returns "English_United Kingdom.1252" instead of "uk",
// and, as a result, locales are set to English_United Kingdom
if (language_info->CanonicalName == "uk")
setlocale(0, language_info->GetCanonicalWithRegion().data());
}
m_wxLocale->AddCatalog(SLIC3R_APP_KEY);
m_imgui->set_language(into_u8(language_info->CanonicalName));
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.

View File

@ -707,6 +707,12 @@ void ObjectManipulation::update_ui_from_settings()
void ObjectManipulation::update_settings_value(const Selection& selection)
{
if (selection.is_empty()) {
// No selection, reset the cache.
reset_settings_value();
return;
}
m_new_move_label_string = L("Position");
m_new_rotate_label_string = L("Rotation");
m_new_scale_label_string = L("Scale factors");
@ -836,11 +842,6 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
#endif // ENABLE_WORLD_COORDINATE
m_new_enabled = true;
}
else {
// No selection, reset the cache.
// assert(selection.is_empty());
reset_settings_value();
}
}
void ObjectManipulation::update_if_dirty()
@ -1395,8 +1396,9 @@ void ObjectManipulation::on_change(const std::string& opt_key, int axis, double
if (new_value > 0.0)
change_size_value(axis, new_value);
else {
new_value = m_cache.size(axis);
m_cache.size(axis) = 0.0;
Vec3d& size = m_imperial_units ? m_cache.size_inches : m_cache.size;
new_value = size(axis);
size(axis) = 0.0;
m_cache.size_rounded(axis) = DBL_MAX;
change_size_value(axis, new_value);
}

View File

@ -799,7 +799,7 @@ void GLGizmoCut3D::render_cut_plane_grabbers()
void GLGizmoCut3D::render_cut_line()
{
if (!cut_line_processing() || m_line_end == Vec3d::Zero())
if (!cut_line_processing() || m_line_end.isApprox(Vec3d::Zero()))
return;
glsafe(::glEnable(GL_DEPTH_TEST));
@ -1130,7 +1130,7 @@ void GLGizmoCut3D::dragging_grabber_xy(const GLGizmoBase::UpdateData &data)
rotation[m_hover_id] = theta;
const Transform3d rotation_tmp = m_start_dragging_m * rotation_transform(rotation);
const bool update_tbb = m_rotation_m.rotation() != rotation_tmp.rotation();
const bool update_tbb = !m_rotation_m.rotation().isApprox(rotation_tmp.rotation());
m_rotation_m = rotation_tmp;
if (update_tbb)
m_transformed_bounding_box = transformed_bounding_box(m_plane_center, m_rotation_m);
@ -1262,7 +1262,7 @@ void GLGizmoCut3D::update_bb()
const BoundingBoxf3 box = bounding_box();
if (!box.defined)
return;
if (m_max_pos != box.max || m_min_pos != box.min) {
if (!m_max_pos.isApprox(box.max) || !m_min_pos.isApprox(box.min)) {
m_bounding_box = box;
@ -1679,7 +1679,7 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors)
const bool has_connectors = !connectors.empty();
const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && m_bb_center == m_plane_center;
const bool is_cut_plane_init = m_rotation_m.isApprox(Transform3d::Identity()) && m_bb_center.isApprox(m_plane_center);
m_imgui->disabled_begin(is_cut_plane_init);
wxString act_name = _L("Reset cutting plane");
if (render_reset_button("cut_plane", into_u8(act_name))) {
@ -2247,7 +2247,7 @@ void GLGizmoCut3D::update_connector_shape()
bool GLGizmoCut3D::cut_line_processing() const
{
return m_line_beg != Vec3d::Zero();
return !m_line_beg.isApprox(Vec3d::Zero());
}
void GLGizmoCut3D::discard_cut_line_processing()

View File

@ -5576,7 +5576,7 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path)
for (mz_uint i = 0; i < num_entries; ++i) {
if (mz_zip_reader_file_stat(&archive, i, &stat)) {
wxString wname = boost::nowide::widen(stat.m_filename);
std::string name = GUI::format(wname);
std::string name = boost::nowide::narrow(wname);
fs::path archive_path(name);
std::string extra(1024, 0);
@ -6503,9 +6503,9 @@ void Plater::export_stl_obj(bool extended, bool selection_only)
}
}
if (path.EndsWith(".stl"))
if (path.Lower().EndsWith(".stl"))
Slic3r::store_stl(path_u8.c_str(), &mesh, true);
else if (path.EndsWith(".obj"))
else if (path.Lower().EndsWith(".obj"))
Slic3r::store_obj(path_u8.c_str(), &mesh);
// p->statusbar()->set_status_text(format_wxstr(_L("STL file exported to %s"), path));
}

View File

@ -1531,6 +1531,7 @@ void TabPrint::build()
optgroup->append_single_option_line("support_tree_branch_diameter", category_path + "tree_branch_diameter");
optgroup->append_single_option_line("support_tree_branch_diameter_angle", category_path + "tree_branch_diameter_angle");
optgroup->append_single_option_line("support_tree_tip_diameter", category_path + "tree_tip_diameter");
optgroup->append_single_option_line("support_tree_branch_distance", category_path + "tree_branch_distance");
optgroup->append_single_option_line("support_tree_top_rate", category_path + "tree_top_rate");
page = add_options_page(L("Speed"), "time");

View File

@ -1024,9 +1024,15 @@ TEST_CASE("pointOnPolygonContour", "[Geometry]") {
REQUIRE(getX(first) == getX(ecache.coords(0)));
REQUIRE(getY(first) == getY(ecache.coords(0)));
auto last = *std::prev(input.end());
REQUIRE(getX(last) == getX(ecache.coords(1.0)));
REQUIRE(getY(last) == getY(ecache.coords(1.0)));
if constexpr (ClosureTypeV<PolygonImpl> == Closure::CLOSED) {
auto last = *std::prev(input.end());
REQUIRE(getX(last) == getX(ecache.coords(1.0)));
REQUIRE(getY(last) == getY(ecache.coords(1.0)));
} else {
auto last = *input.begin();
REQUIRE(getX(last) == getX(ecache.coords(1.0)));
REQUIRE(getY(last) == getY(ecache.coords(1.0)));
}
for(int i = 0; i <= 100; i++) {
auto v = ecache.coords(i*(0.01));