This commit is contained in:
enricoturri1966 2022-12-12 08:40:51 +01:00
commit fd956ecc49
43 changed files with 4634 additions and 4163 deletions

View File

@ -1,28 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve"> width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="cut"> <path fill="#ED6B21" d="M3.0597045,10.3634434H0.5884437C0.2628375,10.3634434,0,10.100606,0,9.7750006
<g> c0-0.3256063,0.2628375-0.5884438,0.5884437-0.5884438h2.4712608c0.3256061,0,0.5884435,0.2628374,0.5884435,0.5884438
<path fill="#ED6B21" d="M118.12,65.5h-10c-0.83,0-1.5-0.67-1.5-1.5s0.67-1.5,1.5-1.5h10c0.83,0,1.5,0.67,1.5,1.5 C3.6481481,10.100606,3.3853078,10.3634434,3.0597045,10.3634434z"/>
S118.95,65.5,118.12,65.5z M98.12,65.5h-10c-0.83,0-1.5-0.67-1.5-1.5s0.67-1.5,1.5-1.5h10c0.83,0,1.5,0.67,1.5,1.5 <path fill="#ED6B21" d="M12.0967369,10.3634434h-2.471261c-0.3256063,0-0.5884438-0.2628374-0.5884438-0.5884428
S98.95,65.5,98.12,65.5z M78.12,65.5h-10c-0.83,0-1.5-0.67-1.5-1.5s0.67-1.5,1.5-1.5h10c0.83,0,1.5,0.67,1.5,1.5 c0-0.3256063,0.2628374-0.5884438,0.5884438-0.5884438h2.471261c0.3256063,0,0.5884438,0.2628374,0.5884438,0.5884438
S78.95,65.5,78.12,65.5z M58.12,65.5h-10c-0.83,0-1.5-0.67-1.5-1.5s0.67-1.5,1.5-1.5h10c0.83,0,1.5,0.67,1.5,1.5 C12.6851807,10.100606,12.4223404,10.3634434,12.0967369,10.3634434z"/>
S58.95,65.5,58.12,65.5z M38.12,65.5h-10c-0.83,0-1.5-0.67-1.5-1.5s0.67-1.5,1.5-1.5h10c0.83,0,1.5,0.67,1.5,1.5 <path fill="#ED6B21" d="M7.5782208,10.3634434h-2.471261c-0.3256059,0-0.5884438-0.2628374-0.5884438-0.5884428
S38.95,65.5,38.12,65.5z M18.12,65.5h-10c-0.83,0-1.5-0.67-1.5-1.5s0.67-1.5,1.5-1.5h10c0.83,0,1.5,0.67,1.5,1.5 c0-0.3256063,0.2628379-0.5884438,0.5884438-0.5884438h2.471261c0.3256059,0,0.5884433,0.2628374,0.5884433,0.5884438
S18.95,65.5,18.12,65.5z"/> C8.1666641,10.100606,7.9038239,10.3634434,7.5782208,10.3634434z"/>
</g> <g>
<g> <path fill="#808080" d="M10.98001,11.9849854c-0.289978,0-0.5199585,0.2299805-0.5199585,0.5199585v0.5922852v0.3327637
<g> c0,0.289978-0.2300415,0.5200195-0.5200195,0.5200195H2.7452075c-0.289978,0-0.5200195-0.2300415-0.5200195-0.5200195V13.097229
<path fill="#808080" d="M108.79,51.6H19.21c-1.93,0-3.5-1.57-3.5-3.5V10.12c0-1.93,1.57-3.5,3.5-3.5h89.57 v-0.5922852c0-0.289978-0.2299803-0.5199585-0.5199584-0.5199585c-0.2900391,0-0.5200195,0.2299805-0.5200195,0.5199585v0.5922852
c1.93,0,3.5,1.57,3.5,3.5V48.1C112.29,50.03,110.71,51.6,108.79,51.6z M19.21,9.62c-0.27,0-0.5,0.23-0.5,0.5V48.1 v0.3327637C1.1852101,14.2999878,1.8952321,15,2.7552173,15h7.1748047c0.8599854,0,1.5700073-0.7000122,1.5700073-1.5700073
c0,0.27,0.23,0.5,0.5,0.5h89.57c0.27,0,0.5-0.23,0.5-0.5V10.12c0-0.27-0.23-0.5-0.5-0.5H19.21z"/> V13.097229v-0.5922852C11.5000296,12.2149658,11.2700491,11.9849854,10.98001,11.9849854z"/>
</g> <path fill="#808080" d="M9.9300222,4.5499878H2.7552173c-0.8599852,0-1.5700072,0.7000122-1.5700072,1.5700073v0.3327637v0.5922852
<g> c0,0.289978,0.2299805,0.5199585,0.5200195,0.5199585c0.289978,0,0.5199584-0.2299805,0.5199584-0.5199585V6.4527588V6.1199951
<path fill="#808080" d="M108.79,121.38H19.21c-1.93,0-3.5-1.57-3.5-3.5V79.4c0-1.93,1.57-3.5,3.5-3.5h89.57 c0-0.289978,0.2300415-0.5200195,0.5200195-0.5200195H9.940032c0.289978,0,0.5200195,0.2300415,0.5200195,0.5200195v0.3327637
c1.93,0,3.5,1.57,3.5,3.5v38.49C112.29,119.81,110.71,121.38,108.79,121.38z M19.21,78.9c-0.27,0-0.5,0.23-0.5,0.5v38.49 v0.5922852c0,0.289978,0.2299805,0.5199585,0.5199585,0.5199585c0.2900391,0,0.5200195-0.2299805,0.5200195-0.5199585V6.4527588
c0,0.27,0.23,0.5,0.5,0.5h89.57c0.27,0,0.5-0.23,0.5-0.5V79.4c0-0.27-0.23-0.5-0.5-0.5H19.21z"/> V6.1199951C11.5000296,5.25,10.7900076,4.5499878,9.9300222,4.5499878z"/>
</g>
</g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,26 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="add_x5F_part"> <path fill="#ED6B21" d="M7.2122064,10.8825388H5.473033c-0.6128426,0-1.1075444-0.4947023-1.1075444-1.1075449
<g> S4.8601904,8.667449,5.473033,8.667449h1.7391734c0.6128426,0,1.1075444,0.4947023,1.1075444,1.1075449
<path fill="#ED6B21" d="M14.62,4.37c-0.01-0.14,0.06-0.34,0.15-0.44l0.13-0.15c0.09-0.11,0.12-0.3,0.07-0.43l-0.2-0.49 S7.8250437,10.8825388,7.2122064,10.8825388z"/>
c-0.05-0.13-0.21-0.24-0.35-0.25l-0.2-0.01c-0.14-0.01-0.33-0.1-0.42-0.21c-0.09-0.1-0.37-0.46-0.38-0.6l-0.01-0.2 <g>
c-0.01-0.14-0.12-0.3-0.25-0.35l-0.49-0.2C12.52,0.97,12.33,1,12.22,1.1l-0.15,0.13c-0.11,0.09-0.31,0.16-0.44,0.15 <path fill="#808080" d="M10.98001,15c-0.289978,0-0.5199585-0.2299805-0.5199585-0.5199585v-0.5922852v-0.3327637
c-0.14-0.01-0.59-0.06-0.69-0.15L10.78,1.1c-0.11-0.09-0.3-0.12-0.43-0.07l-0.49,0.2C9.73,1.28,9.61,1.44,9.6,1.58l-0.01,0.2 c0-0.289978-0.2300415-0.5200195-0.5200195-0.5200195H2.7452075c-0.289978,0-0.5200195,0.2300415-0.5200195,0.5200195v0.3327637
C9.58,1.92,9.49,2.11,9.38,2.2c-0.1,0.09-0.46,0.37-0.6,0.38L8.58,2.6c-0.14,0.01-0.3,0.12-0.35,0.25l-0.2,0.49 v0.5922852C2.225188,14.7700195,1.9952077,15,1.7052296,15c-0.2900391,0-0.5200195-0.2299805-0.5200195-0.5199585v-0.5922852
C7.97,3.48,8,3.67,8.1,3.78l0.13,0.15c0.09,0.11,0.16,0.31,0.15,0.44C8.37,4.52,8.32,4.96,8.23,5.07L8.1,5.22 v-0.3327637c0-0.8699951,0.710022-1.5700073,1.5700072-1.5700073h7.1748047c0.8599854,0,1.5700073,0.7000122,1.5700073,1.5700073
C8,5.33,7.97,5.52,8.03,5.65l0.2,0.49C8.28,6.27,8.44,6.39,8.58,6.4l0.2,0.01c0.14,0.01,0.33,0.1,0.42,0.21 v0.3327637v0.5922852C11.5000296,14.7700195,11.2700491,15,10.98001,15z"/>
c0.09,0.1,0.37,0.46,0.38,0.6l0.01,0.2c0.01,0.14,0.12,0.3,0.25,0.35l0.49,0.2C10.48,8.03,10.67,8,10.78,7.9l0.15-0.13 <path fill="#808080" d="M9.9300222,7.5650024H2.7552173c-0.8599852,0-1.5700072-0.7000122-1.5700072-1.5700073V5.6622314V5.0699463
c0.11-0.09,0.31-0.16,0.44-0.15c0.14,0.01,0.59,0.06,0.69,0.15l0.15,0.13c0.11,0.09,0.3,0.12,0.43,0.07l0.49-0.2 c0-0.289978,0.2299805-0.5199585,0.5200195-0.5199585c0.289978,0,0.5199584,0.2299805,0.5199584,0.5199585v0.5922852v0.3327637
c0.13-0.05,0.24-0.21,0.25-0.35l0.01-0.2c0.01-0.14,0.1-0.33,0.21-0.42s0.46-0.37,0.6-0.38l0.2-0.01c0.14-0.01,0.3-0.12,0.35-0.25 c0,0.289978,0.2300415,0.5200195,0.5200195,0.5200195H9.940032c0.289978,0,0.5200195-0.2300415,0.5200195-0.5200195V5.6622314
l0.2-0.49C15.03,5.52,15,5.33,14.9,5.22l-0.13-0.15C14.68,4.96,14.63,4.51,14.62,4.37z M11.5,6.6c-1.16,0-2.1-0.94-2.1-2.1 V5.0699463c0-0.289978,0.2299805-0.5199585,0.5199585-0.5199585c0.2900391,0,0.5200195,0.2299805,0.5200195,0.5199585v0.5922852
s0.94-2.1,2.1-2.1s2.1,0.94,2.1,2.1S12.66,6.6,11.5,6.6z"/> v0.3327637C11.5000296,6.8649902,10.7900076,7.5650024,9.9300222,7.5650024z"/>
</g>
<path fill="#808080" d="M10.98,9.78c-0.29,0-0.52,0.23-0.52,0.52v2.09v1.04c0,0.29-0.23,0.52-0.52,0.52H2.62
c-0.29,0-0.53-0.24-0.53-0.53L2.04,6.12c0-0.14,0.05-0.27,0.15-0.37c0.1-0.1,0.23-0.15,0.37-0.15l3.19,0v0
c0.29,0,0.52-0.23,0.52-0.52S6.04,4.55,5.75,4.55H3.66c-0.01,0-0.01,0-0.02,0l-1.08,0c-0.42,0-0.81,0.16-1.11,0.46
C1.16,5.31,1,5.71,1,6.13l0.04,7.31C1.05,14.3,1.75,15,2.62,15h7.31c0.86,0,1.57-0.7,1.57-1.57v-1.04V10.3
C11.5,10.01,11.27,9.78,10.98,9.78z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -210,8 +210,9 @@ bool its_write_obj(const indexed_triangle_set &its, const char *file)
bool its_write_obj(const indexed_triangle_set& its, const std::vector<obj_color> &color, const char* file) bool its_write_obj(const indexed_triangle_set& its, const std::vector<obj_color> &color, const char* file)
{ {
Slic3r::CNumericLocalesSetter locales_setter; Slic3r::CNumericLocalesSetter locales_setter;
FILE* fp = fopen(file, "w"); FILE* fp = boost::nowide::fopen(file, "w");
if (fp == nullptr) { if (fp == nullptr) {
BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing";
return false; return false;
} }

View File

@ -17,6 +17,12 @@ imstb_truetype.h modification:
Hot fix for open symbolic fonts on windows Hot fix for open symbolic fonts on windows
62bdfe6f8d04b88e8bd511cd613be80c0baa7f55 62bdfe6f8d04b88e8bd511cd613be80c0baa7f55
Add case STBTT_MS_EID_SYMBOL to swith in file imstb_truetype.h on line 1440.
Hot fix for open curved fonts mainly on MAC Hot fix for open curved fonts mainly on MAC
2148e49f75d82cb19dc6ec409fb7825296ed005c 2148e49f75d82cb19dc6ec409fb7825296ed005c
viz. https://github.com/nothings/stb/issues/1296
In file imstb_truetype.h line 1667 change malloc size from:
vertices = (stbtt_vertex *) STBTT_malloc((m + 1) * sizeof(vertices[0]), info->userdata);
to:
vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);

View File

@ -174,7 +174,6 @@ public:
BoundingBox rotated(double angle, const Point &center) const; BoundingBox rotated(double angle, const Point &center) const;
void rotate(double angle) { (*this) = this->rotated(angle); } void rotate(double angle) { (*this) = this->rotated(angle); }
void rotate(double angle, const Point &center) { (*this) = this->rotated(angle, center); } void rotate(double angle, const Point &center) { (*this) = this->rotated(angle, center); }
bool intersects(const BoundingBox &other) const { return this->min(0) <= other.max(0) && this->max(0) >= other.min(0) && this->min(1) <= other.max(1) && this->max(1) >= other.min(1); }
// Align the min corner to a grid of cell_size x cell_size cells, // Align the min corner to a grid of cell_size x cell_size cells,
// to encompass the original bounding box. // to encompass the original bounding box.
void align_to_grid(const coord_t cell_size); void align_to_grid(const coord_t cell_size);

View File

@ -185,7 +185,6 @@ set(SLIC3R_SOURCES
Model.hpp Model.hpp
ModelArrange.hpp ModelArrange.hpp
ModelArrange.cpp ModelArrange.cpp
#ModelVolumeType.hpp
MultiMaterialSegmentation.cpp MultiMaterialSegmentation.cpp
MultiMaterialSegmentation.hpp MultiMaterialSegmentation.hpp
MeshNormals.hpp MeshNormals.hpp

View File

@ -283,7 +283,7 @@ ExPolygons Emboss::heal_shape(const Polygons &shape) {
// Do not remove all duplicits but do it better way // Do not remove all duplicits but do it better way
// Overlap all duplicit points by rectangle 3x3 // Overlap all duplicit points by rectangle 3x3
Points duplicits = collect_duplications(to_points(polygons)); Points duplicits = collect_duplicates(to_points(polygons));
if (!duplicits.empty()) { if (!duplicits.empty()) {
polygons.reserve(polygons.size() + duplicits.size()); polygons.reserve(polygons.size() + duplicits.size());
for (const Point &p : duplicits) { for (const Point &p : duplicits) {
@ -310,7 +310,7 @@ bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration)
priv::remove_same_neighbor(shape); priv::remove_same_neighbor(shape);
Pointfs intersections = intersection_points(shape); Pointfs intersections = intersection_points(shape);
Points duplicits = collect_duplications(to_points(shape)); Points duplicits = collect_duplicates(to_points(shape));
//Points close = priv::collect_close_points(shape, 1.); //Points close = priv::collect_close_points(shape, 1.);
if (intersections.empty() && duplicits.empty() /* && close.empty() */) break; if (intersections.empty() && duplicits.empty() /* && close.empty() */) break;
@ -353,7 +353,7 @@ bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration)
svg.draw(shape, "green"); svg.draw(shape, "green");
svg.draw(duplicits, "lightgray", 13 / Emboss::SHAPE_SCALE); svg.draw(duplicits, "lightgray", 13 / Emboss::SHAPE_SCALE);
Points duplicits3 = collect_duplications(to_points(shape)); Points duplicits3 = collect_duplicates(to_points(shape));
svg.draw(duplicits3, "black", 7 / Emboss::SHAPE_SCALE); svg.draw(duplicits3, "black", 7 / Emboss::SHAPE_SCALE);
Pointfs pts2 = intersection_points(shape); Pointfs pts2 = intersection_points(shape);
@ -387,7 +387,7 @@ bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration)
} }
assert(intersection_points(shape).empty()); assert(intersection_points(shape).empty());
assert(collect_duplications(to_points(shape)).empty()); assert(collect_duplicates(to_points(shape)).empty());
return true; return true;
} }
@ -1186,7 +1186,7 @@ indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
const IProjection &projection) const IProjection &projection)
{ {
Points points = to_points(shape2d); Points points = to_points(shape2d);
Points duplicits = collect_duplications(points); Points duplicits = collect_duplicates(points);
return (duplicits.empty()) ? return (duplicits.empty()) ?
priv::polygons2model_unique(shape2d, projection, points) : priv::polygons2model_unique(shape2d, projection, points) :
priv::polygons2model_duplicit(shape2d, projection, points, duplicits); priv::polygons2model_duplicit(shape2d, projection, points, duplicits);

View File

@ -148,7 +148,7 @@ static constexpr const char* MESH_STAT_FACETS_RESERVED = "facets_reversed";
static constexpr const char* MESH_STAT_BACKWARDS_EDGES = "backwards_edges"; static constexpr const char* MESH_STAT_BACKWARDS_EDGES = "backwards_edges";
// Store / load of TextConfiguration // Store / load of TextConfiguration
static constexpr const char *TEXT_TAG = "emboss"; static constexpr const char *TEXT_TAG = "slic3rpe:text";
static constexpr const char *TEXT_DATA_ATTR = "text"; static constexpr const char *TEXT_DATA_ATTR = "text";
// TextConfiguration::EmbossStyle // TextConfiguration::EmbossStyle
static constexpr const char *STYLE_NAME_ATTR = "style_name"; static constexpr const char *STYLE_NAME_ATTR = "style_name";
@ -3628,8 +3628,8 @@ std::optional<TextConfiguration> TextConfigurationSerialization::read(const char
float distance = get_attribute_value_float(attributes, num_attributes, DISTANCE_ATTR); float distance = get_attribute_value_float(attributes, num_attributes, DISTANCE_ATTR);
if (std::fabs(distance) > std::numeric_limits<float>::epsilon()) if (std::fabs(distance) > std::numeric_limits<float>::epsilon())
fp.distance = distance; fp.distance = distance;
std::string use_surface = get_attribute_value_string(attributes, num_attributes, USE_SURFACE_ATTR); int use_surface = get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR);
if (!use_surface.empty()) fp.use_surface = true; if (use_surface == 1) fp.use_surface = true;
float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR); float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR);
if (std::fabs(angle) > std::numeric_limits<float>::epsilon()) if (std::fabs(angle) > std::numeric_limits<float>::epsilon())
fp.angle = angle; fp.angle = angle;

