Merge branch 'master' into lm_low_wipe_tower

This commit is contained in:
Lukas Matena 2019-10-01 13:24:25 +02:00
commit 61cee54dd3
92 changed files with 1767 additions and 1029 deletions

View file

@ -342,7 +342,7 @@ static void copy_config_dir_single_level(const boost::filesystem::path &path_src
! boost::filesystem::create_directory(path_dst))
throw std::runtime_error(std::string("Slic3r was unable to create a directory at ") + path_dst.string());
for (auto &dir_entry : boost::filesystem::directory_iterator(path_src))
for (auto &dir_entry : boost::filesystem::directory_iterator(path_src))
if (Slic3r::is_ini_file(dir_entry))
boost::filesystem::copy_file(dir_entry.path(), path_dst / dir_entry.path().filename(), boost::filesystem::copy_option::overwrite_if_exists);
}
@ -351,7 +351,7 @@ static void delete_existing_ini_files(const boost::filesystem::path &path)
{
if (! boost::filesystem::is_directory(path))
return;
for (auto &dir_entry : boost::filesystem::directory_iterator(path))
for (auto &dir_entry : boost::filesystem::directory_iterator(path))
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini"))
boost::filesystem::remove(dir_entry.path());
}
@ -378,7 +378,7 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot:
sprintf(name, "filament_%u", i);
if (! app_config.has("presets", name))
break;
snapshot.filaments.emplace_back(app_config.get("presets", name));
snapshot.filaments.emplace_back(app_config.get("presets", name));
}
// Vendor specific config bundles and installed printers.
for (const std::pair<std::string, std::map<std::string, std::set<std::string>>> &vendor : app_config.vendors()) {
@ -417,7 +417,7 @@ const Snapshot& SnapshotDB::take_snapshot(const AppConfig &app_config, Snapshot:
// Backup the presets.
for (const char *subdir : { "print", "filament", "printer", "vendor" })
copy_config_dir_single_level(data_dir / subdir, snapshot_dir / subdir);
snapshot.save_ini((snapshot_dir / "snapshot.ini").string());
snapshot.save_ini((snapshot_dir / "snapshot.ini").string());
assert(m_snapshots.empty() || m_snapshots.back().time_captured <= snapshot.time_captured);
m_snapshots.emplace_back(std::move(snapshot));
return m_snapshots.back();

View file

@ -227,9 +227,9 @@ size_t Index::load(const boost::filesystem::path &path)
// End of semver or keyword.
break;
}
if (*key_end != 0 && *key_end != ' ' && *key_end != '\t' && *key_end != '=')
if (*key_end != 0 && *key_end != ' ' && *key_end != '\t' && *key_end != '=')
throw file_parser_error("Invalid keyword or semantic version", path, idx_line);
char *value = left_trim(key_end);
char *value = left_trim(key_end);
bool key_value_pair = *value == '=';
if (key_value_pair)
value = left_trim(value + 1);
@ -245,11 +245,11 @@ size_t Index::load(const boost::filesystem::path &path)
if (strcmp(key, "min_slic3r_version") == 0 || strcmp(key, "max_slic3r_version") == 0) {
if (! svalue.empty())
semver = Semver::parse(svalue);
if (! semver)
if (! semver)
throw file_parser_error(std::string(key) + " must referece a valid semantic version", path, idx_line);
if (strcmp(key, "min_slic3r_version") == 0)
if (strcmp(key, "min_slic3r_version") == 0)
ver.min_slic3r_version = *semver;
else
else
ver.max_slic3r_version = *semver;
} else {
// Ignore unknown keys, as there may come new keys in the future.

View file

@ -1717,13 +1717,18 @@ static void thick_point_to_verts(const Vec3crd& point,
point_to_indexed_vertex_array(point, width, height, volume.indexed_vertex_array);
}
void _3DScene::extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume)
{
if (polyline.size() >= 2) {
size_t num_segments = polyline.size() - 1;
thick_lines_to_verts(polyline.lines(), std::vector<double>(num_segments, width), std::vector<double>(num_segments, height), false, print_z, volume);
}
}
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.
void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, GLVolume &volume)
{
Lines lines = extrusion_path.polyline.lines();
std::vector<double> widths(lines.size(), extrusion_path.width);
std::vector<double> heights(lines.size(), extrusion_path.height);
thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume);
}
// Fill in the qverts and tverts with quads and triangles for the extrusion_path.

