This commit is contained in:
enricoturri1966 2023-05-19 09:44:52 +02:00
commit 1619152350
19 changed files with 146 additions and 73 deletions

View file

@ -1,9 +1,9 @@
#ifndef ARRANGE_HPP
#define ARRANGE_HPP
#include "ExPolygon.hpp"
#include <boost/variant.hpp>
#include <libslic3r/ExPolygon.hpp>
#include <libslic3r/BoundingBox.hpp>
namespace Slic3r {

View file

@ -71,9 +71,11 @@ ThickPolylines make_fill_polylines(
vertical_lines[i].a = Point{x, y_min};
vertical_lines[i].b = Point{x, y_max};
}
vertical_lines.push_back(vertical_lines.back());
vertical_lines.back().a = Point{coord_t(bb.min.x() + n_vlines * double(scaled_spacing) + scaled_spacing * 0.5), y_min};
vertical_lines.back().b = Point{vertical_lines.back().a.x(), y_max};
if (vertical_lines.size() > 0) {
vertical_lines.push_back(vertical_lines.back());
vertical_lines.back().a = Point{coord_t(bb.min.x() + n_vlines * double(scaled_spacing) + scaled_spacing * 0.5), y_min};
vertical_lines.back().b = Point{vertical_lines.back().a.x(), y_max};
}
std::vector<std::vector<Line>> polygon_sections(n_vlines);
@ -276,7 +278,7 @@ ThickPolylines make_fill_polylines(
}
}
reconstructed_area = closing(reconstructed_area, float(SCALED_EPSILON), float(SCALED_EPSILON));
reconstructed_area = union_safety_offset(reconstructed_area);
ExPolygons gaps_for_additional_filling = diff_ex(filled_area, reconstructed_area);
if (fill->overlap != 0) {
gaps_for_additional_filling = offset_ex(gaps_for_additional_filling, scaled<float>(fill->overlap));

View file

@ -882,14 +882,20 @@ namespace client
}
}
if (opt == nullptr)
ctx->throw_exception("Variable does not exist", IteratorRange(opt_key.begin(), opt_key.end()));
if (opt->is_scalar())
ctx->throw_exception("Variable does not exist", opt_key);
if (opt->is_scalar()) {
if (opt->is_nil())
ctx->throw_exception("Trying to reference an undefined (nil) optional variable", opt_key);
output = opt->serialize();
else {
} else {
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt);
if (vec->empty())
ctx->throw_exception("Indexing an empty vector variable", opt_key);
output = vec->vserialize()[(idx >= vec->size()) ? 0 : idx];
if (idx >= vec->size())
idx = 0;
if (vec->is_nil(idx))
ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt_key);
output = vec->vserialize()[idx];
}
}
@ -917,7 +923,7 @@ namespace client
ctx->throw_exception("Trying to index a scalar variable", opt_key);
const ConfigOptionVectorBase *vec = static_cast<const ConfigOptionVectorBase*>(opt);
if (vec->empty())
ctx->throw_exception("Indexing an empty vector variable", IteratorRange(opt_key.begin(), opt_key.end()));
ctx->throw_exception("Indexing an empty vector variable", opt_key);
const ConfigOption *opt_index = ctx->resolve_symbol(std::string(opt_vector_index.begin(), opt_vector_index.end()));
if (opt_index == nullptr)
ctx->throw_exception("Variable does not exist", opt_key);
@ -926,7 +932,11 @@ namespace client
int idx = opt_index->getInt();
if (idx < 0)
ctx->throw_exception("Negative vector index", opt_key);
output = vec->vserialize()[(idx >= (int)vec->size()) ? 0 : idx];
if (idx >= (int)vec->size())
idx = 0;
if (vec->is_nil(idx))
ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt_key);
output = vec->vserialize()[idx];
}
static void resolve_variable(
@ -976,6 +986,9 @@ namespace client
assert(opt.opt->is_scalar());
if (opt.opt->is_nil())
ctx->throw_exception("Trying to reference an undefined (nil) optional variable", opt.it_range);
switch (opt.opt->type()) {
case coFloat: output.set_d(opt.opt->getFloat()); break;
case coInt: output.set_i(opt.opt->getInt()); break;
@ -1041,6 +1054,8 @@ namespace client
if (vec->empty())
ctx->throw_exception("Indexing an empty vector variable", opt.it_range);
size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index);
if (vec->is_nil(idx))
ctx->throw_exception("Trying to reference an undefined (nil) element of vector of optional values", opt.it_range);
switch (opt.opt->type()) {
case coFloats: output.set_d(static_cast<const ConfigOptionFloats*>(opt.opt)->values[idx]); break;
case coInts: output.set_i(static_cast<const ConfigOptionInts*>(opt.opt)->values[idx]); break;
@ -1434,6 +1449,8 @@ namespace client
assert(lhs.opt->is_vector());
if (rhs.has_index() || ! rhs.opt->is_vector())
ctx->throw_exception("Cannot assign scalar to a vector", lhs.it_range);
if (rhs.opt->is_nil())
ctx->throw_exception("Some elements of the right hand side vector variable of optional values are undefined (nil)", rhs.it_range);
if (lhs.opt->type() != rhs.opt->type()) {
// Vector types are not compatible.
switch (lhs.opt->type()) {
@ -1470,6 +1487,8 @@ namespace client
if (rhs.has_index() || ! rhs.opt->is_vector())
// Stop parsing, let the other rules resolve this case.
return false;
if (rhs.opt->is_nil())
ctx->throw_exception("Some elements of the right hand side vector variable of optional values are undefined (nil)", rhs.it_range);
// Clone the vector variable.
std::unique_ptr<ConfigOption> opt_new;
if (one_of(rhs.opt->type(), { coFloats, coInts, coStrings, coBools }))

View file

@ -2186,6 +2186,7 @@ void PrintObject::bridge_over_infill()
Polygon &new_poly = expanded_bridged_area.emplace_back(std::move(traced_poly.lows));
new_poly.points.insert(new_poly.points.end(), traced_poly.highs.rbegin(), traced_poly.highs.rend());
}
expanded_bridged_area = union_safety_offset(expanded_bridged_area);
}
polygons_rotate(expanded_bridged_area, -aligning_angle);

View file

@ -497,7 +497,7 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
const bool calculate_placable = m_support_rests_on_model && radius == 0;
LayerPolygonCache data_placeable;
if (calculate_placable)
data_placeable.allocate(data.idx_begin, data.idx_end);
data_placeable.allocate(data.begin(), data.end());
for (size_t outline_idx : layer_outline_indices)
if (const std::vector<Polygons> &outlines = m_layer_outlines[outline_idx].second; ! outlines.empty()) {
@ -517,9 +517,9 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
// 1) Calculate offsets of collision areas in parallel.
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),
std::max<LayerIndex>(0, data.begin() - z_distance_bottom_layers),
std::min<LayerIndex>(outlines.size(), data.end() + z_distance_top_layers));
tbb::parallel_for(tbb::blocked_range<LayerIndex>(collision_areas_offsetted.begin(), collision_areas_offsetted.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) {
@ -536,7 +536,7 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
// 2) Sum over top / bottom ranges.
const bool processing_last_mesh = outline_idx == layer_outline_indices.size();
tbb::parallel_for(tbb::blocked_range<LayerIndex>(data.idx_begin, data.idx_end),
tbb::parallel_for(tbb::blocked_range<LayerIndex>(data.begin(), data.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) {
@ -600,7 +600,7 @@ void TreeModelVolumes::calculateCollision(const coord_t radius, const LayerIndex
// 3) Optionally calculate placables.
if (calculate_placable) {
// Now calculate the placable areas.
tbb::parallel_for(tbb::blocked_range<LayerIndex>(std::max(z_distance_bottom_layers + 1, data.idx_begin), data.idx_end),
tbb::parallel_for(tbb::blocked_range<LayerIndex>(std::max(z_distance_bottom_layers + 1, data.begin()), data.end()),
[&collision_areas_offsetted, &outlines, &anti_overhang = m_anti_overhang, processing_last_mesh,
min_resolution = m_min_resolution, z_distance_bottom_layers, xy_distance, &data_placeable, &throw_on_cancel]
(const tbb::blocked_range<LayerIndex>& range) {

View file

@ -332,23 +332,26 @@ public:
private:
// Caching polygons for a range of layers.
struct LayerPolygonCache {
std::vector<Polygons> polygons;
LayerIndex idx_begin;
LayerIndex idx_end;
class LayerPolygonCache {
public:
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, {});
m_idx_begin = aidx_begin;
m_idx_end = aidx_end;
m_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(); }
LayerIndex begin() const { return m_idx_begin; }
LayerIndex end() const { return m_idx_end; }
size_t size() const { return m_polygons.size(); }
bool has(LayerIndex idx) const { return idx >= idx_begin && idx < idx_end; }
Polygons& operator[](LayerIndex idx) { return polygons[idx + idx_begin]; }
bool has(LayerIndex idx) const { return idx >= m_idx_begin && idx < m_idx_end; }
Polygons& operator[](LayerIndex idx) { assert(idx >= m_idx_begin && idx < m_idx_end); return m_polygons[idx - m_idx_begin]; }
std::vector<Polygons>& polygons_mutable() { return m_polygons; }
private:
std::vector<Polygons> m_polygons;
LayerIndex m_idx_begin;
LayerIndex m_idx_end;
};
/*!
@ -388,9 +391,9 @@ private:
}
void insert(LayerPolygonCache &&in, coord_t radius) {
std::lock_guard<std::mutex> guard(m_mutex);
LayerIndex i = in.idx_begin;
LayerIndex i = in.begin();
allocate_layers(i + LayerIndex(in.size()));
for (auto &d : in.polygons)
for (auto &d : in.polygons_mutable())
m_data[i ++].emplace(radius, std::move(d));
}
/*!

View file

@ -4649,6 +4649,7 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume
// ### Precalculate avoidances, collision etc.
size_t num_support_layers = precalculate(print, overhangs, processing.first, processing.second, volumes, throw_on_cancel);
bool has_support = num_support_layers > 0;
bool has_raft = config.raft_layers.size() > 0;
num_support_layers = std::max(num_support_layers, config.raft_layers.size());
SupportParameters support_params(print_object);
@ -4661,13 +4662,13 @@ static void generate_support_areas(Print &print, const BuildVolume &build_volume
SupportGeneratorLayersPtr interface_layers;
SupportGeneratorLayersPtr base_interface_layers;
SupportGeneratorLayersPtr intermediate_layers(num_support_layers, nullptr);
if (support_params.has_top_contacts)
if (support_params.has_top_contacts || has_raft)
top_contacts.assign(num_support_layers, nullptr);
if (support_params.has_bottom_contacts)
bottom_contacts.assign(num_support_layers, nullptr);
if (support_params.has_interfaces())
if (support_params.has_interfaces() || has_raft)
interface_layers.assign(num_support_layers, nullptr);
if (support_params.has_base_interfaces())
if (support_params.has_base_interfaces() || has_raft)
base_interface_layers.assign(num_support_layers, nullptr);
InterfacePlacer interface_placer{

View file

@ -159,7 +159,7 @@ BundleMap BundleMap::load()
idx_path = fs::path(cache_dir / (id + ".idx"));
}
if (!boost::filesystem::exists(idx_path)) {
BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to missing index %1%.", id, idx_path.string());
BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to missing index %2%.", id, idx_path.string());
continue;
}
Slic3r::GUI::Config::Index index;
@ -167,7 +167,7 @@ BundleMap BundleMap::load()
index.load(idx_path);
}
catch (const std::exception& /* err */) {
BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to invalid index %1%.", id, idx_path.string());
BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to invalid index %2%.", id, idx_path.string());
continue;
}
const auto recommended_it = index.recommended();

View file

@ -1192,6 +1192,13 @@ void ObjectList::key_event(wxKeyEvent& event)
void ObjectList::OnBeginDrag(wxDataViewEvent &event)
{
if (m_is_editing_started)
m_is_editing_started = false;
#ifdef __WXGTK__
const auto renderer = dynamic_cast<BitmapTextRenderer*>(GetColumn(colName)->GetRenderer());
renderer->FinishEditing();
#endif
const wxDataViewItem item(event.GetItem());
const bool mult_sel = multiple_selection();
@ -1225,18 +1232,11 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
m_objects_model->GetInstanceIdByItem(item),
type);
/* Under MSW or OSX, DnD moves an item to the place of another selected item
* But under GTK, DnD moves an item between another two items.
* And as a result - call EVT_CHANGE_SELECTION to unselect all items.
* To prevent such behavior use m_prevent_list_events
**/
m_prevent_list_events = true;//it's needed for GTK
/* Under GTK, DnD requires to the wxTextDataObject been initialized with some valid value,
* so set some nonempty string
*/
wxTextDataObject* obj = new wxTextDataObject;
obj->SetText("Some text");//it's needed for GTK
obj->SetText(mult_sel ? "SomeText" : m_objects_model->GetItemName(item));//it's needed for GTK
event.SetDataObject(obj);
event.SetDragFlags(wxDrag_DefaultMove); // allows both copy and move;
@ -1300,10 +1300,8 @@ void ObjectList::OnDropPossible(wxDataViewEvent &event)
{
const wxDataViewItem& item = event.GetItem();
if (!can_drop(item)) {
if (!can_drop(item))
event.Veto();
m_prevent_list_events = false;
}
}
void ObjectList::OnDrop(wxDataViewEvent &event)
@ -1317,6 +1315,13 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
return;
}
/* Under MSW or OSX, DnD moves an item to the place of another selected item
* But under GTK, DnD moves an item between another two items.
* And as a result - call EVT_CHANGE_SELECTION to unselect all items.
* To prevent such behavior use m_prevent_list_events
**/
m_prevent_list_events = true;//it's needed for GTK
if (m_dragged_data.type() == itInstance)
{
Plater::TakeSnapshot snapshot(wxGetApp().plater(),_(L("Instances to Separated Objects")));
@ -4841,6 +4846,9 @@ void ObjectList::OnEditingStarted(wxDataViewEvent &event)
void ObjectList::OnEditingDone(wxDataViewEvent &event)
{
if (!m_is_editing_started)
return;
m_is_editing_started = false;
if (event.GetColumn() != colName)
return;

View file

@ -17,6 +17,7 @@
#include <GL/glew.h>
#include <algorithm>
namespace Slic3r::GUI {
@ -521,6 +522,13 @@ void GLGizmoFdmSupports::auto_generate()
}
ModelObject *mo = m_c->selection_info()->model_object();
bool printable = std::any_of(mo->instances.begin(), mo->instances.end(), [](const ModelInstance *p) { return p->is_printable(); });
if (!printable) {
MessageDialog dlg(GUI::wxGetApp().plater(), _L("Automatic painting requires printable object."), _L("Warning"), wxOK);
dlg.ShowModal();
return;
}
bool not_painted = std::all_of(mo->volumes.begin(), mo->volumes.end(), [](const ModelVolume* vol){
return vol->type() != ModelVolumeType::MODEL_PART || vol->supported_facets.empty();
});

View file

@ -86,7 +86,7 @@ arrangement::ArrangePolygon get_arrange_poly(T obj, const Plater *plater)
using ArrangePolygon = arrangement::ArrangePolygon;
ArrangePolygon ap = obj.get_arrange_polygon();
ap.bed_idx = ap.translation.x() / bed_stride(plater);
ap.bed_idx = get_extents(ap.transformed_poly()).min.x() / bed_stride(plater);
ap.setter = [obj, plater](const ArrangePolygon &p) {
if (p.is_arranged()) {
Vec2d t = p.translation.cast<double>();

View file

@ -1042,6 +1042,16 @@ int ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer
return GetLayerIdByItem(item);
}
wxString ObjectDataViewModel::GetItemName(const wxDataViewItem& item) const
{
if (!item.IsOk())
return wxEmptyString;
ObjectDataViewModelNode* node = static_cast<ObjectDataViewModelNode*>(item.GetID());
if (!node)
return wxEmptyString;
return node->GetName();
}
int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
{
if(!item.IsOk())

View file

@ -311,6 +311,7 @@ public:
wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
wxString GetItemName(const wxDataViewItem& item) const;
int GetIdByItem(const wxDataViewItem& item) const;
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
int GetObjectIdByItem(const wxDataViewItem& item) const;

View file

@ -1411,27 +1411,25 @@ void Sidebar::update_sliced_info_sizer()
new_label = _L("Used Filament (g)");
info_text = wxString::Format("%.2f", ps.total_weight);
const auto& extruders_filaments = wxGetApp().preset_bundle->extruders_filaments;
const PresetCollection& filaments = wxGetApp().preset_bundle->filaments;
if (ps.filament_stats.size() > 1)
new_label += ":";
for (auto filament : ps.filament_stats) {
const Preset* filament_preset = filaments.find_preset(extruders_filaments[filament.first].get_selected_preset_name(), false);
if (filament_preset) {
const auto& extruders_filaments = wxGetApp().preset_bundle->extruders_filaments;
for (const auto& [filament_id, filament_vol] : ps.filament_stats) {
assert(filament_id < extruders_filaments.size());
if (const Preset* preset = extruders_filaments[filament_id].get_selected_preset()) {
double filament_weight;
if (ps.filament_stats.size() == 1)
filament_weight = ps.total_weight;
else {
double filament_density = filament_preset->config.opt_float("filament_density", 0);
filament_weight = filament.second * filament_density/* *2.4052f*/ * 0.001; // assumes 1.75mm filament diameter;
double filament_density = preset->config.opt_float("filament_density", 0);
filament_weight = filament_vol * filament_density/* *2.4052f*/ * 0.001; // assumes 1.75mm filament diameter;
new_label += "\n - " + format_wxstr(_L("Filament at extruder %1%"), filament.first + 1);
new_label += "\n - " + format_wxstr(_L("Filament at extruder %1%"), filament_id + 1);
info_text += wxString::Format("\n%.2f", filament_weight);
}
double spool_weight = filament_preset->config.opt_float("filament_spool_weight", 0);
double spool_weight = preset->config.opt_float("filament_spool_weight", 0);
if (spool_weight != 0.0) {
new_label += "\n " + _L("(including spool)");
info_text += wxString::Format(" (%.2f)\n", filament_weight + spool_weight);