View File

@ -2327,7 +2327,7 @@ void GCode::process_layer_single_object(
interface_extruder = dontcare_extruder; interface_extruder = dontcare_extruder;
} }
bool extrude_support = has_support && support_extruder == extruder_id; bool extrude_support = has_support && support_extruder == extruder_id;
bool extrude_interface = interface_extruder && interface_extruder == extruder_id; bool extrude_interface = has_interface && interface_extruder == extruder_id;
if (extrude_support || extrude_interface) { if (extrude_support || extrude_interface) {
init_layer_delayed(); init_layer_delayed();
m_layer = layer_to_print.support_layer; m_layer = layer_to_print.support_layer;

View File

@ -133,7 +133,7 @@ Slic3r::Pointfs compute_intersections(const Slic3r::Lines &lines)
Point max_(std::max(a_.x(), b_.x()), std::max(a_.y(), b_.y())); Point max_(std::max(a_.x(), b_.x()), std::max(a_.y(), b_.y()));
BoundingBox bb_(min_, max_); BoundingBox bb_(min_, max_);
// intersect of BB compare min max // intersect of BB compare min max
if (bb.intersects(bb_) && if (bb.overlap(bb_) &&
l.intersection(l_, &i)) l.intersection(l_, &i))
pts.push_back(i.cast<double>()); pts.push_back(i.cast<double>());
} }

View File

