diff --git a/resources/icons/rivet.svg b/resources/icons/rivet.svg
new file mode 100644
index 0000000000..db4760cb65
--- /dev/null
+++ b/resources/icons/rivet.svg
@@ -0,0 +1,13 @@
+
+
+
diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h
index 5aed978426..a152252bac 100644
--- a/src/imgui/imconfig.h
+++ b/src/imgui/imconfig.h
@@ -152,6 +152,7 @@ namespace ImGui
// const wchar_t MmuSegmentationMarker = 0x1F;
const wchar_t PlugMarker = 0x1C;
const wchar_t DowelMarker = 0x1D;
+ const wchar_t RivetMarker = 0x1E;
// Do not forget use following letters only in wstring
const wchar_t DocumentationButton = 0x2600;
const wchar_t DocumentationHoverButton = 0x2601;
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 5c001e3538..7bf8608dde 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -1302,7 +1302,9 @@ indexed_triangle_set ModelObject::get_connector_mesh(CutConnectorAttributes conn
break;
}
- if (connector_attributes.style == CutConnectorStyle::Prism)
+ if (connector_attributes.type == CutConnectorType::Rivet)
+ connector_mesh = its_make_rivet(1.0, 1.0, (2 * PI / /*sectorCount*/10));
+ else if (connector_attributes.style == CutConnectorStyle::Prism)
connector_mesh = its_make_cylinder(1.0, 1.0, (2 * PI / sectorCount));
else if (connector_attributes.type == CutConnectorType::Plug)
connector_mesh = its_make_frustum(1.0, 1.0, (2 * PI / sectorCount));
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 2ee48f9917..d0409588ff 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -224,6 +224,7 @@ private:
enum class CutConnectorType : int {
Plug
, Dowel
+ , Rivet
, Undef
};
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index 4bf9fd486a..374387273f 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -1262,6 +1262,181 @@ indexed_triangle_set its_make_frustum_dowel(double radius, double h, int sectorC
return mesh;
}
+indexed_triangle_set its_make_rivet(double r, double h, double fa)
+{
+ const float radius = (float)r;
+ const float height = (float)h;
+ const size_t sectors_cnt = 10;//(float)fa;
+ const float halfPI = 0.5f * (float)PI;
+
+ const float space_len = 0.2f * radius;
+
+ const float b_len = 0.75f * radius;
+ const float m_len = radius;
+ const float t_len = 0.5f * radius;
+
+ const float b_height = 0.f;
+ const float m_height = 0.5f * height;
+ const float t_height = height;
+
+ const float b_angle = acos(space_len/b_len);
+ const float m_angle = acos(space_len/m_len);
+ const float t_angle = acos(space_len/t_len);
+
+ const float b_angle_step = b_angle / (float)sectors_cnt;
+ const float m_angle_step = m_angle / (float)sectors_cnt;
+ const float t_angle_step = t_angle / (float)sectors_cnt;
+
+ const Vec2f b_vec = Eigen::Vector2f(0, b_len);
+ const Vec2f m_vec = Eigen::Vector2f(0, m_len);
+ const Vec2f t_vec = Eigen::Vector2f(0, t_len);
+
+ const Vec2f space_vec = Eigen::Vector2f(0, space_len);
+ Vec2f b_pt = Eigen::Rotation2Df(halfPI) * space_vec;
+
+
+ indexed_triangle_set mesh;
+
+ auto& vertices = mesh.vertices;
+ auto& facets = mesh.indices;
+
+ vertices.reserve(2 * 3 * sectors_cnt + 2);
+ facets.reserve(2 * 6 * sectors_cnt);
+
+
+ float b_angle_start = halfPI - b_angle;
+ float m_angle_start = halfPI - m_angle;
+ float t_angle_start = halfPI - t_angle;
+
+ float b_angle_stop = halfPI + b_angle;
+
+ // 2 special vertices, top and bottom center, rest are relative to this
+ vertices.emplace_back(Vec3f(-space_len, 0.f, b_height));
+ vertices.emplace_back(Vec3f(-space_len, 0.f, t_height));
+
+ int frst_id = 0;
+ int scnd_id = 1;
+
+ auto add_side_vertices = [b_vec, m_vec, t_vec, b_height, m_height, t_height](std::vector& vertices, float b_angle, float m_angle, float t_angle) {
+ Vec2f b_pt = Eigen::Rotation2Df(b_angle) * b_vec;
+ Vec2f m_pt = Eigen::Rotation2Df(m_angle) * m_vec;
+ Vec2f t_pt = Eigen::Rotation2Df(t_angle) * t_vec;
+
+ vertices.emplace_back(Vec3f(b_pt(0), b_pt(1), b_height));
+ vertices.emplace_back(Vec3f(m_pt(0), m_pt(1), m_height));
+ vertices.emplace_back(Vec3f(t_pt(0), t_pt(1), t_height));
+ };
+
+ // add first vertices and facets
+ {
+ add_side_vertices(vertices, b_angle_start, m_angle_start, t_angle_start);
+
+ int id = (int)vertices.size() - 1;
+
+ facets.emplace_back(id - 4, id - 2, id - 1);
+ facets.emplace_back(id - 4, id - 1, id);
+ facets.emplace_back(id - 4, id, id - 3);
+ }
+
+ while (b_angle_start < b_angle_stop) {
+ b_angle_start += b_angle_step;
+ m_angle_start += m_angle_step;
+ t_angle_start += t_angle_step;
+
+ add_side_vertices(vertices, b_angle_start, m_angle_start, t_angle_start);
+
+ int id = (int)vertices.size() - 1;
+
+ facets.emplace_back(frst_id, id - 2, id - 5);
+
+ facets.emplace_back(id - 2, id - 1, id - 5);
+ facets.emplace_back(id - 1, id - 4, id - 5);
+ facets.emplace_back(id - 4, id - 1, id);
+ facets.emplace_back(id, id - 3, id - 4);
+
+ facets.emplace_back(id, scnd_id, id - 3);
+ }
+
+ // add facets to close the mesh
+ {
+ int id = (int)vertices.size() - 1;
+
+ facets.emplace_back(frst_id, scnd_id, id);
+ facets.emplace_back(frst_id, id, id - 1);
+ facets.emplace_back(frst_id, id - 1, id - 2);
+ }
+
+
+
+
+ b_angle_start = 3 * halfPI - b_angle;
+ m_angle_start = 3 * halfPI - m_angle;
+ t_angle_start = 3 * halfPI - t_angle;
+
+ b_angle_stop = 3 * halfPI + b_angle;
+
+ frst_id = (int)vertices.size();
+ scnd_id = frst_id+1;
+
+ // 2 special vertices, top and bottom center, rest are relative to this
+ vertices.emplace_back(Vec3f(space_len, 0.f, b_height));
+ vertices.emplace_back(Vec3f(space_len, 0.f, t_height));
+
+ // add first vertices and facets
+ {
+ Vec2f b_pt = Eigen::Rotation2Df(b_angle_start) * b_vec;
+ Vec2f m_pt = Eigen::Rotation2Df(m_angle_start) * m_vec;
+ Vec2f t_pt = Eigen::Rotation2Df(t_angle_start) * t_vec;
+
+ vertices.emplace_back(Vec3f(b_pt(0), b_pt(1), b_height));
+ vertices.emplace_back(Vec3f(m_pt(0), m_pt(1), m_height));
+ vertices.emplace_back(Vec3f(t_pt(0), t_pt(1), t_height));
+
+ int id = (int)vertices.size() - 1;
+
+ facets.emplace_back(id - 4, id - 2, id - 1);
+ facets.emplace_back(id - 4, id - 1, id);
+ facets.emplace_back(id - 4, id , id - 3);
+ }
+
+ while (b_angle_start < b_angle_stop) {
+ b_angle_start += b_angle_step;
+ m_angle_start += m_angle_step;
+ t_angle_start += t_angle_step;
+
+ Vec2f b_pt = Eigen::Rotation2Df(b_angle_start) * b_vec;
+ Vec2f m_pt = Eigen::Rotation2Df(m_angle_start) * m_vec;
+ Vec2f t_pt = Eigen::Rotation2Df(t_angle_start) * t_vec;
+
+ vertices.emplace_back(Vec3f(b_pt(0), b_pt(1), b_height));
+ vertices.emplace_back(Vec3f(m_pt(0), m_pt(1), m_height));
+ vertices.emplace_back(Vec3f(t_pt(0), t_pt(1), t_height));
+
+ int id = (int)vertices.size() - 1;
+
+ facets.emplace_back(frst_id, id - 2, id - 5);
+
+ facets.emplace_back(id - 2, id - 1, id - 5);
+ facets.emplace_back(id - 1, id - 4, id - 5);
+ facets.emplace_back(id - 4, id - 1, id);
+ facets.emplace_back(id, id - 3, id - 4);
+
+ facets.emplace_back(id, scnd_id, id - 3);
+ }
+
+ // add facets to close the mesh
+ {
+ int id = (int)vertices.size() - 1;
+
+ facets.emplace_back(frst_id, scnd_id, id);
+ facets.emplace_back(frst_id, id, id - 1);
+ facets.emplace_back(frst_id, id - 1, id - 2);
+ }
+
+
+ return mesh;
+}
+
indexed_triangle_set its_convex_hull(const std::vector &pts)
{
std::vector dst_vertices;
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index 0f43f9d58d..f6a18f59ce 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -321,6 +321,7 @@ indexed_triangle_set its_make_frustum(double r, double h, double fa=(2*PI/360
indexed_triangle_set its_make_frustum_dowel(double r, double h, int sectorCount);
indexed_triangle_set its_make_pyramid(float base, float height);
indexed_triangle_set its_make_sphere(double radius, double fa);
+indexed_triangle_set its_make_rivet(double r, double h, double fa=(2*PI/360));
indexed_triangle_set its_convex_hull(const std::vector &pts);
inline indexed_triangle_set its_convex_hull(const indexed_triangle_set &its) { return its_convex_hull(its.vertices); }
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
index 27585aefd4..9a217a461d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
@@ -186,8 +186,7 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename,
, m_connector_style (int(CutConnectorStyle::Prism))
, m_connector_shape_id (int(CutConnectorShape::Circle))
{
- m_mode = size_t(CutMode::cutTongueAndGroove);
- m_contour_width = .0f;
+ m_connector_type = CutConnectorType::Rivet;
m_modes = { _u8L("Planar"), _u8L("Tongue and Groove")//, _u8L("Grid")
// , _u8L("Radial"), _u8L("Modular")
@@ -197,7 +196,8 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename,
std::map connetor_types = {
{ImGui::PlugMarker , _u8L("Plug") },
- {ImGui::DowelMarker, _u8L("Dowel") },
+ {ImGui::DowelMarker, _u8L("Dowel") },
+ {ImGui::RivetMarker, _u8L("Rivet") },
};
for (auto connector : connetor_types) {
std::string type_label = " " + connector.second + " ";
@@ -1986,20 +1986,27 @@ void GLGizmoCut3D::render_connectors_input_window(CutConnectors &connectors)
m_imgui->text(m_labels_map["Type"]);
bool type_changed = render_connect_type_radio_button(CutConnectorType::Plug);
type_changed |= render_connect_type_radio_button(CutConnectorType::Dowel);
+ type_changed |= render_connect_type_radio_button(CutConnectorType::Rivet);
if (type_changed)
apply_selected_connectors([this, &connectors] (size_t idx) { connectors[idx].attribs.type = CutConnectorType(m_connector_type); });
- m_imgui->disabled_begin(m_connector_type == CutConnectorType::Dowel);
- if (type_changed && m_connector_type == CutConnectorType::Dowel) {
- m_connector_style = int(CutConnectorStyle::Prism);
- apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); });
- }
- if (render_combo(m_labels_map["Style"], m_connector_styles, m_connector_style))
- apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); });
+ m_imgui->disabled_begin(m_connector_type != CutConnectorType::Plug);
+ if (type_changed && m_connector_type == CutConnectorType::Dowel) {
+ m_connector_style = int(CutConnectorStyle::Prism);
+ apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); });
+ }
+ if (render_combo(m_labels_map["Style"], m_connector_styles, m_connector_style))
+ apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.style = CutConnectorStyle(m_connector_style); });
m_imgui->disabled_end();
- if (render_combo(m_labels_map["Shape"], m_connector_shapes, m_connector_shape_id))
- apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); });
+ m_imgui->disabled_begin(m_connector_type == CutConnectorType::Rivet);
+ if (type_changed && m_connector_type == CutConnectorType::Rivet) {
+ m_connector_shape_id = int(CutConnectorShape::Circle);
+ apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); });
+ }
+ if (render_combo(m_labels_map["Shape"], m_connector_shapes, m_connector_shape_id))
+ apply_selected_connectors([this, &connectors](size_t idx) { connectors[idx].attribs.shape = CutConnectorShape(m_connector_shape_id); });
+ m_imgui->disabled_end();
if (render_slider_double_input(m_labels_map["Depth"], m_connector_depth_ratio, m_connector_depth_ratio_tolerance))
apply_selected_connectors([this, &connectors](size_t idx) {
@@ -3232,11 +3239,13 @@ void GLGizmoCut3D::reset_connectors()
void GLGizmoCut3D::init_connector_shapes()
{
- for (const CutConnectorType& type : {CutConnectorType::Dowel, CutConnectorType::Plug})
+ for (const CutConnectorType& type : {CutConnectorType::Dowel, CutConnectorType::Plug, CutConnectorType::Rivet})
for (const CutConnectorStyle& style : {CutConnectorStyle::Frustum, CutConnectorStyle::Prism}) {
if (type == CutConnectorType::Dowel && style == CutConnectorStyle::Frustum)
continue;
for (const CutConnectorShape& shape : {CutConnectorShape::Circle, CutConnectorShape::Hexagon, CutConnectorShape::Square, CutConnectorShape::Triangle}) {
+ if (type == CutConnectorType::Rivet && shape != CutConnectorShape::Circle)
+ continue;
const CutConnectorAttributes attribs = { type, style, shape };
indexed_triangle_set its = ModelObject::get_connector_mesh(attribs);
m_shapes[attribs].model.init_from(its);
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 1a800eee42..ec1d039888 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -67,6 +67,7 @@ static const std::map font_icons = {
{ImGui::InfoMarkerSmall , "notification_info" },
{ImGui::PlugMarker , "plug" },
{ImGui::DowelMarker , "dowel" },
+ {ImGui::RivetMarker , "rivet" },
};
static const std::map font_icons_large = {