mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-19 17:18:09 +08:00
Merge remote-tracking branch 'origin/master' into ys_manipulation_panel_rw
This commit is contained in:
commit
efb9ef37f6
@ -89,33 +89,34 @@ struct stl_neighbors {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct stl_stats {
|
struct stl_stats {
|
||||||
stl_stats() { this->reset(); }
|
stl_stats() { memset(&header, 0, 81); }
|
||||||
void reset() { memset(this, 0, sizeof(stl_stats)); this->volume = -1.0; }
|
char header[81] = "";
|
||||||
char header[81];
|
stl_type type = (stl_type)0;
|
||||||
stl_type type;
|
uint32_t number_of_facets = 0;
|
||||||
uint32_t number_of_facets;
|
stl_vertex max = stl_vertex::Zero();
|
||||||
stl_vertex max;
|
stl_vertex min = stl_vertex::Zero();
|
||||||
stl_vertex min;
|
stl_vertex size = stl_vertex::Zero();
|
||||||
stl_vertex size;
|
float bounding_diameter = 0.f;
|
||||||
float bounding_diameter;
|
float shortest_edge = 0.f;
|
||||||
float shortest_edge;
|
float volume = -1.f;
|
||||||
float volume;
|
int connected_edges = 0;
|
||||||
int connected_edges;
|
int connected_facets_1_edge = 0;
|
||||||
int connected_facets_1_edge;
|
int connected_facets_2_edge = 0;
|
||||||
int connected_facets_2_edge;
|
int connected_facets_3_edge = 0;
|
||||||
int connected_facets_3_edge;
|
int facets_w_1_bad_edge = 0;
|
||||||
int facets_w_1_bad_edge;
|
int facets_w_2_bad_edge = 0;
|
||||||
int facets_w_2_bad_edge;
|
int facets_w_3_bad_edge = 0;
|
||||||
int facets_w_3_bad_edge;
|
int original_num_facets = 0;
|
||||||
int original_num_facets;
|
int edges_fixed = 0;
|
||||||
int edges_fixed;
|
int degenerate_facets = 0;
|
||||||
int degenerate_facets;
|
int facets_removed = 0;
|
||||||
int facets_removed;
|
int facets_added = 0;
|
||||||
int facets_added;
|
int facets_reversed = 0;
|
||||||
int facets_reversed;
|
int backwards_edges = 0;
|
||||||
int backwards_edges;
|
int normals_fixed = 0;
|
||||||
int normals_fixed;
|
int number_of_parts = 0;
|
||||||
int number_of_parts;
|
|
||||||
|
void clear() { *this = stl_stats(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct stl_file {
|
struct stl_file {
|
||||||
@ -124,7 +125,7 @@ struct stl_file {
|
|||||||
void clear() {
|
void clear() {
|
||||||
this->facet_start.clear();
|
this->facet_start.clear();
|
||||||
this->neighbors_start.clear();
|
this->neighbors_start.clear();
|
||||||
this->stats.reset();
|
this->stats.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t memsize() const {
|
size_t memsize() const {
|
||||||
|
@ -36,6 +36,10 @@
|
|||||||
#error "SEEK_SET not defined"
|
#error "SEEK_SET not defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef BOOST_LITTLE_ENDIAN
|
||||||
|
extern void stl_internal_reverse_quads(char *buf, size_t cnt);
|
||||||
|
#endif /* BOOST_LITTLE_ENDIAN */
|
||||||
|
|
||||||
static FILE* stl_open_count_facets(stl_file *stl, const char *file)
|
static FILE* stl_open_count_facets(stl_file *stl, const char *file)
|
||||||
{
|
{
|
||||||
// Open the file in binary mode first.
|
// Open the file in binary mode first.
|
||||||
@ -238,10 +242,6 @@ bool stl_open(stl_file *stl, const char *file)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef BOOST_LITTLE_ENDIAN
|
|
||||||
extern void stl_internal_reverse_quads(char *buf, size_t cnt);
|
|
||||||
#endif /* BOOST_LITTLE_ENDIAN */
|
|
||||||
|
|
||||||
void stl_allocate(stl_file *stl)
|
void stl_allocate(stl_file *stl)
|
||||||
{
|
{
|
||||||
// Allocate memory for the entire .STL file.
|
// Allocate memory for the entire .STL file.
|
||||||
|
@ -15,4 +15,4 @@
|
|||||||
#undef clipper_hpp
|
#undef clipper_hpp
|
||||||
#undef use_xyz
|
#undef use_xyz
|
||||||
|
|
||||||
#endif clipper_z_hpp
|
#endif // clipper_z_hpp
|
||||||
|
@ -15,40 +15,39 @@ namespace Slic3r {
|
|||||||
|
|
||||||
struct SurfaceFillParams
|
struct SurfaceFillParams
|
||||||
{
|
{
|
||||||
SurfaceFillParams() : flow(0.f, 0.f, 0.f, false) { memset(this, 0, sizeof(*this)); }
|
|
||||||
// Zero based extruder ID.
|
// Zero based extruder ID.
|
||||||
unsigned int extruder;
|
unsigned int extruder = 0;
|
||||||
// Infill pattern, adjusted for the density etc.
|
// Infill pattern, adjusted for the density etc.
|
||||||
InfillPattern pattern;
|
InfillPattern pattern = InfillPattern(0);
|
||||||
|
|
||||||
// FillBase
|
// FillBase
|
||||||
// in unscaled coordinates
|
// in unscaled coordinates
|
||||||
coordf_t spacing;
|
coordf_t spacing = 0.;
|
||||||
// infill / perimeter overlap, in unscaled coordinates
|
// infill / perimeter overlap, in unscaled coordinates
|
||||||
coordf_t overlap;
|
coordf_t overlap = 0.;
|
||||||
// Angle as provided by the region config, in radians.
|
// Angle as provided by the region config, in radians.
|
||||||
float angle;
|
float angle = 0.f;
|
||||||
// Non-negative for a bridge.
|
// Non-negative for a bridge.
|
||||||
float bridge_angle;
|
float bridge_angle = 0.f;
|
||||||
|
|
||||||
// FillParams
|
// FillParams
|
||||||
float density;
|
float density = 0.f;
|
||||||
// Don't connect the fill lines around the inner perimeter.
|
// Don't connect the fill lines around the inner perimeter.
|
||||||
bool dont_connect;
|
bool dont_connect = false;
|
||||||
// Don't adjust spacing to fill the space evenly.
|
// Don't adjust spacing to fill the space evenly.
|
||||||
bool dont_adjust;
|
bool dont_adjust = false;
|
||||||
|
|
||||||
// width, height of extrusion, nozzle diameter, is bridge
|
// width, height of extrusion, nozzle diameter, is bridge
|
||||||
// For the output, for fill generator.
|
// For the output, for fill generator.
|
||||||
Flow flow;
|
Flow flow = Flow(0.f, 0.f, 0.f, false);
|
||||||
|
|
||||||
// For the output
|
// For the output
|
||||||
ExtrusionRole extrusion_role;
|
ExtrusionRole extrusion_role = ExtrusionRole(0);
|
||||||
|
|
||||||
// Various print settings?
|
// Various print settings?
|
||||||
|
|
||||||
// Index of this entry in a linear vector.
|
// Index of this entry in a linear vector.
|
||||||
size_t idx;
|
size_t idx = 0;
|
||||||
|
|
||||||
|
|
||||||
bool operator<(const SurfaceFillParams &rhs) const {
|
bool operator<(const SurfaceFillParams &rhs) const {
|
||||||
|
@ -246,7 +246,7 @@ static void extract_model_from_archive(
|
|||||||
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
|
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
|
||||||
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
||||||
// Just reset the normal and silently ignore it.
|
// Just reset the normal and silently ignore it.
|
||||||
memset(&facet.normal, 0, sizeof(facet.normal));
|
facet.normal = stl_normal::Zero();
|
||||||
}
|
}
|
||||||
facets.emplace_back(facet);
|
facets.emplace_back(facet);
|
||||||
}
|
}
|
||||||
@ -278,7 +278,7 @@ static void extract_model_from_archive(
|
|||||||
instance->set_rotation(instance_rotation);
|
instance->set_rotation(instance_rotation);
|
||||||
instance->set_scaling_factor(instance_scaling_factor);
|
instance->set_scaling_factor(instance_scaling_factor);
|
||||||
instance->set_offset(instance_offset);
|
instance->set_offset(instance_offset);
|
||||||
if (group_id != (size_t)-1)
|
if (group_id != (unsigned int)(-1))
|
||||||
group_to_model_object[group_id] = model_object;
|
group_to_model_object[group_id] = model_object;
|
||||||
} else {
|
} else {
|
||||||
// This is not the 1st mesh of a group. Add it to the ModelObject.
|
// This is not the 1st mesh of a group. Add it to the ModelObject.
|
||||||
|
@ -1462,7 +1462,7 @@ stl_stats ModelObject::get_object_stl_stats() const
|
|||||||
return this->volumes[0]->mesh().stl.stats;
|
return this->volumes[0]->mesh().stl.stats;
|
||||||
|
|
||||||
stl_stats full_stats;
|
stl_stats full_stats;
|
||||||
memset(&full_stats, 0, sizeof(stl_stats));
|
full_stats.volume = 0.f;
|
||||||
|
|
||||||
// fill full_stats from all objet's meshes
|
// fill full_stats from all objet's meshes
|
||||||
for (ModelVolume* volume : this->volumes)
|
for (ModelVolume* volume : this->volumes)
|
||||||
|
@ -2125,7 +2125,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
|
|||||||
}
|
}
|
||||||
// $layer->slices contains the full shape of layer, thus including
|
// $layer->slices contains the full shape of layer, thus including
|
||||||
// perimeter's width. $support contains the full shape of support
|
// perimeter's width. $support contains the full shape of support
|
||||||
// material, thus including the width of its foremost extrusion.
|
// material, thus including the width of its foremost extrusion.
|
||||||
// We leave a gap equal to a full extrusion width.
|
// We leave a gap equal to a full extrusion width.
|
||||||
support_layer.polygons = diff(support_layer.polygons, polygons_trimming);
|
support_layer.polygons = diff(support_layer.polygons, polygons_trimming);
|
||||||
}
|
}
|
||||||
@ -2934,20 +2934,13 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
|||||||
// Prepare fillers.
|
// Prepare fillers.
|
||||||
SupportMaterialPattern support_pattern = m_object_config->support_material_pattern;
|
SupportMaterialPattern support_pattern = m_object_config->support_material_pattern;
|
||||||
bool with_sheath = m_object_config->support_material_with_sheath;
|
bool with_sheath = m_object_config->support_material_with_sheath;
|
||||||
InfillPattern infill_pattern;
|
InfillPattern infill_pattern = (support_pattern == smpHoneycomb ? ipHoneycomb : ipRectilinear);
|
||||||
std::vector<float> angles;
|
std::vector<float> angles;
|
||||||
angles.push_back(base_angle);
|
angles.push_back(base_angle);
|
||||||
switch (support_pattern) {
|
|
||||||
case smpRectilinearGrid:
|
if (support_pattern == smpRectilinearGrid)
|
||||||
angles.push_back(interface_angle);
|
angles.push_back(interface_angle);
|
||||||
// fall through
|
|
||||||
case smpRectilinear:
|
|
||||||
infill_pattern = ipRectilinear;
|
|
||||||
break;
|
|
||||||
case smpHoneycomb:
|
|
||||||
infill_pattern = ipHoneycomb;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.)));
|
BoundingBox bbox_object(Point(-scale_(1.), -scale_(1.0)), Point(scale_(1.), scale_(1.)));
|
||||||
|
|
||||||
// const coordf_t link_max_length_factor = 3.;
|
// const coordf_t link_max_length_factor = 3.;
|
||||||
@ -3217,7 +3210,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
|||||||
density = 0.5f;
|
density = 0.5f;
|
||||||
flow = m_first_layer_flow;
|
flow = m_first_layer_flow;
|
||||||
// use the proper spacing for first layer as we don't need to align
|
// use the proper spacing for first layer as we don't need to align
|
||||||
// its pattern to the other layers
|
// its pattern to the other layers
|
||||||
//FIXME When paralellizing, each thread shall have its own copy of the fillers.
|
//FIXME When paralellizing, each thread shall have its own copy of the fillers.
|
||||||
filler->spacing = flow.spacing();
|
filler->spacing = flow.spacing();
|
||||||
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
|
||||||
|
@ -1225,13 +1225,16 @@ bool ConfigWizard::run(PresetBundle *preset_bundle, const PresetUpdater *updater
|
|||||||
|
|
||||||
const wxString& ConfigWizard::name(const bool from_menu/* = false*/)
|
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__
|
#if __APPLE__
|
||||||
static const wxString config_wizard_name = _(L("Configuration Assistant"));
|
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_menu = L("Configuration &Assistant");
|
||||||
#else
|
#else
|
||||||
static const wxString config_wizard_name = _(L("Configuration Wizard"));
|
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_menu = L("Configuration &Wizard");
|
||||||
#endif
|
#endif
|
||||||
return from_menu ? config_wizard_name_menu : config_wizard_name;
|
return from_menu ? config_wizard_name_menu : config_wizard_name;
|
||||||
}
|
}
|
||||||
|
@ -753,9 +753,9 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol
|
|||||||
}
|
}
|
||||||
|
|
||||||
select_items(items);
|
select_items(items);
|
||||||
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
||||||
selection_changed();
|
selection_changed();
|
||||||
#endif //no __WXOSX__ //__WXMSW__
|
//#endif //no __WXOSX__ //__WXMSW__
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::paste_objects_into_list(const std::vector<size_t>& object_idxs)
|
void ObjectList::paste_objects_into_list(const std::vector<size_t>& object_idxs)
|
||||||
@ -773,9 +773,9 @@ void ObjectList::paste_objects_into_list(const std::vector<size_t>& object_idxs)
|
|||||||
wxGetApp().plater()->changed_objects(object_idxs);
|
wxGetApp().plater()->changed_objects(object_idxs);
|
||||||
|
|
||||||
select_items(items);
|
select_items(items);
|
||||||
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
||||||
selection_changed();
|
selection_changed();
|
||||||
#endif //no __WXOSX__ //__WXMSW__
|
//#endif //no __WXOSX__ //__WXMSW__
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __WXOSX__
|
#ifdef __WXOSX__
|
||||||
@ -815,7 +815,9 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/)
|
|||||||
if (col == nullptr) {
|
if (col == nullptr) {
|
||||||
if (wxOSX)
|
if (wxOSX)
|
||||||
UnselectAll();
|
UnselectAll();
|
||||||
else
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1720,9 +1722,9 @@ void ObjectList::load_subobject(ModelVolumeType type)
|
|||||||
if (sel_item)
|
if (sel_item)
|
||||||
select_item(sel_item);
|
select_item(sel_item);
|
||||||
|
|
||||||
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
||||||
selection_changed();
|
selection_changed();
|
||||||
#endif //no __WXOSX__ //__WXMSW__
|
//#endif //no __WXOSX__ //__WXMSW__
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::load_part( ModelObject* model_object,
|
void ObjectList::load_part( ModelObject* model_object,
|
||||||
@ -1858,9 +1860,9 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
|||||||
const auto object_item = m_objects_model->GetTopParent(GetSelection());
|
const auto object_item = m_objects_model->GetTopParent(GetSelection());
|
||||||
select_item(m_objects_model->AddVolumeChild(object_item, name, type,
|
select_item(m_objects_model->AddVolumeChild(object_item, name, type,
|
||||||
new_volume->get_mesh_errors_count()>0));
|
new_volume->get_mesh_errors_count()>0));
|
||||||
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
//#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
||||||
selection_changed();
|
selection_changed();
|
||||||
#endif //no __WXOSX__ //__WXMSW__
|
//#endif //no __WXOSX__ //__WXMSW__
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::load_shape_object(const std::string& type_name)
|
void ObjectList::load_shape_object(const std::string& type_name)
|
||||||
@ -1899,6 +1901,9 @@ void ObjectList::load_shape_object(const std::string& type_name)
|
|||||||
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||||
new_object->invalidate_bounding_box();
|
new_object->invalidate_bounding_box();
|
||||||
|
|
||||||
|
new_object->center_around_origin();
|
||||||
|
new_object->ensure_on_bed();
|
||||||
|
|
||||||
const BoundingBoxf bed_shape = wxGetApp().plater()->bed_shape_bb();
|
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)));
|
new_object->instances[0]->set_offset(Slic3r::to_3d(bed_shape.center().cast<double>(), -new_object->origin_translation(2)));
|
||||||
|
|
||||||
|
@ -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 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;
|
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;
|
continue;
|
||||||
|
|
||||||
// First decide about the color of the point.
|
// 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)
|
if (m_clipping_plane_distance == 0.f)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point;
|
Vec3d transformed_point = m_model_object->instances.front()->get_transformation().get_matrix() * point;
|
||||||
transformed_point(2) += m_z_shift;
|
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));
|
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift));
|
||||||
|
|
||||||
// The raycaster query
|
// The raycaster query
|
||||||
std::vector<Vec3f> hits;
|
Vec3f hit;
|
||||||
std::vector<Vec3f> normals;
|
Vec3f normal;
|
||||||
m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, &hits, &normals);
|
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.
|
||||||
// We must also take care of the clipping plane (if active)
|
pos_and_normal = std::make_pair(hit, normal);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate and return both the point and the facet normal.
|
|
||||||
pos_and_normal = std::make_pair(hits[i], normals[i]);
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event.
|
// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event.
|
||||||
@ -481,20 +469,16 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||||||
std::vector<Vec3f> points_inside;
|
std::vector<Vec3f> points_inside;
|
||||||
std::vector<unsigned int> points_idxs = m_selection_rectangle.stop_dragging(m_parent, points);
|
std::vector<unsigned int> points_idxs = m_selection_rectangle.stop_dragging(m_parent, points);
|
||||||
for (size_t idx : points_idxs)
|
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
|
// 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,
|
for (size_t idx : m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, m_clipping_plane.get()))
|
||||||
[this](const Vec3f& pt) { return is_point_clipped(pt.cast<double>()); }))
|
|
||||||
{
|
{
|
||||||
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)
|
if (rectangle_status == GLSelectionRectangle::Deselect)
|
||||||
unselect_point(points_idxs[idx]);
|
unselect_point(points_idxs[idx]);
|
||||||
else
|
else
|
||||||
select_point(points_idxs[idx]);
|
select_point(points_idxs[idx]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ private:
|
|||||||
mutable std::unique_ptr<MeshClipper> m_supports_clipper;
|
mutable std::unique_ptr<MeshClipper> m_supports_clipper;
|
||||||
|
|
||||||
std::vector<const ConfigOption*> get_config_options(const std::vector<std::string>& keys) const;
|
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;
|
//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,
|
// Methods that do the model_object and editing cache synchronization,
|
||||||
|
@ -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,
|
bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera,
|
||||||
const Camera& camera, std::vector<Vec3f>* positions, std::vector<Vec3f>* normals) const
|
Vec3f& position, Vec3f& normal, const ClippingPlane* clipping_plane) const
|
||||||
{
|
{
|
||||||
const std::array<int, 4>& viewport = camera.get_viewport();
|
const std::array<int, 4>& viewport = camera.get_viewport();
|
||||||
const Transform3d& model_mat = camera.get_view_matrix();
|
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; });
|
std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
|
||||||
|
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
// 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:
|
// Now stuff the points in the provided vector and calculate normals if asked about them:
|
||||||
if (positions != nullptr) {
|
position = m_AABB_wrapper->get_hit_pos(hits[i]);
|
||||||
positions->clear();
|
normal = m_AABB_wrapper->get_hit_normal(hits[i]);
|
||||||
if (normals != nullptr)
|
|
||||||
normals->clear();
|
|
||||||
for (const igl::Hit& hit : hits) {
|
|
||||||
positions->push_back(m_AABB_wrapper->get_hit_pos(hit));
|
|
||||||
|
|
||||||
if (normals != nullptr)
|
|
||||||
normals->push_back(m_AABB_wrapper->get_hit_normal(hit));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points,
|
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;
|
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 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>();
|
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));
|
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) {
|
for (size_t i=0; i<points.size(); ++i) {
|
||||||
const Vec3f& pt = points[i];
|
const Vec3f& pt = points[i];
|
||||||
|
if (clipping_plane && clipping_plane->is_point_clipped(pt.cast<double>()))
|
||||||
|
continue;
|
||||||
|
|
||||||
bool is_obscured = false;
|
bool is_obscured = false;
|
||||||
// Cast a ray in the direction of the camera and look for intersection with the mesh:
|
// Cast a ray in the direction of the camera and look for intersection with the mesh:
|
||||||
std::vector<igl::Hit> hits;
|
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(
|
if (m_AABB_wrapper->m_AABB.intersect_ray(
|
||||||
AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3),
|
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),
|
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; });
|
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,
|
// 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:
|
// 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)
|
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
|
// Eradicate all hits that the caller wants to ignore
|
||||||
for (unsigned j=0; j<hits.size(); ++j) {
|
for (unsigned j=0; j<hits.size(); ++j) {
|
||||||
const igl::Hit& hit = hits[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);
|
hits.erase(hits.begin()+j);
|
||||||
--j;
|
--j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction.
|
// 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.
|
// Also, the threshold is in mesh coordinates, not in actual dimensions.
|
||||||
if (! hits.empty())
|
if (! hits.empty())
|
||||||
|
@ -50,6 +50,7 @@ public:
|
|||||||
return (-get_normal().dot(pt) + m_data[3]);
|
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_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; }
|
void set_offset(double offset) { m_data[3] = offset; }
|
||||||
Vec3d get_normal() const { return Vec3d(m_data[0], m_data[1], m_data[2]); }
|
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);
|
void set_camera(const Camera& camera);
|
||||||
|
|
||||||
bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, 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,
|
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;
|
Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const;
|
||||||
|
|
||||||
|
@ -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);
|
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();
|
p->arrange();
|
||||||
} else {
|
|
||||||
p->update();
|
p->update();
|
||||||
}
|
|
||||||
|
|
||||||
p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1);
|
p->get_selection().add_instance(obj_idx, (int)model_object->instances.size() - 1);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user