@ -317,15 +317,18 @@ void Layer::build_up_down_graph(Layer& below, Layer& above)
coord_t* end = srcs + 4; coord_t* end = srcs + 4;
std::sort(begin, end); std::sort(begin, end);
end = std::unique(begin, end); end = std::unique(begin, end);
assert(begin + 2 == end); if (begin + 1 == end) {
if (begin + 1 == end) // Self intersection may happen on source contour. Just copy the Z value.
pt.z() = *begin; pt.z() = *begin;
else if (begin + 2 <= end) { } else {
assert(begin + 2 == end);
if (begin + 2 <= end) {
// store a -1 based negative index into the "intersections" vector here. // store a -1 based negative index into the "intersections" vector here.
m_intersections.emplace_back(srcs[0], srcs[1]); m_intersections.emplace_back(srcs[0], srcs[1]);
pt.z() = -coord_t(m_intersections.size()); pt.z() = -coord_t(m_intersections.size());
} }
} }
}
const std::vector<std::pair<coord_t, coord_t>>& intersections() const { return m_intersections; } const std::vector<std::pair<coord_t, coord_t>>& intersections() const { return m_intersections; }
private: private:

View File

@ -14,7 +14,6 @@
#include "Arrange.hpp" #include "Arrange.hpp"
#include "CustomGCode.hpp" #include "CustomGCode.hpp"
#include "enum_bitmask.hpp" #include "enum_bitmask.hpp"
//#include "ModelVolumeType.hpp"
#include "TextConfiguration.hpp" #include "TextConfiguration.hpp"
#include <map> #include <map>

View File

@ -1,16 +0,0 @@
#ifndef slic3r_ModelVolumeType_hpp_
#define slic3r_ModelVolumeType_hpp_
namespace Slic3r {
enum class ModelVolumeType : int {
INVALID = -1,
MODEL_PART = 0,
NEGATIVE_VOLUME,
PARAMETER_MODIFIER,
SUPPORT_BLOCKER,
SUPPORT_ENFORCER,
};
} // namespace Slic3r
#endif /* slic3r_ModelVolumeType_hpp_ */

View File

@ -3,6 +3,8 @@
using namespace Slic3r; using namespace Slic3r;
// inspired by nanosvgrast.h function nsvgRasterize -> nsvg__flattenShape -> nsvg__flattenCubicBez
// https://github.com/memononen/nanosvg/blob/f0a3e1034dd22e2e87e5db22401e44998383124e/src/nanosvgrast.h#L335
void NSVGUtils::flatten_cubic_bez(Polygon &polygon, void NSVGUtils::flatten_cubic_bez(Polygon &polygon,
float tessTol, float tessTol,
Vec2f p1, Vec2f p1,

View File

@ -397,22 +397,37 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path &subject, con
ClipperLib_Z::Clipper clipper; ClipperLib_Z::Clipper clipper;
clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot, clipper.ZFillFunction([](const ClipperLib_Z::IntPoint &e1bot, const ClipperLib_Z::IntPoint &e1top, const ClipperLib_Z::IntPoint &e2bot,
const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) { const ClipperLib_Z::IntPoint &e2top, ClipperLib_Z::IntPoint &pt) {
// The clipping contour may be simplified by clipping it with a bounding box of "subject" path.
// The clipping function used may produce self intersections outside of the "subject" bounding box. Such self intersections are
// harmless to the result of the clipping operation,
// Both ends of each edge belong to the same source: Either they are from subject or from clipping path.
assert(e1bot.z() >= 0 && e1top.z() >= 0);
assert(e2bot.z() >= 0 && e2top.z() >= 0);
assert((e1bot.z() == 0) == (e1top.z() == 0));
assert((e2bot.z() == 0) == (e2top.z() == 0));
// Start & end points of the clipped polyline (extrusion path with a non-zero width).
ClipperLib_Z::IntPoint start = e1bot; ClipperLib_Z::IntPoint start = e1bot;
ClipperLib_Z::IntPoint end = e1top; ClipperLib_Z::IntPoint end = e1top;
if (start.z() <= 0 && end.z() <= 0) { if (start.z() <= 0 && end.z() <= 0) {
start = e2bot; start = e2bot;
end = e2top; end = e2top;
} }
if (start.z() <= 0 && end.z() <= 0) {
// Self intersection on the source contour.
assert(start.z() == 0 && end.z() == 0);
pt.z() = 0;
} else {
// Interpolate extrusion line width.
assert(start.z() > 0 && end.z() > 0); assert(start.z() > 0 && end.z() > 0);
// Interpolate extrusion line width.
double length_sqr = (end - start).cast<double>().squaredNorm(); double length_sqr = (end - start).cast<double>().squaredNorm();
double dist_sqr = (pt - start).cast<double>().squaredNorm(); double dist_sqr = (pt - start).cast<double>().squaredNorm();
double t = std::sqrt(dist_sqr / length_sqr); double t = std::sqrt(dist_sqr / length_sqr);
pt.z() = start.z() + coord_t((end.z() - start.z()) * t); pt.z() = start.z() + coord_t((end.z() - start.z()) * t);
}
}); });
clipper.AddPath(subject, ClipperLib_Z::ptSubject, false); clipper.AddPath(subject, ClipperLib_Z::ptSubject, false);

View File