View file

@ -656,6 +656,7 @@ public:
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume);

View file

@ -455,7 +455,7 @@ void BedShapePanel::update_shape()
else if (page_idx == SHAPE_CUSTOM)
m_shape = m_loaded_shape;
update_preview();
update_preview();
}
// Loads an stl file, projects it to the XY plane and calculates a polygon.

View file

@ -1225,13 +1225,16 @@ bool ConfigWizard::run(PresetBundle *preset_bundle, const PresetUpdater *updater
const wxString& ConfigWizard::name(const bool from_menu/* = false*/)
{
// A different naming convention is used for the Wizard on Windows vs. OSX & GTK.
// A different naming convention is used for the Wizard on Windows & GTK vs. OSX.
// Note: Don't call _() macro here.
// This function just return the current name according to the OS.
// Translation is implemented inside GUI_App::add_config_menu()
#if __APPLE__
static const wxString config_wizard_name = _(L("Configuration Assistant"));
static const wxString config_wizard_name_menu = _(L("Configuration &Assistant"));
static const wxString config_wizard_name = L("Configuration Assistant");
static const wxString config_wizard_name_menu = L("Configuration &Assistant");
#else
static const wxString config_wizard_name = _(L("Configuration Wizard"));
static const wxString config_wizard_name_menu = _(L("Configuration &Wizard"));
static const wxString config_wizard_name = L("Configuration Wizard");
static const wxString config_wizard_name_menu = L("Configuration &Wizard");
#endif
return from_menu ? config_wizard_name_menu : config_wizard_name;
}

View file

@ -928,8 +928,8 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
if (items_count > 1)
m_original_height += (items_count - 1) * scaled_square_contour;
m_width = (int)next_highest_power_of_2((uint32_t)m_original_width);
m_height = (int)next_highest_power_of_2((uint32_t)m_original_height);
m_width = (int)next_highest_power_of_2((uint32_t)m_original_width);
m_height = (int)next_highest_power_of_2((uint32_t)m_original_height);
// generates bitmap
wxBitmap bitmap(m_width, m_height);
@ -1882,7 +1882,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
if (m_reload_delayed)
return;
bool update_object_list = false;
bool update_object_list = false;
if (m_volumes.volumes != glvolumes_new)
update_object_list = true;
@ -3012,23 +3012,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
wxGetApp().obj_manipul()->set_dirty();
// forces a frame render to update the view before the context menu is shown
render();
/* #et_FIXME
Vec2d logical_pos = pos.cast<double>();
#if ENABLE_RETINA_GL
const float factor = m_retina_helper->get_scale_factor();
logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
#endif // ENABLE_RETINA_GL
post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, logical_pos));
*/
}
}
// #et_FIXME
Vec2d logical_pos = pos.cast<double>();
#if ENABLE_RETINA_GL
const float factor = m_retina_helper->get_scale_factor();
logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor));
#endif // ENABLE_RETINA_GL
post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, {logical_pos, m_hover_volume_idxs.empty()}));
if (!m_mouse.dragging)
// do not post the event if the user is panning the scene
post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, { logical_pos, m_hover_volume_idxs.empty() }));
}
mouse_up_cleanup();
@ -3396,10 +3389,9 @@ void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool foc
m_sidebar_field = focus_on ? opt_key : "";
if (!m_sidebar_field.empty())
{
m_gizmos.reset_all_states();
m_dirty = true;
}
m_dirty = true;
}
void GLCanvas3D::handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type)
@ -4995,19 +4987,21 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
// helper functions to select data in dependence of the extrusion view type
struct Helper
{
static float path_filter(GCodePreviewData::Extrusion::EViewType type, const ExtrusionPath& path)
static float path_filter(GCodePreviewData::Extrusion::EViewType type, const GCodePreviewData::Extrusion::Path& path)
{
switch (type)
{
case GCodePreviewData::Extrusion::FeatureType:
// The role here is used for coloring.
return (float)path.role();
return (float)path.extrusion_role;
case GCodePreviewData::Extrusion::Height:
return path.height;
case GCodePreviewData::Extrusion::Width:
return path.width;
case GCodePreviewData::Extrusion::Feedrate:
return path.feedrate;
case GCodePreviewData::Extrusion::FanSpeed:
return path.fan_speed;
case GCodePreviewData::Extrusion::VolumetricRate:
return path.feedrate * (float)path.mm3_per_mm;
case GCodePreviewData::Extrusion::Tool:
@ -5033,6 +5027,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
return data.get_width_color(value);
case GCodePreviewData::Extrusion::Feedrate:
return data.get_feedrate_color(value);
case GCodePreviewData::Extrusion::FanSpeed:
return data.get_fan_speed_color(value);
case GCodePreviewData::Extrusion::VolumetricRate:
return data.get_volumetric_rate_color(value);
case GCodePreviewData::Extrusion::Tool:
@ -5075,16 +5071,16 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
{
std::vector<size_t> num_paths_per_role(size_t(erCount), 0);
for (const GCodePreviewData::Extrusion::Layer &layer : preview_data.extrusion.layers)
for (const ExtrusionPath &path : layer.paths)
++ num_paths_per_role[size_t(path.role())];
std::vector<std::vector<float>> roles_values;
for (const GCodePreviewData::Extrusion::Path &path : layer.paths)
++ num_paths_per_role[size_t(path.extrusion_role)];
std::vector<std::vector<float>> roles_values;
roles_values.assign(size_t(erCount), std::vector<float>());
for (size_t i = 0; i < roles_values.size(); ++ i)
roles_values[i].reserve(num_paths_per_role[i]);
for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
for (const ExtrusionPath& path : layer.paths)
roles_values[size_t(path.role())].emplace_back(Helper::path_filter(preview_data.extrusion.view_type, path));
roles_filters.reserve(size_t(erCount));
for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
for (const GCodePreviewData::Extrusion::Path &path : layer.paths)
roles_values[size_t(path.extrusion_role)].emplace_back(Helper::path_filter(preview_data.extrusion.view_type, path));
roles_filters.reserve(size_t(erCount));
size_t num_buffers = 0;
for (std::vector<float> &values : roles_values) {
sort_remove_duplicates(values);
@ -5111,9 +5107,9 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
// populates volumes
for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
{
for (const ExtrusionPath& path : layer.paths)
for (const GCodePreviewData::Extrusion::Path& path : layer.paths)
{
std::vector<std::pair<float, GLVolume*>> &filters = roles_filters[size_t(path.role())];
std::vector<std::pair<float, GLVolume*>> &filters = roles_filters[size_t(path.extrusion_role)];
auto key = std::make_pair<float, GLVolume*>(Helper::path_filter(preview_data.extrusion.view_type, path), nullptr);
auto it_filter = std::lower_bound(filters.begin(), filters.end(), key);
assert(it_filter != filters.end() && key.first == it_filter->first);
@ -5123,7 +5119,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
vol.offsets.push_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.push_back(vol.indexed_vertex_array.triangle_indices.size());
_3DScene::extrusionentity_to_verts(path, layer.z, vol);
_3DScene::extrusionentity_to_verts(path.polyline, path.width, path.height, layer.z, vol);
}
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
for (std::vector<std::pair<float, GLVolume*>> &filters : roles_filters) {

View file

@ -71,7 +71,6 @@ public:
wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
using Vec2dEvent = Event<Vec2d>;
// #et_FIXME : RBtnEvent is used instead of Vec2dEvent on EVT_GLCANVAS_RIGHT_CLICK
// _bool_ value is used as a indicator of selection in the 3DScene
using RBtnEvent = Event<std::pair<Vec2d, bool>>;
template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>;

View file

@ -125,7 +125,7 @@ void config_wizard(int reason)
if (! wxGetApp().check_unsaved_changes())
return;
try {
try {
ConfigWizard wizard(nullptr, static_cast<ConfigWizard::RunReason>(reason));
wizard.run(wxGetApp().preset_bundle, wxGetApp().preset_updater);
}

View file

@ -725,7 +725,7 @@ bool GUI_App::load_language(wxString language, bool initial)
#endif
if (initial)
message + "\n\nApplication will close.";
wxMessageBox(message, "PrusaSlicer - Switching language failed", wxOK | wxICON_ERROR);
wxMessageBox(message, "PrusaSlicer - Switching language failed", wxOK | wxICON_ERROR);
if (initial)
std::exit(EXIT_FAILURE);
else

View file

@ -131,7 +131,7 @@ ObjectList::ObjectList(wxWindow* parent) :
{
wxDataViewItemArray sels;
GetSelections(sels);
if (sels.front() == m_last_selected_item)
if (! sels.empty() && sels.front() == m_last_selected_item)
m_last_selected_item = sels.back();
else
m_last_selected_item = event.GetItem();
@ -255,21 +255,32 @@ void ObjectList::create_objects_ctrl()
EnableDropTarget(wxDF_UNICODETEXT);
#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
const int em = wxGetApp().em_unit();
// column ItemName(Icon+Text) of the view control:
// And Icon can be consisting of several bitmaps
AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(),
colName, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
colName, 20*em, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
// column PrintableProperty (Icon) of the view control:
AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, int(2 * wxGetApp().em_unit()),
AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, 3*em,
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
// column Extruder of the view control:
AppendColumn(create_objects_list_extruder_column(4));
// column ItemEditing of the view control:
AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/,
AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, 3*em,
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
// For some reason under OSX on 4K(5K) monitors in wxDataViewColumn constructor doesn't set width of column.
// Therefore, force set column width.
if (wxOSX)
{
GetColumn(colName)->SetWidth(20*em);
GetColumn(colPrint)->SetWidth(3*em);
GetColumn(colExtruder)->SetWidth(8*em);
}
}
void ObjectList::create_popup_menus()
@ -742,9 +753,9 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol
}
select_items(items);
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed();
#endif //no __WXOSX__ //__WXMSW__
//#endif //no __WXOSX__ //__WXMSW__
}
void ObjectList::paste_objects_into_list(const std::vector<size_t>& object_idxs)
@ -762,9 +773,9 @@ void ObjectList::paste_objects_into_list(const std::vector<size_t>& object_idxs)
wxGetApp().plater()->changed_objects(object_idxs);
select_items(items);
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed();
#endif //no __WXOSX__ //__WXMSW__
//#endif //no __WXOSX__ //__WXMSW__
}
#ifdef __WXOSX__
@ -801,8 +812,15 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/)
*/
if (!item) {
if (wxOSX && col == nullptr)
UnselectAll();
if (col == nullptr) {
if (wxOSX)
UnselectAll();
else if (!evt_context_menu)
// Case, when last item was deleted and under GTK was called wxEVT_DATAVIEW_SELECTION_CHANGED,
// which invoked next list_manipulation(false)
return;
}
if (evt_context_menu) {
show_context_menu(evt_context_menu);
return;
@ -822,12 +840,18 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/)
show_context_menu(evt_context_menu);
else if (title == _("Name"))
{
int obj_idx, vol_idx;
get_selected_item_indexes(obj_idx, vol_idx, item);
if (wxOSX)
show_context_menu(evt_context_menu); // return context menu under OSX (related to #2909)
if (is_windows10() && get_mesh_errors_count(obj_idx, vol_idx) > 0 &&
pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() )
fix_through_netfabb();
if (is_windows10())
{
int obj_idx, vol_idx;
get_selected_item_indexes(obj_idx, vol_idx, item);
if (get_mesh_errors_count(obj_idx, vol_idx) > 0 &&
pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() )
fix_through_netfabb();
}
}
#ifndef __WXMSW__
@ -1315,7 +1339,7 @@ wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeTy
for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") })
{
if (type == ModelVolumeType::INVALID && item == "Slab")
if (type == ModelVolumeType::INVALID && strncmp(item, "Slab", 4) == 0)
continue;
append_menu_item(sub_menu, wxID_ANY, _(item), "",
[this, type, item](wxCommandEvent&) { load_generic_subobject(item, type); }, "", menu);
@ -1698,9 +1722,9 @@ void ObjectList::load_subobject(ModelVolumeType type)
if (sel_item)
select_item(sel_item);
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed();
#endif //no __WXOSX__ //__WXMSW__
//#endif //no __WXOSX__ //__WXMSW__
}
void ObjectList::load_part( ModelObject* model_object,
@ -1836,9 +1860,9 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
const auto object_item = m_objects_model->GetTopParent(GetSelection());
select_item(m_objects_model->AddVolumeChild(object_item, name, type,
new_volume->get_mesh_errors_count()>0));
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
selection_changed();
#endif //no __WXOSX__ //__WXMSW__
//#endif //no __WXOSX__ //__WXMSW__
}
void ObjectList::load_shape_object(const std::string& type_name)
@ -1877,6 +1901,9 @@ void ObjectList::load_shape_object(const std::string& type_name)
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
new_object->invalidate_bounding_box();
new_object->center_around_origin();
new_object->ensure_on_bed();
const BoundingBoxf bed_shape = wxGetApp().plater()->bed_shape_bb();
new_object->instances[0]->set_offset(Slic3r::to_3d(bed_shape.center().cast<double>(), -new_object->origin_translation(2)));
@ -3662,10 +3689,10 @@ void ObjectList::msw_rescale()
// update min size !!! A width of control shouldn't be a wxDefaultCoord
SetMinSize(wxSize(1, 15 * em));
GetColumn(colName)->SetWidth(19 * em);
GetColumn(colPrint)->SetWidth( 2 * em);
GetColumn(colName )->SetWidth(20 * em);
GetColumn(colPrint )->SetWidth( 3 * em);
GetColumn(colExtruder)->SetWidth( 8 * em);
GetColumn(colEditing)->SetWidth( 2 * em);
GetColumn(colEditing )->SetWidth( 3 * em);
// rescale all icons, used by ObjectList
msw_rescale_icons();

View file

@ -221,6 +221,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
m_choice_view_type->Append(_(L("Height")));
m_choice_view_type->Append(_(L("Width")));
m_choice_view_type->Append(_(L("Speed")));
m_choice_view_type->Append(_(L("Fan speed")));
m_choice_view_type->Append(_(L("Volumetric flow rate")));
m_choice_view_type->Append(_(L("Tool")));
m_choice_view_type->Append(_(L("Color Print")));

View file

@ -252,7 +252,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
const sla::SupportPoint& support_point = m_editing_mode ? m_editing_cache[i].support_point : m_normal_cache[i];
const bool& point_selected = m_editing_mode ? m_editing_cache[i].selected : false;
if (is_point_clipped(support_point.pos.cast<double>()))
if (is_mesh_point_clipped(support_point.pos.cast<double>()))
continue;
// First decide about the color of the point.
@ -335,14 +335,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const
bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const
{
if (m_clipping_plane_distance == 0.f)
return false;
Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point;
transformed_point(2) += m_z_shift;
return m_clipping_plane->distance(transformed_point) < 0.;
return m_clipping_plane->is_point_clipped(transformed_point);
}
@ -391,27 +391,15 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift));
// The raycaster query
std::vector<Vec3f> hits;
std::vector<Vec3f> normals;
m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, &hits, &normals);
// We must also take care of the clipping plane (if active)
unsigned i = 0;
if (m_clipping_plane_distance != 0.f) {
for (i=0; i<hits.size(); ++i)
if (! is_point_clipped(hits[i].cast<double>()))
break;
Vec3f hit;
Vec3f normal;
if (m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, hit, normal, m_clipping_plane.get())) {
// Return both the point and the facet normal.
pos_and_normal = std::make_pair(hit, normal);
return true;
}
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
// All hits are either clipped, or there is an odd number of unclipped
// hits - meaning the nearest must be from inside the mesh.
else
return false;
}
// Calculate and return both the point and the facet normal.
pos_and_normal = std::make_pair(hits[i], normals[i]);
return true;
}
// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event.
@ -481,19 +469,15 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
std::vector<Vec3f> points_inside;
std::vector<unsigned int> points_idxs = m_selection_rectangle.stop_dragging(m_parent, points);
for (size_t idx : points_idxs)
points_inside.push_back((trafo.get_matrix() * points[idx]).cast<float>());
points_inside.push_back(points[idx].cast<float>());
// Only select/deselect points that are actually visible
for (size_t idx : m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside,
[this](const Vec3f& pt) { return is_point_clipped(pt.cast<double>()); }))
for (size_t idx : m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get()))
{
const sla::SupportPoint &support_point = m_editing_cache[points_idxs[idx]].support_point;
if (! is_point_clipped(support_point.pos.cast<double>())) {
if (rectangle_status == GLSelectionRectangle::Deselect)
unselect_point(points_idxs[idx]);
else
select_point(points_idxs[idx]);
}
if (rectangle_status == GLSelectionRectangle::Deselect)
unselect_point(points_idxs[idx]);
else
select_point(points_idxs[idx]);
}
return true;
}

