Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate
This commit is contained in:
commit
f7297a240e
13 changed files with 149 additions and 72 deletions
BIN
resources/profiles/Creality/ENDER5S1_thumbnail.png
Normal file
BIN
resources/profiles/Creality/ENDER5S1_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
resources/profiles/Creality/SERMOONV1_thumbnail.png
Normal file
BIN
resources/profiles/Creality/SERMOONV1_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -3002,9 +3002,14 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
|||
Polyline travel { this->last_pos(), point };
|
||||
|
||||
if (this->config().avoid_curled_filament_during_travels) {
|
||||
Point scaled_origin = Point(scaled(this->origin()));
|
||||
travel = m_avoid_curled_filaments.find_path(this->last_pos() + scaled_origin, point + scaled_origin);
|
||||
travel.translate(-scaled_origin);
|
||||
if (m_config.avoid_crossing_perimeters) {
|
||||
BOOST_LOG_TRIVIAL(warning)
|
||||
<< "Option >avoid curled filament during travels< is not compatible with avoid crossing perimeters and it will be ignored!";
|
||||
} else {
|
||||
Point scaled_origin = Point(scaled(this->origin()));
|
||||
travel = m_avoid_curled_filaments.find_path(this->last_pos() + scaled_origin, point + scaled_origin);
|
||||
travel.translate(-scaled_origin);
|
||||
}
|
||||
}
|
||||
|
||||
// check whether a straight travel move would need retraction
|
||||
|
|
|
@ -112,7 +112,7 @@ inline double angle(const Eigen::MatrixBase<Derived> &v1, const Eigen::MatrixBas
|
|||
template<typename Derived>
|
||||
Eigen::Matrix<typename Derived::Scalar, 2, 1, Eigen::DontAlign> to_2d(const Eigen::MatrixBase<Derived> &ptN) {
|
||||
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) >= 3, "to_2d(): first parameter is not a 3D or higher dimensional vector");
|
||||
return { ptN.x(), ptN.y() };
|
||||
return ptN.template head<2>();
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
|
||||
Vec3f get_cell_center(const Vec3i &cell_coords) const
|
||||
{
|
||||
return origin + cell_coords.cast<float>().cwiseProduct(this->cell_size) + this->cell_size.cwiseQuotient(Vec3f(2.0f, 2.0f, 2.0));
|
||||
return origin + cell_coords.cast<float>().cwiseProduct(this->cell_size) + this->cell_size.cwiseQuotient(Vec3f(2.0f, 2.0f, 2.0f));
|
||||
}
|
||||
|
||||
void take_position(const Vec3f &position) { taken_cells.insert(to_cell_index(to_cell_coords(position))); }
|
||||
|
@ -199,16 +199,6 @@ struct ExtrusionPropertiesAccumulator
|
|||
}
|
||||
};
|
||||
|
||||
// base function: ((e^(((1)/(x^(2)+1)))-1)/(e-1))
|
||||
// checkout e.g. here: https://www.geogebra.org/calculator
|
||||
float gauss(float value, float mean_x_coord, float mean_value, float falloff_speed)
|
||||
{
|
||||
float shifted = value - mean_x_coord;
|
||||
float denominator = falloff_speed * shifted * shifted + 1.0f;
|
||||
float exponent = 1.0f / denominator;
|
||||
return mean_value * (std::exp(exponent) - 1.0f) / (std::exp(1.0f) - 1.0f);
|
||||
}
|
||||
|
||||
std::vector<ExtrusionLine> to_short_lines(const ExtrusionEntity *e, float length_limit)
|
||||
{
|
||||
assert(!e->is_collection());
|
||||
|
|
|
@ -977,8 +977,10 @@ indexed_triangle_set its_make_cone(double r, double h, double fa)
|
|||
vertices.emplace_back(Vec3f(0., 0., h));
|
||||
|
||||
size_t i = 0;
|
||||
const auto vec = Eigen::Vector2f(0, float(r));
|
||||
for (double angle=0; angle<2*PI; angle+=fa) {
|
||||
vertices.emplace_back(r*std::cos(angle), r*std::sin(angle), 0.);
|
||||
Vec2f p = Eigen::Rotation2Df(angle) * vec;
|
||||
vertices.emplace_back(Vec3f(p(0), p(1), 0.f));
|
||||
if (angle > 0.) {
|
||||
facets.emplace_back(0, i+2, i+1);
|
||||
facets.emplace_back(1, i+1, i+2);
|
||||
|
|
|
@ -137,18 +137,41 @@ enum class FacetSliceType {
|
|||
Cutting = 2
|
||||
};
|
||||
|
||||
// Return true, if the facet has been sliced and line_out has been filled.
|
||||
static FacetSliceType slice_facet(
|
||||
// Z height of the slice in XY plane. Scaled or unscaled (same as vertices[].z()).
|
||||
float slice_z,
|
||||
// 3 vertices of the triangle, XY scaled. Z scaled or unscaled (same as slice_z).
|
||||
const stl_vertex *vertices,
|
||||
const stl_triangle_vertex_indices &indices,
|
||||
const Vec3i &edge_ids,
|
||||
const int idx_vertex_lowest,
|
||||
const bool horizontal,
|
||||
IntersectionLine &line_out)
|
||||
// Convert an int32_t scaled coordinate into an unscaled 3D floating point coordinate (mesh vertex).
|
||||
template<typename T>
|
||||
inline Vec3f contour_point_to_v3f(const Point &pt, const T z)
|
||||
{
|
||||
return to_3d(
|
||||
// unscale using doubles for higher accuracy
|
||||
unscaled<double>(pt).
|
||||
// then convert to floats
|
||||
cast<float>(),
|
||||
float(z));
|
||||
}
|
||||
|
||||
// Convert 2D projection of an int32_t scaled coordinate into an unscaled 3D floating point coordinate (mesh vertex).
|
||||
template<typename Derived>
|
||||
inline Point v3f_scaled_to_contour_point(const Eigen::MatrixBase<Derived> &v)
|
||||
{
|
||||
static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) >= 2, "v3f_scaled_to_contour_point(): Not a 2D or 3D vector.");
|
||||
using T = typename Derived::Scalar;
|
||||
return { coord_t(std::floor(v.x() + T(0.5))), coord_t(std::floor(v.y() + T(0.5))) };
|
||||
}
|
||||
|
||||
// Return true, if the facet has been sliced and line_out has been filled.
|
||||
template<typename T>
|
||||
inline FacetSliceType slice_facet(
|
||||
// Z height of the slice in XY plane. Scaled or unscaled (same as vertices[].z()).
|
||||
T slice_z,
|
||||
// 3 vertices of the triangle, XY scaled. Z scaled or unscaled (same as slice_z).
|
||||
const Eigen::Matrix<T, 3, 1, Eigen::DontAlign> *vertices,
|
||||
const stl_triangle_vertex_indices &indices,
|
||||
const Vec3i &edge_ids,
|
||||
const int idx_vertex_lowest,
|
||||
const bool horizontal,
|
||||
IntersectionLine &line_out)
|
||||
{
|
||||
using Vector = Eigen::Matrix<T, 3, 1, Eigen::DontAlign>;
|
||||
IntersectionPoint points[3];
|
||||
size_t num_points = 0;
|
||||
auto point_on_layer = size_t(-1);
|
||||
|
@ -158,7 +181,7 @@ static FacetSliceType slice_facet(
|
|||
// (external on the right of the line)
|
||||
for (int j = 0; j < 3; ++ j) { // loop through facet edges
|
||||
int edge_id;
|
||||
const stl_vertex *a, *b;
|
||||
const Vector *a, *b;
|
||||
int a_id, b_id;
|
||||
{
|
||||
int k = (idx_vertex_lowest + j) % 3;
|
||||
|
@ -174,16 +197,16 @@ static FacetSliceType slice_facet(
|
|||
if (a->z() == slice_z && b->z() == slice_z) {
|
||||
// Edge is horizontal and belongs to the current layer.
|
||||
// The following rotation of the three vertices may not be efficient, but this branch happens rarely.
|
||||
const stl_vertex &v0 = vertices[0];
|
||||
const stl_vertex &v1 = vertices[1];
|
||||
const stl_vertex &v2 = vertices[2];
|
||||
const Vector &v0 = vertices[0];
|
||||
const Vector &v1 = vertices[1];
|
||||
const Vector &v2 = vertices[2];
|
||||
// We may ignore this edge for slicing purposes, but we may still use it for object cutting.
|
||||
FacetSliceType result = FacetSliceType::Slicing;
|
||||
if (horizontal) {
|
||||
// All three vertices are aligned with slice_z.
|
||||
line_out.edge_type = IntersectionLine::FacetEdgeType::Horizontal;
|
||||
result = FacetSliceType::Cutting;
|
||||
double normal = (v1.x() - v0.x()) * (v2.y() - v1.y()) - (v1.y() - v0.y()) * (v2.x() - v1.x());
|
||||
double normal = cross2((to_2d(v1) - to_2d(v0)).template cast<double>(), (to_2d(v2) - to_2d(v1)).template cast<double>());
|
||||
if (normal < 0) {
|
||||
// If normal points downwards this is a bottom horizontal facet so we reverse its point order.
|
||||
std::swap(a, b);
|
||||
|
@ -205,10 +228,8 @@ static FacetSliceType slice_facet(
|
|||
} else
|
||||
line_out.edge_type = IntersectionLine::FacetEdgeType::Bottom;
|
||||
}
|
||||
line_out.a.x() = a->x();
|
||||
line_out.a.y() = a->y();
|
||||
line_out.b.x() = b->x();
|
||||
line_out.b.y() = b->y();
|
||||
line_out.a = v3f_scaled_to_contour_point(*a);
|
||||
line_out.b = v3f_scaled_to_contour_point(*b);
|
||||
line_out.a_id = a_id;
|
||||
line_out.b_id = b_id;
|
||||
assert(line_out.a != line_out.b);
|
||||
|
@ -220,8 +241,7 @@ static FacetSliceType slice_facet(
|
|||
if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != a_id) {
|
||||
point_on_layer = num_points;
|
||||
IntersectionPoint &point = points[num_points ++];
|
||||
point.x() = a->x();
|
||||
point.y() = a->y();
|
||||
static_cast<Point&>(point) = v3f_scaled_to_contour_point(*a);
|
||||
point.point_id = a_id;
|
||||
}
|
||||
} else if (b->z() == slice_z) {
|
||||
|
@ -229,8 +249,7 @@ static FacetSliceType slice_facet(
|
|||
if (point_on_layer == size_t(-1) || points[point_on_layer].point_id != b_id) {
|
||||
point_on_layer = num_points;
|
||||
IntersectionPoint &point = points[num_points ++];
|
||||
point.x() = b->x();
|
||||
point.y() = b->y();
|
||||
static_cast<Point&>(point) = v3f_scaled_to_contour_point(*b);
|
||||
point.point_id = b_id;
|
||||
}
|
||||
} else if ((a->z() < slice_z && b->z() > slice_z) || (b->z() < slice_z && a->z() > slice_z)) {
|
||||
|
@ -270,16 +289,10 @@ static FacetSliceType slice_facet(
|
|||
}
|
||||
#else
|
||||
// Just clamp the intersection point to source triangle edge.
|
||||
if (t <= 0.) {
|
||||
point.x() = a->x();
|
||||
point.y() = a->y();
|
||||
} else if (t >= 1.) {
|
||||
point.x() = b->x();
|
||||
point.y() = b->y();
|
||||
} else {
|
||||
point.x() = coord_t(floor(double(a->x()) + (double(b->x()) - double(a->x())) * t + 0.5));
|
||||
point.y() = coord_t(floor(double(a->y()) + (double(b->y()) - double(a->y())) * t + 0.5));
|
||||
}
|
||||
static_cast<Point&>(point) =
|
||||
t <= 0. ? v3f_scaled_to_contour_point(*a) :
|
||||
t >= 1. ? v3f_scaled_to_contour_point(*b) :
|
||||
v3f_scaled_to_contour_point(a->template head<2>().template cast<double>() * (1. - t) + b->template head<2>().template cast<double>() * t + Vec2d(0.5, 0.5));
|
||||
point.edge_id = edge_id;
|
||||
++ num_points;
|
||||
#endif
|
||||
|
@ -2182,28 +2195,44 @@ void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *u
|
|||
int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0);
|
||||
FacetSliceType slice_type = FacetSliceType::NoSlice;
|
||||
if (z > min_z - EPSILON && z < max_z + EPSILON) {
|
||||
Vec3f vertices_scaled[3];
|
||||
Vec3d vertices_scaled[3];
|
||||
for (int i = 0; i < 3; ++ i) {
|
||||
const Vec3f &src = vertices[i];
|
||||
Vec3f &dst = vertices_scaled[i];
|
||||
dst.x() = scale_(src.x());
|
||||
dst.y() = scale_(src.y());
|
||||
Vec3d &dst = vertices_scaled[i];
|
||||
dst.x() = scaled<double>(src.x());
|
||||
dst.y() = scaled<double>(src.y());
|
||||
dst.z() = src.z();
|
||||
}
|
||||
slice_type = slice_facet(z, vertices_scaled, mesh.indices[facet_idx], facets_edge_ids[facet_idx], idx_vertex_lowest, min_z == max_z, line);
|
||||
slice_type = slice_facet(double(z), vertices_scaled, mesh.indices[facet_idx], facets_edge_ids[facet_idx], idx_vertex_lowest, min_z == max_z, line);
|
||||
}
|
||||
|
||||
if (slice_type != FacetSliceType::NoSlice) {
|
||||
// Save intersection lines for generating correct triangulations.
|
||||
if (line.edge_type == IntersectionLine::FacetEdgeType::Top) {
|
||||
lower_lines.emplace_back(line);
|
||||
lower_slice_vertices.emplace_back(line.a_id);
|
||||
lower_slice_vertices.emplace_back(line.b_id);
|
||||
if (lower) {
|
||||
lower_lines.emplace_back(line);
|
||||
if (triangulate_caps) {
|
||||
// Snap these vertices to coord_t grid, so that they will be matched with the vertices produced
|
||||
// by triangulating opening on the cut.
|
||||
lower->vertices[line.a_id] = contour_point_to_v3f(line.a, z);
|
||||
lower->vertices[line.b_id] = contour_point_to_v3f(line.b, z);
|
||||
}
|
||||
}
|
||||
} else if (line.edge_type == IntersectionLine::FacetEdgeType::Bottom) {
|
||||
upper_lines.emplace_back(line);
|
||||
upper_slice_vertices.emplace_back(line.a_id);
|
||||
upper_slice_vertices.emplace_back(line.b_id);
|
||||
} else if (line.edge_type == IntersectionLine::FacetEdgeType::General) {
|
||||
if (upper) {
|
||||
upper_lines.emplace_back(line);
|
||||
if (triangulate_caps) {
|
||||
// Snap these vertices to coord_t grid, so that they will be matched with the vertices produced
|
||||
// by triangulating opening on the cut.
|
||||
upper->vertices[line.a_id] = contour_point_to_v3f(line.a, z);
|
||||
upper->vertices[line.b_id] = contour_point_to_v3f(line.b, z);
|
||||
}
|
||||
}
|
||||
} else if (line.edge_type == IntersectionLine::FacetEdgeType::General && triangulate_caps) {
|
||||
lower_lines.emplace_back(line);
|
||||
upper_lines.emplace_back(line);
|
||||
}
|
||||
|
@ -2235,11 +2264,11 @@ void cut_mesh(const indexed_triangle_set &mesh, float z, indexed_triangle_set *u
|
|||
assert(facets_edge_ids[facet_idx](iv) == line.edge_a_id || facets_edge_ids[facet_idx](iv) == line.edge_b_id);
|
||||
if (facets_edge_ids[facet_idx](iv) == line.edge_a_id) {
|
||||
// Unscale to doubles first, then to floats to reach the same accuracy as triangulate_expolygons_2d().
|
||||
v0v1 = to_3d(unscaled<double>(line.a).cast<float>().eval(), z);
|
||||
v2v0 = to_3d(unscaled<double>(line.b).cast<float>().eval(), z);
|
||||
v0v1 = contour_point_to_v3f(line.a, z);
|
||||
v2v0 = contour_point_to_v3f(line.b, z);
|
||||
} else {
|
||||
v0v1 = to_3d(unscaled<double>(line.b).cast<float>().eval(), z);
|
||||
v2v0 = to_3d(unscaled<double>(line.a).cast<float>().eval(), z);
|
||||
v0v1 = contour_point_to_v3f(line.b, z);
|
||||
v2v0 = contour_point_to_v3f(line.a, z);
|
||||
}
|
||||
const stl_vertex &v0 = vertices[iv];
|
||||
const int iv0 = facet[iv];
|
||||
|
|
|
@ -127,7 +127,9 @@ void GLVolume::SinkingContours::update()
|
|||
init_data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
|
||||
}
|
||||
}
|
||||
m_model.init_from(std::move(init_data));
|
||||
|
||||
if (init_data.vertices_count() > 0)
|
||||
m_model.init_from(std::move(init_data));
|
||||
}
|
||||
|
||||
void GLVolume::NonManifoldEdges::render()
|
||||
|
@ -437,9 +439,9 @@ std::vector<int> GLVolumeCollection::load_object(
|
|||
|
||||
int GLVolumeCollection::load_object_volume(
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx)
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx)
|
||||
{
|
||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||
const int extruder_id = model_volume->extruder_id();
|
||||
|
@ -452,10 +454,12 @@ int GLVolumeCollection::load_object_volume(
|
|||
v.printable = instance->printable;
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.model.init_from(*mesh, true);
|
||||
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
|
||||
if (m_use_raycasters)
|
||||
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
|
||||
#else
|
||||
v.model.init_from(*mesh);
|
||||
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
|
||||
if (m_use_raycasters)
|
||||
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
|
||||
if (model_volume->is_model_part()) {
|
||||
|
|
|
@ -397,6 +397,7 @@ private:
|
|||
Slope m_slope;
|
||||
bool m_show_sinking_contours{ false };
|
||||
bool m_show_non_manifold_edges{ true };
|
||||
bool m_use_raycasters{ true };
|
||||
|
||||
public:
|
||||
GLVolumePtrs volumes;
|
||||
|
@ -445,6 +446,7 @@ public:
|
|||
bool empty() const { return volumes.empty(); }
|
||||
void set_range(double low, double high) { for (GLVolume* vol : this->volumes) vol->set_range(low, high); }
|
||||
|
||||
void set_use_raycasters(bool value) { m_use_raycasters = value; }
|
||||
void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; }
|
||||
|
||||
void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; }
|
||||
|
|
|
@ -315,6 +315,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||
"wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" })
|
||||
toggle_field(el, have_wipe_tower);
|
||||
|
||||
toggle_field("avoid_curled_filament_during_travels", !config->opt_bool("avoid_crossing_perimeters"));
|
||||
toggle_field("avoid_crossing_perimeters", !config->opt_bool("avoid_curled_filament_during_travels"));
|
||||
|
||||
bool have_avoid_crossing_perimeters = config->opt_bool("avoid_crossing_perimeters");
|
||||
toggle_field("avoid_crossing_perimeters_max_detour", have_avoid_crossing_perimeters);
|
||||
|
||||
|
|
|
@ -643,7 +643,7 @@ const ColorRGBA GCodeViewer::Neutral_Color = ColorRGBA::DARK_GRAY();
|
|||
GCodeViewer::GCodeViewer()
|
||||
{
|
||||
m_extrusions.reset_role_visibility_flags();
|
||||
|
||||
m_shells.volumes.set_use_raycasters(false);
|
||||
// m_sequential_view.skip_invisible_moves = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ static const ColorRGBA SELECTED_PLAG_COLOR = ColorRGBA::GRAY();
|
|||
static const ColorRGBA SELECTED_DOWEL_COLOR = ColorRGBA::DARK_GRAY();
|
||||
static const ColorRGBA CONNECTOR_DEF_COLOR = ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f);
|
||||
static const ColorRGBA CONNECTOR_ERR_COLOR = ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f);
|
||||
static const ColorRGBA HOVERED_ERR_COLOR = ColorRGBA(1.0f, 0.3f, 0.3f, 1.0f);
|
||||
|
||||
const unsigned int AngleResolution = 64;
|
||||
const unsigned int ScaleStepsCount = 72;
|
||||
|
@ -1849,7 +1850,7 @@ Transform3d GLGizmoCut3D::get_volume_transformation(const ModelVolume* volume) c
|
|||
return translation_transform(offset) * scale_transform(Vec3d::Ones() - border_scale) * vol_matrix;
|
||||
}
|
||||
|
||||
bool GLGizmoCut3D::is_conflict_for_connector(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos)
|
||||
bool GLGizmoCut3D::is_outside_of_cut_contour(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos)
|
||||
{
|
||||
// check if connector pos is out of clipping plane
|
||||
if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(cur_pos)) {
|
||||
|
@ -1857,16 +1858,54 @@ bool GLGizmoCut3D::is_conflict_for_connector(size_t idx, const CutConnectors& co
|
|||
return true;
|
||||
}
|
||||
|
||||
// check if connector bottom contour is out of clipping plane
|
||||
const CutConnector& cur_connector = connectors[idx];
|
||||
const CutConnectorShape shape = CutConnectorShape(cur_connector.attribs.shape);
|
||||
const int sectorCount = shape == CutConnectorShape::Triangle ? 3 :
|
||||
shape == CutConnectorShape::Square ? 4 :
|
||||
shape == CutConnectorShape::Circle ? 60: // supposably, 60 points are enough for conflict detection
|
||||
shape == CutConnectorShape::Hexagon ? 6 : 1 ;
|
||||
|
||||
indexed_triangle_set mesh;
|
||||
auto& vertices = mesh.vertices;
|
||||
vertices.reserve(sectorCount + 1);
|
||||
|
||||
float fa = 2 * PI / sectorCount;
|
||||
auto vec = Eigen::Vector2f(0, cur_connector.radius);
|
||||
for (float angle = 0; angle < 2.f * PI; angle += fa) {
|
||||
Vec2f p = Eigen::Rotation2Df(angle) * vec;
|
||||
vertices.emplace_back(Vec3f(p(0), p(1), 0.f));
|
||||
}
|
||||
its_transform(mesh, translation_transform(cur_pos) * m_rotation_m);
|
||||
|
||||
for (auto vertex : vertices) {
|
||||
if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(vertex.cast<double>())) {
|
||||
m_info_stats.outside_cut_contour++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLGizmoCut3D::is_conflict_for_connector(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos)
|
||||
{
|
||||
if (is_outside_of_cut_contour(idx, connectors, cur_pos))
|
||||
return true;
|
||||
|
||||
const CutConnector& cur_connector = connectors[idx];
|
||||
|
||||
const Transform3d matrix = translation_transform(cur_pos) * m_rotation_m *
|
||||
scale_transform(Vec3f(cur_connector.radius, cur_connector.radius, cur_connector.height).cast<double>());
|
||||
const BoundingBoxf3 cur_tbb = m_shapes[cur_connector.attribs].model.get_bounding_box().transformed(matrix);
|
||||
|
||||
// check if connector's bounding box is inside the object's bounding box
|
||||
if (!bounding_box().contains(cur_tbb)) {
|
||||
m_info_stats.outside_bb++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if connectors are overlapping
|
||||
for (size_t i = 0; i < connectors.size(); ++i) {
|
||||
if (i == idx)
|
||||
continue;
|
||||
|
@ -1920,7 +1959,8 @@ void GLGizmoCut3D::render_connectors()
|
|||
Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ();
|
||||
|
||||
// First decide about the color of the point.
|
||||
if (is_conflict_for_connector(i, connectors, pos)) {
|
||||
const bool conflict_connector = is_conflict_for_connector(i, connectors, pos);
|
||||
if (conflict_connector) {
|
||||
m_has_invalid_connector = true;
|
||||
render_color = CONNECTOR_ERR_COLOR;
|
||||
}
|
||||
|
@ -1930,7 +1970,8 @@ void GLGizmoCut3D::render_connectors()
|
|||
if (!m_connectors_editing)
|
||||
render_color = CONNECTOR_ERR_COLOR;
|
||||
else if (size_t(m_hover_id - m_connectors_group_id) == i)
|
||||
render_color = connector.attribs.type == CutConnectorType::Dowel ? HOVERED_DOWEL_COLOR : HOVERED_PLAG_COLOR;
|
||||
render_color = conflict_connector ? HOVERED_ERR_COLOR :
|
||||
connector.attribs.type == CutConnectorType::Dowel ? HOVERED_DOWEL_COLOR : HOVERED_PLAG_COLOR;
|
||||
else if (m_selected[i])
|
||||
render_color = connector.attribs.type == CutConnectorType::Dowel ? SELECTED_DOWEL_COLOR : SELECTED_PLAG_COLOR;
|
||||
|
||||
|
|
|
@ -241,6 +241,7 @@ private:
|
|||
bool render_reset_button(const std::string& label_id, const std::string& tooltip) const;
|
||||
bool render_connect_type_radio_button(CutConnectorType type);
|
||||
Transform3d get_volume_transformation(const ModelVolume* volume) const;
|
||||
bool is_outside_of_cut_contour(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos);
|
||||
bool is_conflict_for_connector(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos);
|
||||
void render_connectors();
|
||||
|
||||
|
|
Loading…
Reference in a new issue