@ -66,9 +66,9 @@ bool has_duplicate_points(std::vector<Point> &&pts)
return false; return false;
} }
Points collect_duplications(Points pts /* Copy */) Points collect_duplicates(Points pts /* Copy */)
{ {
std::stable_sort(pts.begin(), pts.end()); std::sort(pts.begin(), pts.end());
Points duplicits; Points duplicits;
const Point *prev = &pts.front(); const Point *prev = &pts.front();
for (size_t i = 1; i < pts.size(); ++i) { for (size_t i = 1; i < pts.size(); ++i) {

View File

@ -268,7 +268,7 @@ inline bool has_duplicate_successive_points_closed(const std::vector<Point> &pts
} }
// Collect adjecent(duplicit points) // Collect adjecent(duplicit points)
Points collect_duplications(Points pts /* Copy */); Points collect_duplicates(Points pts /* Copy */);
inline bool shorter_then(const Point& p0, const coord_t len) inline bool shorter_then(const Point& p0, const coord_t len)
{ {

View File

@ -977,8 +977,10 @@ indexed_triangle_set its_make_cone(double r, double h, double fa)
vertices.emplace_back(Vec3f(0., 0., h)); vertices.emplace_back(Vec3f(0., 0., h));
size_t i = 0; size_t i = 0;
const auto vec = Eigen::Vector2f(0, float(r));
for (double angle=0; angle<2*PI; angle+=fa) { 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.) { if (angle > 0.) {
facets.emplace_back(0, i+2, i+1); facets.emplace_back(0, i+2, i+1);
facets.emplace_back(1, i+1, i+2); facets.emplace_back(1, i+1, i+2);
@ -1013,58 +1015,121 @@ indexed_triangle_set its_make_pyramid(float base, float height)
// Generates mesh for a sphere centered about the origin, using the generated angle // Generates mesh for a sphere centered about the origin, using the generated angle
// to determine the granularity. // to determine the granularity.
// Default angle is 1 degree. // Default angle is 1 degree.
//FIXME better to discretize an Icosahedron recursively http://www.songho.ca/opengl/gl_sphere.html
indexed_triangle_set its_make_sphere(double radius, double fa) indexed_triangle_set its_make_sphere(double radius, double fa)
{ {
int sectorCount = int(ceil(2. * M_PI / fa)); // First build an icosahedron (taken from http://www.songho.ca/opengl/gl_sphere.html)
int stackCount = int(ceil(M_PI / fa));
float sectorStep = float(2. * M_PI / sectorCount);
float stackStep = float(M_PI / stackCount);
indexed_triangle_set mesh; indexed_triangle_set mesh;
const float PI = 3.1415926f;
const float H_ANGLE = PI / 180 * 72; // 72 degree = 360 / 5
const float V_ANGLE = atanf(1.0f / 2); // elevation = 26.565 degree
auto& vertices = mesh.vertices; auto& vertices = mesh.vertices;
vertices.reserve((stackCount - 1) * sectorCount + 2); auto& indices = mesh.indices;
for (int i = 0; i <= stackCount; ++ i) { vertices.resize(12);
// from pi/2 to -pi/2 indices.reserve(20);
double stackAngle = 0.5 * M_PI - stackStep * i;
double xy = radius * cos(stackAngle); float z, xy;
double z = radius * sin(stackAngle); float hAngle1 = -PI / 2 - H_ANGLE / 2;
if (i == 0 || i == stackCount)
vertices.emplace_back(Vec3f(float(xy), 0.f, float(z))); vertices[0] = stl_vertex(0, 0, radius); // the first top vertex at (0, 0, r)
else
for (int j = 0; j < sectorCount; ++ j) { for (int i = 1; i <= 5; ++i) {
// from 0 to 2pi z = radius * sinf(V_ANGLE);
double sectorAngle = sectorStep * j; xy = radius * cosf(V_ANGLE);
vertices.emplace_back(Vec3d(xy * std::cos(sectorAngle), xy * std::sin(sectorAngle), z).cast<float>()); vertices[i] = stl_vertex(xy * cosf(hAngle1), xy * sinf(hAngle1), z);
vertices[i+5] = stl_vertex(xy * cosf(hAngle1 + H_ANGLE / 2), xy * sinf(hAngle1 + H_ANGLE / 2), -z);
hAngle1 += H_ANGLE;
indices.emplace_back(stl_triangle_vertex_indices(i, i < 5 ? i+1 : 1, 0));
indices.emplace_back(stl_triangle_vertex_indices(i, i+5, i < 5 ? i+1 : 1));
indices.emplace_back(stl_triangle_vertex_indices(i+5, i+6 < 11 ? i+6 : 6, i+6 < 11 ? i+1 : 1));
indices.emplace_back(stl_triangle_vertex_indices(i+5, 11, i+6 < 11 ? i+6 : 6));
}
vertices[11] = stl_vertex(0, 0, -radius); // the last bottom vertex at (0, 0, -r)
// We have a beautiful icosahedron. Now subdivide the triangles.
std::vector<Vec3i> neighbors = its_face_neighbors(mesh); // This is cheap, the mesh is small.
const double side_len_limit = radius * fa;
const double side_len = (vertices[1] - vertices[0]).norm();
const int iterations = std::ceil(std::log2(side_len / side_len_limit));
indices.reserve(indices.size() * std::pow(4, iterations));
vertices.reserve(vertices.size() * std::pow(2, iterations));
struct DividedEdge {
int neighbor = -1;
int middle_vertex_idx;
std::pair<int, int> children_idxs;
};
for (int iter=0; iter<iterations; ++iter) {
std::vector<std::array<DividedEdge, 3>> divided_triangles(indices.size());
std::vector<Vec3i> new_neighbors(4*indices.size());
size_t orig_indices_size = indices.size();
for (int i=0; i<orig_indices_size; ++i) { // iterate over all old triangles
// We are going to split this triangle. Let's foresee what will be the indices
// of the new internal triangles along individual edges.
int last_triangle_idx = indices.size()-1;
std::array<std::pair<int, int>, 3> edge_children = { std::make_pair(i,last_triangle_idx + 2),
std::make_pair(last_triangle_idx + 2,last_triangle_idx + 3),
std::make_pair(last_triangle_idx + 3,i) };
std::array<int, 3> middle_vertices_idxs;
std::array<std::pair<int, int>, 3> new_neighbors_per_edge;
for (int n=0; n<3; ++n) { // for all three edges
const int edge_neighbor = neighbors[i][n];
if (divided_triangles[edge_neighbor][0].neighbor == -1) {
// This n-th edge is not yet divided. Divide it now.
vertices.emplace_back(0.5 * (vertices[indices[i][n]] + vertices[indices[i][n == 2 ? 0 : n+1]]));
vertices.back() *= radius / vertices.back().norm();
middle_vertices_idxs[n] = vertices.size()-1;
// Save information about what we did.
int j = -1;
while (divided_triangles[i][++j].neighbor != -1);
divided_triangles[i][j] = { edge_neighbor, int(vertices.size()-1), edge_children[n] };
new_neighbors_per_edge[n] = std::make_pair(-1,-1);
} else {
// This edge is already divided. Get the index of the middle point.
int j = -1;
while (divided_triangles[edge_neighbor][++j].neighbor != i);
middle_vertices_idxs[n] = divided_triangles[edge_neighbor][j].middle_vertex_idx;
new_neighbors_per_edge[n] = divided_triangles[edge_neighbor][j].children_idxs;
std::swap(new_neighbors_per_edge[n].first, new_neighbors_per_edge[n].second);
// We have saved the middle-point. We are looking for edges leading to/from it.
int idx = -1; while (indices[new_neighbors_per_edge[n].first][++idx] != middle_vertices_idxs[n]);
new_neighbors[new_neighbors_per_edge[n].first][idx] = edge_children[n].first;
new_neighbors[new_neighbors_per_edge[n].second][idx] = edge_children[n].second;
} }
} }
auto& facets = mesh.indices; // Add three new triangles, reindex the old one.
facets.reserve(2 * (stackCount - 1) * sectorCount); const int last_index = indices.size() - 1;
for (int i = 0; i < stackCount; ++ i) { indices.emplace_back(stl_triangle_vertex_indices(middle_vertices_idxs[0], middle_vertices_idxs[1], middle_vertices_idxs[2]));
// Beginning of current stack. new_neighbors[indices.size()-1] = Vec3i(last_index+2, last_index+3, i);
int k1 = (i == 0) ? 0 : (1 + (i - 1) * sectorCount);
int k1_first = k1;
// Beginning of next stack.
int k2 = (i == 0) ? 1 : (k1 + sectorCount);
int k2_first = k2;
for (int j = 0; j < sectorCount; ++ j) {
// 2 triangles per sector excluding first and last stacks
int k1_next = k1;
int k2_next = k2;
if (i != 0) {
k1_next = (j + 1 == sectorCount) ? k1_first : (k1 + 1);
facets.emplace_back(k1, k2, k1_next);
}
if (i + 1 != stackCount) {
k2_next = (j + 1 == sectorCount) ? k2_first : (k2 + 1);
facets.emplace_back(k1_next, k2, k2_next);
}
k1 = k1_next;
k2 = k2_next;
}
}
indices.emplace_back(stl_triangle_vertex_indices(middle_vertices_idxs[0], indices[i][1], middle_vertices_idxs[1]));
new_neighbors[indices.size()-1] = Vec3i(new_neighbors_per_edge[0].second, new_neighbors_per_edge[1].first, last_index+1);
indices.emplace_back(stl_triangle_vertex_indices(middle_vertices_idxs[2], middle_vertices_idxs[1], indices[i][2]));
new_neighbors[indices.size()-1] = Vec3i(last_index+1, new_neighbors_per_edge[1].second, new_neighbors_per_edge[2].first);
indices[i][1] = middle_vertices_idxs[0];
indices[i][2] = middle_vertices_idxs[2];
new_neighbors[i] = Vec3i(new_neighbors_per_edge[0].first, last_index+1, new_neighbors_per_edge[2].second);
}
neighbors = std::move(new_neighbors);
}
return mesh; return mesh;
} }

View File

@ -241,7 +241,7 @@ Triangulation::Indices Triangulation::triangulate(const ExPolygon &expolygon){
Triangulation::Indices Triangulation::triangulate(const ExPolygons &expolygons){ Triangulation::Indices Triangulation::triangulate(const ExPolygons &expolygons){
Points pts = to_points(expolygons); Points pts = to_points(expolygons);
Points d_pts = collect_duplications(pts); Points d_pts = collect_duplicates(pts);
if (d_pts.empty()) return triangulate(expolygons, pts); if (d_pts.empty()) return triangulate(expolygons, pts);
Changes changes = create_changes(pts, d_pts); Changes changes = create_changes(pts, d_pts);
@ -262,7 +262,7 @@ Triangulation::Indices Triangulation::triangulate(const ExPolygons &expolygons,
{ {
assert(count_points(expolygons) == points.size()); assert(count_points(expolygons) == points.size());
// when contain duplicit coordinate in points will not work properly // when contain duplicit coordinate in points will not work properly
assert(collect_duplications(points).empty()); assert(collect_duplicates(points).empty());
HalfEdges edges; HalfEdges edges;
edges.reserve(points.size()); edges.reserve(points.size());

View File

@ -113,7 +113,6 @@ inline void append(std::vector<T>& dest, const std::vector<T>& src)
dest = src; // copy dest = src; // copy
else else
dest.insert(dest.end(), src.begin(), src.end()); dest.insert(dest.end(), src.begin(), src.end());
// NOTE: insert reserve space when needed
} }
template <typename T> template <typename T>

View File

@ -956,7 +956,8 @@ std::string xml_escape(std::string text, bool is_marked/* = false*/)
} }
// Definition of escape symbols https://www.w3.org/TR/REC-xml/#AVNormalize // Definition of escape symbols https://www.w3.org/TR/REC-xml/#AVNormalize
// During the read of xml attribute normalization of white spaces is applied
// Soo for not lose white space character it is escaped before store
std::string xml_escape_double_quotes_attribute_value(std::string text) std::string xml_escape_double_quotes_attribute_value(std::string text)
{ {
std::string::size_type pos = 0; std::string::size_type pos = 0;

View File

@ -448,11 +448,15 @@ int GLVolumeCollection::load_object_volume(
this->volumes.emplace_back(new GLVolume()); this->volumes.emplace_back(new GLVolume());
GLVolume& v = *this->volumes.back(); GLVolume& v = *this->volumes.back();
v.set_color(color_from_model_volume(*model_volume)); v.set_color(color_from_model_volume(*model_volume));
// apply printable value from the instance
v.printable = instance->printable;
#if ENABLE_SMOOTH_NORMALS #if ENABLE_SMOOTH_NORMALS
v.model.init_from(*mesh, true); v.model.init_from(*mesh, true);
if (m_use_raycasters)
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh); v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
#else #else
v.model.init_from(*mesh); v.model.init_from(*mesh);
if (m_use_raycasters)
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh); v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
#endif // ENABLE_SMOOTH_NORMALS #endif // ENABLE_SMOOTH_NORMALS
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);

View File

@ -397,6 +397,7 @@ private:
Slope m_slope; Slope m_slope;
bool m_show_sinking_contours{ false }; bool m_show_sinking_contours{ false };
bool m_show_non_manifold_edges{ true }; bool m_show_non_manifold_edges{ true };
bool m_use_raycasters{ true };
public: public:
GLVolumePtrs volumes; GLVolumePtrs volumes;
@ -445,6 +446,7 @@ public:
bool empty() const { return volumes.empty(); } 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_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_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; } void set_z_range(float min_z, float max_z) { m_z_range[0] = min_z; m_z_range[1] = max_z; }

View File

@ -1386,6 +1386,45 @@ void PageFirmware::apply_custom_config(DynamicPrintConfig &config)
} }
} }
static void focus_event(wxFocusEvent& e, wxTextCtrl* ctrl, double def_value)
{
e.Skip();
wxString str = ctrl->GetValue();
const char dec_sep = is_decimal_separator_point() ? '.' : ',';
const char dec_sep_alt = dec_sep == '.' ? ',' : '.';
// Replace the first incorrect separator in decimal number.
bool was_replaced = str.Replace(dec_sep_alt, dec_sep, false) != 0;
double val = 0.0;
if (!str.ToDouble(&val)) {
if (val == 0.0)
val = def_value;
ctrl->SetValue(double_to_string(val));
show_error(nullptr, _L("Invalid numeric input."));
// On Windows, this SetFocus creates an invisible marker.
//ctrl->SetFocus();
}
else if (was_replaced)
ctrl->SetValue(double_to_string(val));
}
class DiamTextCtrl : public wxTextCtrl
{
public:
DiamTextCtrl(wxWindow* parent)
{
#ifdef _WIN32
long style = wxBORDER_SIMPLE;
#else
long style = 0;
#endif
Create(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(Field::def_width_thinner() * wxGetApp().em_unit(), wxDefaultCoord), style);
wxGetApp().UpdateDarkUI(this);
}
~DiamTextCtrl() {}
};
PageBedShape::PageBedShape(ConfigWizard *parent) PageBedShape::PageBedShape(ConfigWizard *parent)
: ConfigWizardPage(parent, _L("Bed Shape and Size"), _L("Bed Shape"), 1) : ConfigWizardPage(parent, _L("Bed Shape and Size"), _L("Bed Shape"), 1)
, shape_panel(new BedShapePanel(this)) , shape_panel(new BedShapePanel(this))
@ -1409,10 +1448,20 @@ void PageBedShape::apply_custom_config(DynamicPrintConfig &config)
config.set_key_value("bed_custom_model", new ConfigOptionString(custom_model)); config.set_key_value("bed_custom_model", new ConfigOptionString(custom_model));
} }
static void focus_event(wxFocusEvent& e, wxTextCtrl* ctrl, double def_value) PageBuildVolume::PageBuildVolume(ConfigWizard* parent)
: ConfigWizardPage(parent, _L("Build Volume"), _L("Build Volume"), 1)
, build_volume(new DiamTextCtrl(this))
{ {
append_text(_L("Set verctical size of your printer."));
wxString value = "200";
build_volume->SetValue(value);
build_volume->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent& e) {
double def_value = 200.0;
double max_value = 1200.0;
e.Skip(); e.Skip();
wxString str = ctrl->GetValue(); wxString str = build_volume->GetValue();
const char dec_sep = is_decimal_separator_point() ? '.' : ','; const char dec_sep = is_decimal_separator_point() ? '.' : ',';
const char dec_sep_alt = dec_sep == '.' ? ',' : '.'; const char dec_sep_alt = dec_sep == '.' ? ',' : '.';
@ -1421,31 +1470,41 @@ static void focus_event(wxFocusEvent& e, wxTextCtrl* ctrl, double def_value)
double val = 0.0; double val = 0.0;
if (!str.ToDouble(&val)) { if (!str.ToDouble(&val)) {
if (val == 0.0)
val = def_value; val = def_value;
ctrl->SetValue(double_to_string(val)); build_volume->SetValue(double_to_string(val));
show_error(nullptr, _L("Invalid numeric input.")); show_error(nullptr, _L("Invalid numeric input."));
ctrl->SetFocus(); //build_volume->SetFocus();
} } else if (val < 0.0) {
else if (was_replaced) val = def_value;
ctrl->SetValue(double_to_string(val)); build_volume->SetValue(double_to_string(val));
show_error(nullptr, _L("Invalid numeric input."));
//build_volume->SetFocus();
} else if (val > max_value) {
val = max_value;
build_volume->SetValue(double_to_string(val));
show_error(nullptr, _L("Invalid numeric input."));
//build_volume->SetFocus();
} else if (was_replaced)
build_volume->SetValue(double_to_string(val));
}, build_volume->GetId());
auto* sizer_volume = new wxFlexGridSizer(3, 5, 5);
auto* text_volume = new wxStaticText(this, wxID_ANY, _L("Max print height:"));
auto* unit_volume = new wxStaticText(this, wxID_ANY, _L("mm"));
sizer_volume->AddGrowableCol(0, 1);
sizer_volume->Add(text_volume, 0, wxALIGN_CENTRE_VERTICAL);
sizer_volume->Add(build_volume);
sizer_volume->Add(unit_volume, 0, wxALIGN_CENTRE_VERTICAL);
append(sizer_volume);
} }
class DiamTextCtrl : public wxTextCtrl void PageBuildVolume::apply_custom_config(DynamicPrintConfig& config)
{ {
public: double val = 0.0;
DiamTextCtrl(wxWindow* parent) build_volume->GetValue().ToDouble(&val);
{ auto* opt_volume = new ConfigOptionFloat(val);
#ifdef _WIN32 config.set_key_value("max_print_height", opt_volume);
long style = wxBORDER_SIMPLE; }
#else
long style = 0;
#endif
Create(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(Field::def_width_thinner() * wxGetApp().em_unit(), wxDefaultCoord), style);
wxGetApp().UpdateDarkUI(this);
}
~DiamTextCtrl() {}
};
PageDiameters::PageDiameters(ConfigWizard *parent) PageDiameters::PageDiameters(ConfigWizard *parent)
: ConfigWizardPage(parent, _L("Filament and Nozzle Diameters"), _L("Print Diameters"), 1) : ConfigWizardPage(parent, _L("Filament and Nozzle Diameters"), _L("Print Diameters"), 1)
@ -1915,6 +1974,7 @@ void ConfigWizard::priv::load_pages()
if (page_custom->custom_wanted()) { if (page_custom->custom_wanted()) {
index->add_page(page_firmware); index->add_page(page_firmware);
index->add_page(page_bed); index->add_page(page_bed);
index->add_page(page_bvolume);
index->add_page(page_diams); index->add_page(page_diams);
index->add_page(page_temps); index->add_page(page_temps);
} }
@ -2773,6 +2833,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
page_firmware->apply_custom_config(*custom_config); page_firmware->apply_custom_config(*custom_config);
page_bed->apply_custom_config(*custom_config); page_bed->apply_custom_config(*custom_config);
page_bvolume->apply_custom_config(*custom_config);
page_diams->apply_custom_config(*custom_config); page_diams->apply_custom_config(*custom_config);
page_temps->apply_custom_config(*custom_config); page_temps->apply_custom_config(*custom_config);
@ -2923,6 +2984,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
p->add_page(p->page_mode = new PageMode(this)); p->add_page(p->page_mode = new PageMode(this));
p->add_page(p->page_firmware = new PageFirmware(this)); p->add_page(p->page_firmware = new PageFirmware(this));
p->add_page(p->page_bed = new PageBedShape(this)); p->add_page(p->page_bed = new PageBedShape(this));
p->add_page(p->page_bvolume = new PageBuildVolume(this));
p->add_page(p->page_diams = new PageDiameters(this)); p->add_page(p->page_diams = new PageDiameters(this));
p->add_page(p->page_temps = new PageTemperatures(this)); p->add_page(p->page_temps = new PageTemperatures(this));