View file

@ -125,7 +125,7 @@ private:
mutable std::unique_ptr<MeshClipper> m_supports_clipper;
std::vector<const ConfigOption*> get_config_options(const std::vector<std::string>& keys) const;
bool is_point_clipped(const Vec3d& point) const;
bool is_mesh_point_clipped(const Vec3d& point) const;
//void find_intersecting_facets(const igl::AABB<Eigen::MatrixXf, 3>* aabb, const Vec3f& normal, double offset, std::vector<unsigned int>& out) const;
// Methods that do the model_object and editing cache synchronization,

View file

@ -192,7 +192,7 @@ ConfigOptionsGroupShp LambdaObjectDialog::init_modificator_options_page(const wx
else
panel->SetSizer(optgroup->sizer);
return optgroup;
return optgroup;
}

View file

@ -917,7 +917,7 @@ void MainFrame::load_config_file()
wxString file;
if (dlg.ShowModal() == wxID_OK)
file = dlg.GetPath();
if (! file.IsEmpty() && this->load_config_file(file.ToUTF8().data())) {
if (! file.IsEmpty() && this->load_config_file(file.ToUTF8().data())) {
wxGetApp().app_config->update_config_dir(get_dir_name(file));
m_last_config = file;
}

View file

@ -152,8 +152,8 @@ Vec3f MeshRaycaster::AABBWrapper::get_hit_normal(const igl::Hit& hit) const
}
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo,
const Camera& camera, std::vector<Vec3f>* positions, std::vector<Vec3f>* normals) const
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane) const
{
const std::array<int, 4>& viewport = camera.get_viewport();
const Transform3d& model_mat = camera.get_view_matrix();
@ -179,25 +179,30 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
// Now stuff the points in the provided vector and calculate normals if asked about them:
if (positions != nullptr) {
positions->clear();
if (normals != nullptr)
normals->clear();
for (const igl::Hit& hit : hits) {
positions->push_back(m_AABB_wrapper->get_hit_pos(hit));
unsigned i = 0;
if (normals != nullptr)
normals->push_back(m_AABB_wrapper->get_hit_normal(hit));
// Remove points that are obscured or cut by the clipping plane
if (clipping_plane) {
for (i=0; i<hits.size(); ++i)
if (! clipping_plane->is_point_clipped(trafo * m_AABB_wrapper->get_hit_pos(hits[i]).cast<double>()))
break;
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
// All hits are either clipped, or there is an odd number of unclipped
// hits - meaning the nearest must be from inside the mesh.
return false;
}
}
// Now stuff the points in the provided vector and calculate normals if asked about them:
position = m_AABB_wrapper->get_hit_pos(hits[i]);
normal = m_AABB_wrapper->get_hit_normal(hits[i]);
return true;
}
std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points,
std::function<bool(const Vec3f&)> fn_ignore_hit) const
const ClippingPlane* clipping_plane) const
{
std::vector<unsigned> out;
@ -206,19 +211,24 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast<float>() * direction_to_camera).normalized().eval();
Vec3f scaling = trafo.get_scaling_factor().cast<float>();
direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2));
const Transform3f inverse_trafo = trafo.get_matrix().inverse().cast<float>();
for (size_t i=0; i<points.size(); ++i) {
const Vec3f& pt = points[i];
if (clipping_plane && clipping_plane->is_point_clipped(pt.cast<double>()))
continue;
bool is_obscured = false;
// Cast a ray in the direction of the camera and look for intersection with the mesh:
std::vector<igl::Hit> hits;
// Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies.
// Offset the start of the ray by EPSILON to account for numerical inaccuracies.
if (m_AABB_wrapper->m_AABB.intersect_ray(
AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3),
pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) {
inverse_trafo * pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) {
std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; });
// If the closest hit facet normal points in the same direction as the ray,
// we are looking through the mesh and should therefore discard the point:
if (m_AABB_wrapper->get_hit_normal(hits.front()).dot(direction_to_camera_mesh) > 0.f)
@ -227,11 +237,12 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
// Eradicate all hits that the caller wants to ignore
for (unsigned j=0; j<hits.size(); ++j) {
const igl::Hit& hit = hits[j];
if (fn_ignore_hit(m_AABB_wrapper->get_hit_pos(hit))) {
if (clipping_plane && clipping_plane->is_point_clipped(trafo.get_matrix() * m_AABB_wrapper->get_hit_pos(hit).cast<double>())) {
hits.erase(hits.begin()+j);
--j;
}
}
// FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
// Also, the threshold is in mesh coordinates, not in actual dimensions.
if (! hits.empty())

View file

@ -50,6 +50,7 @@ public:
return (-get_normal().dot(pt) + m_data[3]);
}
bool is_point_clipped(const Vec3d& point) const { return distance(point) < 0.; }
void set_normal(const Vec3d& normal) { for (size_t i=0; i<3; ++i) m_data[i] = normal(i); }
void set_offset(double offset) { m_data[3] = offset; }
Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); }
@ -98,10 +99,10 @@ public:
void set_camera(const Camera& camera);
bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const;
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane = nullptr) const;
std::vector<unsigned> get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera,
const std::vector<Vec3f>& points, std::function<bool(const Vec3f&)> fn_ignore_hit) const;
const std::vector<Vec3f>& points, const ClippingPlane* clipping_plane = nullptr) const;
Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const;