View File

@ -450,6 +450,14 @@ struct PageBedShape: ConfigWizardPage
virtual void apply_custom_config(DynamicPrintConfig &config); virtual void apply_custom_config(DynamicPrintConfig &config);
}; };
struct PageBuildVolume : ConfigWizardPage
{
wxTextCtrl* build_volume;
PageBuildVolume(ConfigWizard* parent);
virtual void apply_custom_config(DynamicPrintConfig& config);
};
struct PageDiameters: ConfigWizardPage struct PageDiameters: ConfigWizardPage
{ {
wxTextCtrl *diam_nozzle; wxTextCtrl *diam_nozzle;
@ -584,6 +592,7 @@ struct ConfigWizard::priv
PageBedShape *page_bed = nullptr; PageBedShape *page_bed = nullptr;
PageDiameters *page_diams = nullptr; PageDiameters *page_diams = nullptr;
PageTemperatures *page_temps = nullptr; PageTemperatures *page_temps = nullptr;
PageBuildVolume* page_bvolume = nullptr;
// Pointers to all pages (regardless or whether currently part of the ConfigWizardIndex) // Pointers to all pages (regardless or whether currently part of the ConfigWizardIndex)
std::vector<ConfigWizardPage*> all_pages; std::vector<ConfigWizardPage*> all_pages;

View File

@ -643,7 +643,7 @@ const ColorRGBA GCodeViewer::Neutral_Color = ColorRGBA::DARK_GRAY();
GCodeViewer::GCodeViewer() GCodeViewer::GCodeViewer()
{ {
m_extrusions.reset_role_visibility_flags(); m_extrusions.reset_role_visibility_flags();
m_shells.volumes.set_use_raycasters(false);
// m_sequential_view.skip_invisible_moves = true; // m_sequential_view.skip_invisible_moves = true;
} }

View File

@ -81,6 +81,11 @@ static const Slic3r::ColorRGBA ERROR_BG_LIGHT_COLOR = { 0.753f, 0.192f, 0.039f
// Number of floats // Number of floats
static constexpr const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB static constexpr const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB
#define SHOW_IMGUI_DEMO_WINDOW
#ifdef SHOW_IMGUI_DEMO_WINDOW
static bool show_imgui_demo_window = false;
#endif // SHOW_IMGUI_DEMO_WINDOW
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -1499,6 +1504,10 @@ void GLCanvas3D::render()
#endif // ENABLE_RAYCAST_PICKING_DEBUG #endif // ENABLE_RAYCAST_PICKING_DEBUG
} }
#ifdef SHOW_IMGUI_DEMO_WINDOW
if (show_imgui_demo_window) ImGui::ShowDemoWindow();
#endif // SHOW_IMGUI_DEMO_WINDOW
const bool is_looking_downward = camera.is_looking_downward(); const bool is_looking_downward = camera.is_looking_downward();
// draw scene // draw scene
@ -2379,10 +2388,11 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
if (!m_initialized) if (!m_initialized)
return; return;
// see include/wx/defs.h enum wxKeyCode #ifdef SHOW_IMGUI_DEMO_WINDOW
int keyCode = evt.GetKeyCode(); static int cur = 0;
int ctrlMask = wxMOD_CONTROL; if (wxString("demo")[cur] == evt.GetUnicodeKey()) ++cur; else cur = 0;
int shiftMask = wxMOD_SHIFT; if (cur == 4) { show_imgui_demo_window = !show_imgui_demo_window; cur = 0;}
#endif // SHOW_IMGUI_DEMO_WINDOW
auto imgui = wxGetApp().imgui(); auto imgui = wxGetApp().imgui();
if (imgui->update_key_data(evt)) { if (imgui->update_key_data(evt)) {
@ -2390,6 +2400,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
return; return;
} }
// see include/wx/defs.h enum wxKeyCode
int keyCode = evt.GetKeyCode();
int ctrlMask = wxMOD_CONTROL;
int shiftMask = wxMOD_SHIFT;
if (keyCode == WXK_ESCAPE && (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item() || _deactivate_arrange_menu())) if (keyCode == WXK_ESCAPE && (_deactivate_undo_redo_toolbar_items() || _deactivate_search_toolbar_item() || _deactivate_arrange_menu()))
return; return;
@ -3447,22 +3461,29 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
evt.Skip(); evt.Skip();
// Detection of doubleclick on text to open emboss edit window // Detection of doubleclick on text to open emboss edit window
if (evt.LeftDClick() && m_gizmos.get_current() == nullptr && !m_hover_volume_idxs.empty()) { auto type = m_gizmos.get_current_type();
if (evt.LeftDClick() && !m_hover_volume_idxs.empty() &&
(type == GLGizmosManager::EType::Undefined ||
type == GLGizmosManager::EType::Move ||
type == GLGizmosManager::EType::Rotate ||
type == GLGizmosManager::EType::Scale ||
type == GLGizmosManager::EType::Emboss) ) {
for (int hover_volume_id : m_hover_volume_idxs) { for (int hover_volume_id : m_hover_volume_idxs) {
const GLVolume &hover_gl_volume = *m_volumes.volumes[hover_volume_id]; const GLVolume &hover_gl_volume = *m_volumes.volumes[hover_volume_id];
const ModelObject* hover_object = m_model->objects[hover_gl_volume.object_idx()]; int object_idx = hover_gl_volume.object_idx();
if (object_idx < 0 || object_idx >= m_model->objects.size()) continue;
const ModelObject* hover_object = m_model->objects[object_idx];
int hover_volume_idx = hover_gl_volume.volume_idx(); int hover_volume_idx = hover_gl_volume.volume_idx();
if (hover_volume_idx < 0 || hover_volume_idx >= hover_object->volumes.size()) continue;
const ModelVolume* hover_volume = hover_object->volumes[hover_volume_idx]; const ModelVolume* hover_volume = hover_object->volumes[hover_volume_idx];
if (hover_volume->text_configuration.has_value()) { if (!hover_volume->text_configuration.has_value()) continue;
//m_selection.set_mode(Selection::EMode::Volume);
//m_selection.add(hover_volume_id); // add whole instance
m_selection.add_volumes(Selection::EMode::Volume, {(unsigned) hover_volume_id}); m_selection.add_volumes(Selection::EMode::Volume, {(unsigned) hover_volume_id});
if (type != GLGizmosManager::EType::Emboss)
m_gizmos.open_gizmo(GLGizmosManager::EType::Emboss); m_gizmos.open_gizmo(GLGizmosManager::EType::Emboss);
wxGetApp().obj_list()->update_selections(); wxGetApp().obj_list()->update_selections();
return; return;
} }
} }
}
if (m_moving) if (m_moving)
show_sinking_contours(); show_sinking_contours();

View File

@ -970,16 +970,19 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu)
wxString name = _L("Edit text"); wxString name = _L("Edit text");
auto can_edit_text = []() { auto can_edit_text = []() {
const auto& sel = plater()->get_selection(); if (plater() != nullptr) {
if (sel.volumes_count() != 1) return false; const Selection& sel = plater()->get_selection();
auto cid = sel.get_volume(*sel.get_volume_idxs().begin()); if (sel.volumes_count() == 1) {
const ModelVolume* vol = plater()->canvas3D()->get_model() const GLVolume* gl_vol = sel.get_first_volume();
->objects[cid->object_idx()]->volumes[cid->volume_idx()]; const ModelVolume* vol = plater()->model().objects[gl_vol->object_idx()]->volumes[gl_vol->volume_idx()];
return vol->text_configuration.has_value(); return vol->text_configuration.has_value();
}
}
return false;
}; };
if (menu == &m_object_menu) { if (menu != &m_text_part_menu) {
auto menu_item_id = menu->FindItem(name); const int menu_item_id = menu->FindItem(name);
if (menu_item_id != wxNOT_FOUND) if (menu_item_id != wxNOT_FOUND)
menu->Destroy(menu_item_id); menu->Destroy(menu_item_id);
if (!can_edit_text()) if (!can_edit_text())

View File

@ -30,6 +30,7 @@ static const ColorRGBA SELECTED_PLAG_COLOR = ColorRGBA::GRAY();
static const ColorRGBA SELECTED_DOWEL_COLOR = ColorRGBA::DARK_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_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 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 AngleResolution = 64;
const unsigned int ScaleStepsCount = 72; const unsigned int ScaleStepsCount = 72;
@ -359,10 +360,19 @@ void GLGizmoCut3D::put_connectors_on_cut_plane(const Vec3d& cp_normal, double cp
} }
} }
// returns true if the camera (forward) is pointing in the negative direction of the cut normal
bool GLGizmoCut3D::is_looking_forward() const
{
const Camera& camera = wxGetApp().plater()->get_camera();
const double dot = camera.get_dir_forward().dot(m_cut_normal);
return dot < 0.05;
}
void GLGizmoCut3D::update_clipper() void GLGizmoCut3D::update_clipper()
{ {
BoundingBoxf3 box = bounding_box(); BoundingBoxf3 box = bounding_box();
// update cut_normal
Vec3d beg, end = beg = m_plane_center; Vec3d beg, end = beg = m_plane_center;
beg[Z] = box.center().z() - m_radius; beg[Z] = box.center().z() - m_radius;
end[Z] = box.center().z() + m_radius; end[Z] = box.center().z() + m_radius;
@ -370,12 +380,26 @@ void GLGizmoCut3D::update_clipper()
rotate_vec3d_around_plane_center(beg); rotate_vec3d_around_plane_center(beg);
rotate_vec3d_around_plane_center(end); rotate_vec3d_around_plane_center(end);
double dist = (m_plane_center - beg).norm(); // calculate normal for cut plane
Vec3d normal = m_cut_normal = end - beg;
m_cut_normal.normalize();
// calculate normal and offset for clipping plane if (!is_looking_forward()) {
Vec3d normal = end - beg; end = beg = m_plane_center;
beg[Z] = box.center().z() + m_radius;
end[Z] = box.center().z() - m_radius;
rotate_vec3d_around_plane_center(beg);
rotate_vec3d_around_plane_center(end);
// recalculate normal for clipping plane, if camera is looking downward to cut plane
normal = end - beg;
if (normal == Vec3d::Zero()) if (normal == Vec3d::Zero())
return; return;
}
// calculate normal and offset for clipping plane
double dist = (m_plane_center - beg).norm();
dist = std::clamp(dist, 0.0001, normal.norm()); dist = std::clamp(dist, 0.0001, normal.norm());
normal.normalize(); normal.normalize();
const double offset = normal.dot(beg) + dist; const double offset = normal.dot(beg) + dist;
@ -1372,7 +1396,7 @@ void GLGizmoCut3D::render_clipper_cut()
void GLGizmoCut3D::on_render() void GLGizmoCut3D::on_render()
{ {
if (update_bb() || force_update_clipper_on_render) { if (update_bb() || force_update_clipper_on_render || m_connectors_editing) {
update_clipper_on_render(); update_clipper_on_render();
m_c->object_clipper()->set_behavior(m_connectors_editing, m_connectors_editing, 0.4); m_c->object_clipper()->set_behavior(m_connectors_editing, m_connectors_editing, 0.4);
} }
@ -1826,7 +1850,7 @@ Transform3d GLGizmoCut3D::get_volume_transformation(const ModelVolume* volume) c
return translation_transform(offset) * scale_transform(Vec3d::Ones() - border_scale) * vol_matrix; 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 // check if connector pos is out of clipping plane
if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(cur_pos)) { if (m_c->object_clipper() && !m_c->object_clipper()->is_projection_inside_cut(cur_pos)) {
@ -1834,16 +1858,54 @@ bool GLGizmoCut3D::is_conflict_for_connector(size_t idx, const CutConnectors& co
return true; return true;
} }
// check if connector bottom contour is out of clipping plane
const CutConnector& cur_connector = connectors[idx]; 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 * const Transform3d matrix = translation_transform(cur_pos) * m_rotation_m *
scale_transform(Vec3f(cur_connector.radius, cur_connector.radius, cur_connector.height).cast<double>()); 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); 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)) { if (!bounding_box().contains(cur_tbb)) {
m_info_stats.outside_bb++; m_info_stats.outside_bb++;
return true; return true;
} }
// check if connectors are overlapping
for (size_t i = 0; i < connectors.size(); ++i) { for (size_t i = 0; i < connectors.size(); ++i) {
if (i == idx) if (i == idx)
continue; continue;
@ -1897,7 +1959,8 @@ void GLGizmoCut3D::render_connectors()
Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ(); Vec3d pos = connector.pos + instance_offset + sla_shift * Vec3d::UnitZ();
// First decide about the color of the point. // 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; m_has_invalid_connector = true;
render_color = CONNECTOR_ERR_COLOR; render_color = CONNECTOR_ERR_COLOR;
} }
@ -1907,16 +1970,23 @@ void GLGizmoCut3D::render_connectors()
if (!m_connectors_editing) if (!m_connectors_editing)
render_color = CONNECTOR_ERR_COLOR; render_color = CONNECTOR_ERR_COLOR;
else if (size_t(m_hover_id - m_connectors_group_id) == i) 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]) else if (m_selected[i])
render_color = connector.attribs.type == CutConnectorType::Dowel ? SELECTED_DOWEL_COLOR : SELECTED_PLAG_COLOR; render_color = connector.attribs.type == CutConnectorType::Dowel ? SELECTED_DOWEL_COLOR : SELECTED_PLAG_COLOR;
const Camera& camera = wxGetApp().plater()->get_camera(); const Camera& camera = wxGetApp().plater()->get_camera();
if (connector.attribs.type == CutConnectorType::Dowel && if (connector.attribs.type == CutConnectorType::Dowel &&
connector.attribs.style == CutConnectorStyle::Prizm) { connector.attribs.style == CutConnectorStyle::Prizm) {
if (is_looking_forward())
pos -= height * normal; pos -= height * normal;
else
pos += height * normal;
height *= 2; height *= 2;
} }
else if (!is_looking_forward())
pos += 0.05 * normal;
const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(pos) * m_rotation_m * const Transform3d view_model_matrix = camera.get_view_matrix() * translation_transform(pos) * m_rotation_m *
scale_transform(Vec3f(connector.radius, connector.radius, height).cast<double>()); scale_transform(Vec3f(connector.radius, connector.radius, height).cast<double>());

View File

@ -73,6 +73,7 @@ class GLGizmoCut3D : public GLGizmoBase
GLModel m_angle_arc; GLModel m_angle_arc;
Vec3d m_old_center; Vec3d m_old_center;
Vec3d m_cut_normal;
struct InvalidConnectorsStatistics struct InvalidConnectorsStatistics
{ {
@ -160,6 +161,7 @@ public:
bool is_in_editing_mode() const override { return m_connectors_editing; } bool is_in_editing_mode() const override { return m_connectors_editing; }
bool is_selection_rectangle_dragging() const override { return m_selection_rectangle.is_dragging(); } bool is_selection_rectangle_dragging() const override { return m_selection_rectangle.is_dragging(); }
bool is_looking_forward() const;
/// <summary> /// <summary>
/// Drag of plane /// Drag of plane
@ -239,6 +241,7 @@ private:
bool render_reset_button(const std::string& label_id, const std::string& tooltip) const; bool render_reset_button(const std::string& label_id, const std::string& tooltip) const;
bool render_connect_type_radio_button(CutConnectorType type); bool render_connect_type_radio_button(CutConnectorType type);
Transform3d get_volume_transformation(const ModelVolume* volume) const; 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); bool is_conflict_for_connector(size_t idx, const CutConnectors& connectors, const Vec3d cur_pos);
void render_connectors(); void render_connectors();

File diff suppressed because it is too large Load Diff

View File

@ -87,8 +87,10 @@ private:
// localized default text // localized default text
void set_default_text(); void set_default_text();
void check_selection(); void set_volume_by_selection();
ModelVolume *get_selected_volume(); // load text configuration from volume into gizmo
bool set_volume(ModelVolume *volume);
// create volume from text - main functionality // create volume from text - main functionality
bool process(); bool process();
void close(); void close();
@ -109,6 +111,9 @@ private:
void draw_font_preview(FaceName &face, bool is_visible); void draw_font_preview(FaceName &face, bool is_visible);
void draw_font_list(); void draw_font_list();
void draw_style_edit(); void draw_style_edit();
void draw_height(std::optional<float> scale, bool use_inch);
void draw_depth(std::optional<float> scale, bool use_inch);
bool draw_italic_button(); bool draw_italic_button();
bool draw_bold_button(); bool draw_bold_button();
void draw_advanced(); void draw_advanced();
@ -119,11 +124,9 @@ private:
void do_translate(const Vec3d& relative_move); void do_translate(const Vec3d& relative_move);
void do_rotate(float relative_z_angle); void do_rotate(float relative_z_angle);
/// <summary> bool rev_input_mm(const std::string &name, float &value, const float *default_value,
/// Move window for edit emboss text near to embossed object const std::string &undo_tooltip, float step, float step_fast, const char *format,
/// NOTE: embossed object must be selected bool use_inch = false, std::optional<float> scale = {});
/// </summary>
void set_fine_position();
/// <summary> /// <summary>
/// Reversible input float with option to restor default value /// Reversible input float with option to restor default value
@ -154,8 +157,6 @@ private:
bool choose_true_type_file(); bool choose_true_type_file();
bool choose_svg_file(); bool choose_svg_file();
bool load_configuration(ModelVolume *volume);
// When open text loaded from .3mf it could be written with unknown font // When open text loaded from .3mf it could be written with unknown font
bool m_is_unknown_font; bool m_is_unknown_font;
void create_notification_not_valid_font(const TextConfiguration& tc); void create_notification_not_valid_font(const TextConfiguration& tc);
@ -216,9 +217,12 @@ private:
GuiCfg() = default; GuiCfg() = default;
}; };
std::optional<const GuiCfg> m_gui_cfg; std::optional<const GuiCfg> m_gui_cfg;
bool m_is_advanced_edit_style = false;
// when true window will appear near to text
bool m_allow_float_window = false;
// setted only when wanted to use - not all the time // setted only when wanted to use - not all the time
std::optional<ImVec2> m_set_window_offset; std::optional<ImVec2> m_set_window_offset;
bool m_is_advanced_edit_style = false;
Emboss::StyleManager m_style_manager; Emboss::StyleManager m_style_manager;