View file

@ -133,7 +133,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
m_options_mode.push_back(option_set[0].opt.mode);
// if we have a single option with no label, no sidetext just add it directly to sizer
if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width &&
if (option_set.size() == 1 && label_width == 0 && option_set.front().opt.full_width &&
option_set.front().opt.label.empty() &&
option_set.front().opt.sidetext.size() == 0 && option_set.front().side_widget == nullptr &&
line.get_extra_widgets().size() == 0) {

View file

@ -3322,7 +3322,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
this->statusbar()->set_progress(evt.status.percent);
this->statusbar()->set_status_text(_(evt.status.text) + wxString::FromUTF8(""));
}
if (evt.status.flags & (PrintBase::SlicingStatus::RELOAD_SCENE || PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS)) {
if (evt.status.flags & (PrintBase::SlicingStatus::RELOAD_SCENE | PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS)) {
switch (this->printer_technology) {
case ptFFF:
this->update_fff_scene();
@ -4288,11 +4288,10 @@ void Plater::increase_instances(size_t num)
sidebar().obj_list()->increase_object_instances(obj_idx, was_one_instance ? num + 1 : num);
if (p->get_config("autocenter") == "1") {
if (p->get_config("autocenter") == "1")
p->arrange();
} else {
p->update();
}
p->update();
p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1);
@ -4336,14 +4335,14 @@ void Plater::set_number_of_copies(/*size_t num*/)
ModelObject* model_object = p->model.objects[obj_idx];
const auto num = wxGetNumberFromUser( " ", _("Enter the number of copies:"),
const int num = wxGetNumberFromUser( " ", _("Enter the number of copies:"),
_("Copies of the selected object"), model_object->instances.size(), 0, 1000, this );
if (num < 0)
return;
Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num));
int diff = (int)num - (int)model_object->instances.size();
int diff = num - (int)model_object->instances.size();
if (diff > 0)
increase_instances(diff);
else if (diff < 0)
@ -4843,6 +4842,34 @@ void Plater::on_config_change(const DynamicPrintConfig &config)
this->p->schedule_background_process();
}
void Plater::force_filament_colors_update()
{
bool update_scheduled = false;
DynamicPrintConfig* config = p->config;
const std::vector<std::string> filament_presets = wxGetApp().preset_bundle->filament_presets;
if (filament_presets.size() > 1 &&
p->config->option<ConfigOptionStrings>("filament_colour")->values.size() == filament_presets.size())
{
const PresetCollection& filaments = wxGetApp().preset_bundle->filaments;
std::vector<std::string> filament_colors;
filament_colors.reserve(filament_presets.size());
for (const std::string& filament_preset : filament_presets)
filament_colors.push_back(filaments.find_preset(filament_preset, true)->config.opt_string("filament_colour", (unsigned)0));
if (config->option<ConfigOptionStrings>("filament_colour")->values != filament_colors) {
config->option<ConfigOptionStrings>("filament_colour")->values = filament_colors;
update_scheduled = true;
}
}
if (update_scheduled)
update();
if (p->main_frame->is_loaded())
this->p->schedule_background_process();
}
void Plater::on_activate()
{
#ifdef __linux__

View file

@ -211,6 +211,7 @@ public:
void on_extruders_change(size_t extruders_count);
void on_config_change(const DynamicPrintConfig &config);
void force_filament_colors_update();
// On activating the parent window.
void on_activate();
const DynamicPrintConfig* get_plater_config() const;

View file

@ -279,7 +279,7 @@ std::string PresetBundle::load_system_presets()
errors_cummulative += "\n";
}
}
if (first) {
if (first) {
// No config bundle loaded, reset.
this->reset(false);
}

View file

@ -410,7 +410,7 @@ void Selection::set_deserialized(EMode mode, const std::vector<std::pair<size_t,
if (! m_valid)
return;
m_mode = mode;
m_mode = mode;
for (unsigned int i : m_list)
(*m_volumes)[i]->selected = false;
m_list.clear();

View file

@ -3033,6 +3033,12 @@ void Tab::save_preset(std::string name /*= ""*/)
if (m_type == Preset::TYPE_PRINTER)
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count;
update_changed_ui();
/* If filament preset is saved for multi-material printer preset,
* there are cases when filament comboboxs are updated for old (non-modified) colors,
* but in full_config a filament_colors option aren't.*/
if (m_type == Preset::TYPE_FILAMENT && wxGetApp().extruders_edited_cnt() > 1)
wxGetApp().plater()->force_filament_colors_update();
}
// Called for a currently selected preset.

View file

@ -371,7 +371,7 @@ void WipingPanel::toggle_advanced(bool user_action) {
else
m_advanced = !advanced_matches_simple(); // if called from constructor, show what is appropriate
(m_advanced ? m_page_advanced : m_page_simple)->Show();
(m_advanced ? m_page_advanced : m_page_simple)->Show();
(!m_advanced ? m_page_advanced : m_page_simple)->Hide();
m_widget_button->SetLabel(m_advanced ? _(L("Show simplified settings")) : _(L("Show advanced settings")));

View file

@ -669,7 +669,7 @@ wxDataViewItem ObjectDataViewModel::Add(const wxString &name,
if (has_errors)
root->m_bmp = *m_warning_bmp;
m_objects.push_back(root);
m_objects.push_back(root);
// notify control
wxDataViewItem child((void*)root);
wxDataViewItem parent((void*)NULL);
@ -720,7 +720,7 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
root->SetBitmap(*m_warning_bmp);
// notify control
const wxDataViewItem child((void*)node);
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
root->m_volumes_cnt++;