View File

@ -257,20 +257,39 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt)
return false; return false;
} }
ImGuiIO& io = ImGui::GetIO(); auto to_string = [](wxEventType type) -> std::string {
if (type == wxEVT_CHAR) return "Char";
if (type == wxEVT_KEY_DOWN) return "KeyDown";
if (type == wxEVT_KEY_UP) return "KeyUp";
return "Other";
};
if (evt.GetEventType() == wxEVT_CHAR) { wxEventType type = evt.GetEventType();
ImGuiIO& io = ImGui::GetIO();
BOOST_LOG_TRIVIAL(debug) << "ImGui - key event(" << to_string(type) << "):"
//<< " Unicode(" << evt.GetUnicodeKey() << ")"
<< " KeyCode(" << evt.GetKeyCode() << ")";
if (type == wxEVT_CHAR) {
// Char event // Char event
const auto key = evt.GetUnicodeKey(); const auto key = evt.GetUnicodeKey();
unsigned int key_u = static_cast<unsigned int>(key);
// Release BackSpace, Delete, ... when miss wxEVT_KEY_UP event
// Already Fixed at begining of new frame
//if (key_u >= 0 && key_u < IM_ARRAYSIZE(io.KeysDown) && io.KeysDown[key_u]) {
// io.KeysDown[key_u] = false;
//}
if (key != 0) { if (key != 0) {
io.AddInputCharacter(key); io.AddInputCharacter(key);
} }
} else { } else if (type == wxEVT_KEY_DOWN || type == wxEVT_KEY_UP) {
// Key up/down event // Key up/down event
int key = evt.GetKeyCode(); int key = evt.GetKeyCode();
wxCHECK_MSG(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown), false, "Received invalid key code"); wxCHECK_MSG(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown), false, "Received invalid key code");
io.KeysDown[key] = evt.GetEventType() == wxEVT_KEY_DOWN; io.KeysDown[key] = (type == wxEVT_KEY_DOWN);
io.KeyShift = evt.ShiftDown(); io.KeyShift = evt.ShiftDown();
io.KeyCtrl = evt.ControlDown(); io.KeyCtrl = evt.ControlDown();
io.KeyAlt = evt.AltDown(); io.KeyAlt = evt.AltDown();
@ -282,6 +301,7 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt)
return ret; return ret;
} }
#include <array>
void ImGuiWrapper::new_frame() void ImGuiWrapper::new_frame()
{ {
if (m_new_frame_open) { if (m_new_frame_open) {
@ -292,6 +312,35 @@ void ImGuiWrapper::new_frame()
init_font(true); init_font(true);
} }
ImGuiIO& io = ImGui::GetIO();
// synchronize key states
// when the application loses the focus it may happen that the key up event is not processed
// synchronize modifier keys
constexpr std::array<std::pair<ImGuiKeyModFlags_, wxKeyCode>, 3> imgui_mod_keys{
std::make_pair(ImGuiKeyModFlags_Ctrl, WXK_CONTROL),
std::make_pair(ImGuiKeyModFlags_Shift, WXK_SHIFT),
std::make_pair(ImGuiKeyModFlags_Alt, WXK_ALT)};
for (const std::pair<ImGuiKeyModFlags_, wxKeyCode>& key : imgui_mod_keys) {
if ((io.KeyMods & key.first) != 0 && !wxGetKeyState(key.second))
io.KeyMods &= ~key.first;
}
// Not sure if it is neccessary
// values from 33 to 126 are reserved for the standard ASCII characters
for (size_t i = 33; i <= 126; ++i) {
wxKeyCode keycode = static_cast<wxKeyCode>(i);
if (io.KeysDown[i] && keycode != WXK_NONE && !wxGetKeyState(keycode))
io.KeysDown[i] = false;
}
// special keys: delete, backspace, ...
for (int key: io.KeyMap) {
wxKeyCode keycode = static_cast<wxKeyCode>(key);
if (io.KeysDown[key] && keycode != WXK_NONE && !wxGetKeyState(keycode))
io.KeysDown[key] = false;
}
ImGui::NewFrame(); ImGui::NewFrame();
m_new_frame_open = true; m_new_frame_open = true;
} }

View File

@ -483,7 +483,7 @@ TriangleMesh priv::create_mesh(DataBase &input, Fnc was_canceled, Job::Ctl& ctl)
TriangleMesh priv::create_default_mesh() TriangleMesh priv::create_default_mesh()
{ {
// When cant load any font use default object loaded from file // When cant load any font use default object loaded from file
std::string path = Slic3r::resources_dir() + "/data/embossed_text.stl"; std::string path = Slic3r::resources_dir() + "/data/embossed_text.obj";
TriangleMesh triangle_mesh; TriangleMesh triangle_mesh;
if (!load_obj(path.c_str(), &triangle_mesh)) { if (!load_obj(path.c_str(), &triangle_mesh)) {
// when can't load mesh use cube // when can't load mesh use cube
@ -527,10 +527,6 @@ void UpdateJob::update_volume(ModelVolume *volume,
obj_list->update_name_in_list(object_idx, volume_idx); obj_list->update_name_in_list(object_idx, volume_idx);
} }
// update printable state on canvas
if (volume->type() == ModelVolumeType::MODEL_PART)
canvas->update_instance_printable_state_for_object((size_t) object_idx);
// Move object on bed // Move object on bed
if (GLGizmoEmboss::is_text_object(volume)) volume->get_object()->ensure_on_bed(); if (GLGizmoEmboss::is_text_object(volume)) volume->get_object()->ensure_on_bed();
@ -679,7 +675,7 @@ OrthoProject3d priv::create_emboss_projection(
bool is_outside, float emboss, Transform3d tr, SurfaceCut &cut) bool is_outside, float emboss, Transform3d tr, SurfaceCut &cut)
{ {
// Offset of clossed side to model // Offset of clossed side to model
const float surface_offset = 1e-3f; // [in mm] const float surface_offset = 0.015f; // [in mm]
float float
front_move = (is_outside) ? emboss : surface_offset, front_move = (is_outside) ? emboss : surface_offset,
back_move = -((is_outside) ? surface_offset : emboss); back_move = -((is_outside) ? surface_offset : emboss);

View File

@ -5,7 +5,6 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <libslic3r/Emboss.hpp> #include <libslic3r/Emboss.hpp>
//#include <libslic3r/ModelVolumeType.hpp>
#include "slic3r/Utils/RaycastManager.hpp" #include "slic3r/Utils/RaycastManager.hpp"
#include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/Camera.hpp"
#include "Job.hpp" #include "Job.hpp"

View File

@ -154,6 +154,7 @@ void KBShortcutsDialog::fill_shortcuts()
{ "L", L("Gizmo FDM paint-on supports") }, { "L", L("Gizmo FDM paint-on supports") },
{ "P", L("Gizmo FDM paint-on seam") }, { "P", L("Gizmo FDM paint-on seam") },
{ "N", L("Gizmo Multi Material painting") }, { "N", L("Gizmo Multi Material painting") },
{ "T", L("Gizmo Text emboss / engrave")},
{ "Esc", L("Unselect gizmo or clear selection") }, { "Esc", L("Unselect gizmo or clear selection") },
{ "K", L("Change camera type (perspective, orthographic)") }, { "K", L("Change camera type (perspective, orthographic)") },
{ "B", L("Zoom to Bed") }, { "B", L("Zoom to Bed") },

View File

@ -39,19 +39,19 @@ void StyleManager::init(AppConfig *app_config, const EmbossStyles &default_style
m_style_items.push_back({style}); m_style_items.push_back({style});
} }
std::optional<size_t> activ_index_opt = (app_config != nullptr) ? std::optional<size_t> active_index_opt = (app_config != nullptr) ?
EmbossStylesSerializable::load_style_index(*app_config) : EmbossStylesSerializable::load_style_index(*app_config) :
std::optional<size_t>{}; std::optional<size_t>{};
size_t activ_index = 0; size_t active_index = 0;
if (activ_index_opt.has_value()) activ_index = *activ_index_opt; if (active_index_opt.has_value()) active_index = *active_index_opt;
if (activ_index >= m_style_items.size()) activ_index = 0; if (active_index >= m_style_items.size()) active_index = 0;
// find valid font item // find valid font item
if (!load_style(activ_index)) { if (!load_style(active_index)) {
m_style_items.erase(m_style_items.begin() + activ_index); m_style_items.erase(m_style_items.begin() + active_index);
activ_index = 0; active_index = 0;
while (m_style_items.empty() || !load_style(activ_index)) while (m_style_items.empty() || !load_style(active_index))
m_style_items.erase(m_style_items.begin()); m_style_items.erase(m_style_items.begin());
// no one style from config is loadable // no one style from config is loadable
if (m_style_items.empty()) { if (m_style_items.empty()) {
@ -61,14 +61,14 @@ void StyleManager::init(AppConfig *app_config, const EmbossStyles &default_style
m_style_items.push_back({std::move(style)}); m_style_items.push_back({std::move(style)});
} }
// try to load first default font // try to load first default font
[[maybe_unused]] bool loaded = load_style(activ_index); [[maybe_unused]] bool loaded = load_style(active_index);
assert(loaded); assert(loaded);
} }
} }
} }
bool StyleManager::store_styles_to_app_config(bool use_modification, bool StyleManager::store_styles_to_app_config(bool use_modification,
bool store_activ_index) bool store_active_index)
{ {
assert(m_app_config != nullptr); assert(m_app_config != nullptr);
if (m_app_config == nullptr) return false; if (m_app_config == nullptr) return false;
@ -87,7 +87,7 @@ bool StyleManager::store_styles_to_app_config(bool use_modification,
m_style_cache.stored_wx_font = m_style_cache.wx_font; m_style_cache.stored_wx_font = m_style_cache.wx_font;
} }
if (store_activ_index) if (store_active_index)
{ {
size_t style_index = exist_stored_style() ? size_t style_index = exist_stored_style() ?
m_style_cache.style_index : m_style_cache.style_index :
@ -200,7 +200,7 @@ bool StyleManager::load_style(const EmbossStyle &style, const wxFont &font)
return true; return true;
} }
bool StyleManager::is_activ_font() { return m_style_cache.font_file.has_value(); } bool StyleManager::is_active_font() { return m_style_cache.font_file.has_value(); }
bool StyleManager::load_first_valid_font() { bool StyleManager::load_first_valid_font() {
while (!m_style_items.empty()) { while (!m_style_items.empty()) {
@ -228,7 +228,7 @@ void StyleManager::clear_imgui_font() { m_style_cache.atlas.Clear(); }
ImFont *StyleManager::get_imgui_font() ImFont *StyleManager::get_imgui_font()
{ {
if (!is_activ_font()) return nullptr; if (!is_active_font()) return nullptr;
ImVector<ImFont *> &fonts = m_style_cache.atlas.Fonts; ImVector<ImFont *> &fonts = m_style_cache.atlas.Fonts;
if (fonts.empty()) return nullptr; if (fonts.empty()) return nullptr;

View File

@ -46,7 +46,7 @@ public:
/// <param name="use_modification">When true cache state will be used for store</param> /// <param name="use_modification">When true cache state will be used for store</param>
/// <param name="use_modification">When true store activ index into configuration</param> /// <param name="use_modification">When true store activ index into configuration</param>
/// <returns>True on succes otherwise False.</returns> /// <returns>True on succes otherwise False.</returns>
bool store_styles_to_app_config(bool use_modification = true, bool store_activ_index = true); bool store_styles_to_app_config(bool use_modification = true, bool store_active_index = true);
/// <summary> /// <summary>
/// Append actual style to style list /// Append actual style to style list
@ -185,7 +185,7 @@ public:
}; };
// check if exist selected font style in manager // check if exist selected font style in manager
bool is_activ_font(); bool is_active_font();
// Limits for imgui loaded font size // Limits for imgui loaded font size
// Value out of limits is crop // Value out of limits is crop

View File

@ -19,7 +19,7 @@ const std::string EmbossStylesSerializable::APP_CONFIG_FONT_COLLECTION = "colle
const std::string EmbossStylesSerializable::APP_CONFIG_FONT_CHAR_GAP = "char_gap"; const std::string EmbossStylesSerializable::APP_CONFIG_FONT_CHAR_GAP = "char_gap";
const std::string EmbossStylesSerializable::APP_CONFIG_FONT_LINE_GAP = "line_gap"; const std::string EmbossStylesSerializable::APP_CONFIG_FONT_LINE_GAP = "line_gap";
const std::string EmbossStylesSerializable::APP_CONFIG_ACTIVE_FONT = "activ_font"; const std::string EmbossStylesSerializable::APP_CONFIG_ACTIVE_FONT = "active_font";
std::string EmbossStylesSerializable::create_section_name(unsigned index) std::string EmbossStylesSerializable::create_section_name(unsigned index)
{ {
@ -150,8 +150,8 @@ void EmbossStylesSerializable::store_style_index(AppConfig &cfg, unsigned index)
// store actual font index // store actual font index
cfg.clear_section(AppConfig::SECTION_EMBOSS_STYLE); cfg.clear_section(AppConfig::SECTION_EMBOSS_STYLE);
// activ font first index is +1 to correspond with section name // activ font first index is +1 to correspond with section name
std::string activ_font = std::to_string(index); std::string active_font = std::to_string(index);
cfg.set(AppConfig::SECTION_EMBOSS_STYLE, APP_CONFIG_ACTIVE_FONT, activ_font); cfg.set(AppConfig::SECTION_EMBOSS_STYLE, APP_CONFIG_ACTIVE_FONT, active_font);
} }
std::optional<size_t> EmbossStylesSerializable::load_style_index(const AppConfig &cfg) std::optional<size_t> EmbossStylesSerializable::load_style_index(const AppConfig &cfg)

View File

@ -220,10 +220,16 @@ SCENARIO( "make_xxx functions produce meshes.") {
GIVEN("make_sphere() function") { GIVEN("make_sphere() function") {
WHEN("make_sphere() is called with arguments 10, PI / 3") { WHEN("make_sphere() is called with arguments 10, PI / 3") {
TriangleMesh sph = make_sphere(10, PI / 243.0); TriangleMesh sph = make_sphere(10, PI / 243.0);
THEN("Resulting mesh has one point at 0,0,-10 and one at 0,0,10") { THEN( "Edge length is smaller than limit but not smaller than half of it") {
const std::vector<stl_vertex> &verts = sph.its.vertices; double len = (sph.its.vertices[sph.its.indices[0][0]] - sph.its.vertices[sph.its.indices[0][1]]).norm();
REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return is_approx(t, Vec3f(0.f, 0.f, 10.f)); } ) == 1); double limit = 10*PI/243.;
REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return is_approx(t, Vec3f(0.f, 0.f, -10.f)); } ) == 1); REQUIRE(len <= limit);
REQUIRE(len >= limit/2.);
}
THEN( "Vertices are about the correct distance from the origin") {
bool all_vertices_ok = std::all_of(sph.its.vertices.begin(), sph.its.vertices.end(),
[](const stl_vertex& pt) { return is_approx(pt.squaredNorm(), 100.f); });
REQUIRE(all_vertices_ok);
} }
THEN( "The mesh volume is approximately 4/3 * pi * 10^3") { THEN( "The mesh volume is approximately 4/3 * pi * 10^3") {
REQUIRE(abs(sph.volume() - (4.0/3.0 * M_PI * std::pow(10,3))) < 1); // 1% tolerance? REQUIRE(abs(sph.volume() - (4.0/3.0 * M_PI * std::pow(10,3))) < 1); // 1% tolerance?

View File

@ -201,7 +201,7 @@ ExPolygons heal_and_check(const Polygons &polygons)
{ {
Pointfs intersections_prev = intersection_points(polygons); Pointfs intersections_prev = intersection_points(polygons);
Points polygons_points = to_points(polygons); Points polygons_points = to_points(polygons);
Points duplicits_prev = collect_duplications(polygons_points); Points duplicits_prev = collect_duplicates(polygons_points);
ExPolygons shape = Emboss::heal_shape(polygons); ExPolygons shape = Emboss::heal_shape(polygons);
@ -215,7 +215,7 @@ ExPolygons heal_and_check(const Polygons &polygons)
Pointfs intersections = intersection_points(shape); Pointfs intersections = intersection_points(shape);
Points shape_points = to_points(shape); Points shape_points = to_points(shape);
Points duplicits = collect_duplications(shape_points); Points duplicits = collect_duplicates(shape_points);
//{ //{
// BoundingBox bb(polygons_points); // BoundingBox bb(polygons_points);
// // bb.scale(svg_scale); // // bb.scale(svg_scale);