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"?>
<!-- Generator: Adobe Illustrator 23.0.2, 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"
viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve">
<g id="cut">
<g>
<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
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
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
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
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
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
S18.95,65.5,18.12,65.5z"/>
</g>
<g>
<g>
<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
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
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"/>
</g>
<g>
<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
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
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"/>
</g>
</g>
<!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<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"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path fill="#ED6B21" d="M3.0597045,10.3634434H0.5884437C0.2628375,10.3634434,0,10.100606,0,9.7750006
c0-0.3256063,0.2628375-0.5884438,0.5884437-0.5884438h2.4712608c0.3256061,0,0.5884435,0.2628374,0.5884435,0.5884438
C3.6481481,10.100606,3.3853078,10.3634434,3.0597045,10.3634434z"/>
<path fill="#ED6B21" d="M12.0967369,10.3634434h-2.471261c-0.3256063,0-0.5884438-0.2628374-0.5884438-0.5884428
c0-0.3256063,0.2628374-0.5884438,0.5884438-0.5884438h2.471261c0.3256063,0,0.5884438,0.2628374,0.5884438,0.5884438
C12.6851807,10.100606,12.4223404,10.3634434,12.0967369,10.3634434z"/>
<path fill="#ED6B21" d="M7.5782208,10.3634434h-2.471261c-0.3256059,0-0.5884438-0.2628374-0.5884438-0.5884428
c0-0.3256063,0.2628379-0.5884438,0.5884438-0.5884438h2.471261c0.3256059,0,0.5884433,0.2628374,0.5884433,0.5884438
C8.1666641,10.100606,7.9038239,10.3634434,7.5782208,10.3634434z"/>
<g>
<path fill="#808080" d="M10.98001,11.9849854c-0.289978,0-0.5199585,0.2299805-0.5199585,0.5199585v0.5922852v0.3327637
c0,0.289978-0.2300415,0.5200195-0.5200195,0.5200195H2.7452075c-0.289978,0-0.5200195-0.2300415-0.5200195-0.5200195V13.097229
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
v0.3327637C1.1852101,14.2999878,1.8952321,15,2.7552173,15h7.1748047c0.8599854,0,1.5700073-0.7000122,1.5700073-1.5700073
V13.097229v-0.5922852C11.5000296,12.2149658,11.2700491,11.9849854,10.98001,11.9849854z"/>
<path fill="#808080" d="M9.9300222,4.5499878H2.7552173c-0.8599852,0-1.5700072,0.7000122-1.5700072,1.5700073v0.3327637v0.5922852
c0,0.289978,0.2299805,0.5199585,0.5200195,0.5199585c0.289978,0,0.5199584-0.2299805,0.5199584-0.5199585V6.4527588V6.1199951
c0-0.289978,0.2300415-0.5200195,0.5200195-0.5200195H9.940032c0.289978,0,0.5200195,0.2300415,0.5200195,0.5200195v0.3327637
v0.5922852c0,0.289978,0.2299805,0.5199585,0.5199585,0.5199585c0.2900391,0,0.5200195-0.2299805,0.5200195-0.5199585V6.4527588
V6.1199951C11.5000296,5.25,10.7900076,4.5499878,9.9300222,4.5499878z"/>
</g>
</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"?>
<!-- Generator: Adobe Illustrator 23.0.3, 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"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="add_x5F_part">
<g>
<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
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
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
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
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
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
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
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
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.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
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
s0.94-2.1,2.1-2.1s2.1,0.94,2.1,2.1S12.66,6.6,11.5,6.6z"/>
</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"/>
<!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<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"
width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<path fill="#ED6B21" d="M7.2122064,10.8825388H5.473033c-0.6128426,0-1.1075444-0.4947023-1.1075444-1.1075449
S4.8601904,8.667449,5.473033,8.667449h1.7391734c0.6128426,0,1.1075444,0.4947023,1.1075444,1.1075449
S7.8250437,10.8825388,7.2122064,10.8825388z"/>
<g>
<path fill="#808080" d="M10.98001,15c-0.289978,0-0.5199585-0.2299805-0.5199585-0.5199585v-0.5922852v-0.3327637
c0-0.289978-0.2300415-0.5200195-0.5200195-0.5200195H2.7452075c-0.289978,0-0.5200195,0.2300415-0.5200195,0.5200195v0.3327637
v0.5922852C2.225188,14.7700195,1.9952077,15,1.7052296,15c-0.2900391,0-0.5200195-0.2299805-0.5200195-0.5199585v-0.5922852
v-0.3327637c0-0.8699951,0.710022-1.5700073,1.5700072-1.5700073h7.1748047c0.8599854,0,1.5700073,0.7000122,1.5700073,1.5700073
v0.3327637v0.5922852C11.5000296,14.7700195,11.2700491,15,10.98001,15z"/>
<path fill="#808080" d="M9.9300222,7.5650024H2.7552173c-0.8599852,0-1.5700072-0.7000122-1.5700072-1.5700073V5.6622314V5.0699463
c0-0.289978,0.2299805-0.5199585,0.5200195-0.5199585c0.289978,0,0.5199584,0.2299805,0.5199584,0.5199585v0.5922852v0.3327637
c0,0.289978,0.2300415,0.5200195,0.5200195,0.5200195H9.940032c0.289978,0,0.5200195-0.2300415,0.5200195-0.5200195V5.6622314
V5.0699463c0-0.289978,0.2299805-0.5199585,0.5199585-0.5199585c0.2900391,0,0.5200195,0.2299805,0.5200195,0.5199585v0.5922852
v0.3327637C11.5000296,6.8649902,10.7900076,7.5650024,9.9300222,7.5650024z"/>
</g>
</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)
{
Slic3r::CNumericLocalesSetter locales_setter;
FILE* fp = fopen(file, "w");
FILE* fp = boost::nowide::fopen(file, "w");
if (fp == nullptr) {
BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing";
return false;
}

View file

@ -17,6 +17,12 @@ imstb_truetype.h modification:
Hot fix for open symbolic fonts on windows
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
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;
void rotate(double angle) { (*this) = this->rotated(angle); }
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,
// to encompass the original bounding box.
void align_to_grid(const coord_t cell_size);

View file

@ -185,7 +185,6 @@ set(SLIC3R_SOURCES
Model.hpp
ModelArrange.hpp
ModelArrange.cpp
#ModelVolumeType.hpp
MultiMaterialSegmentation.cpp
MultiMaterialSegmentation.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
// Overlap all duplicit points by rectangle 3x3
Points duplicits = collect_duplications(to_points(polygons));
Points duplicits = collect_duplicates(to_points(polygons));
if (!duplicits.empty()) {
polygons.reserve(polygons.size() + duplicits.size());
for (const Point &p : duplicits) {
@ -310,7 +310,7 @@ bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration)
priv::remove_same_neighbor(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.);
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(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);
Pointfs pts2 = intersection_points(shape);
@ -387,7 +387,7 @@ bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration)
}
assert(intersection_points(shape).empty());
assert(collect_duplications(to_points(shape)).empty());
assert(collect_duplicates(to_points(shape)).empty());
return true;
}
@ -1186,7 +1186,7 @@ indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
const IProjection &projection)
{
Points points = to_points(shape2d);
Points duplicits = collect_duplications(points);
Points duplicits = collect_duplicates(points);
return (duplicits.empty()) ?
priv::polygons2model_unique(shape2d, projection, points) :
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";
// 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";
// TextConfiguration::EmbossStyle
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);
if (std::fabs(distance) > std::numeric_limits<float>::epsilon())
fp.distance = distance;
std::string use_surface = get_attribute_value_string(attributes, num_attributes, USE_SURFACE_ATTR);
if (!use_surface.empty()) fp.use_surface = true;
int use_surface = get_attribute_value_int(attributes, num_attributes, USE_SURFACE_ATTR);
if (use_surface == 1) fp.use_surface = true;
float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR);
if (std::fabs(angle) > std::numeric_limits<float>::epsilon())
fp.angle = angle;

View file

@ -2327,7 +2327,7 @@ void GCode::process_layer_single_object(
interface_extruder = dontcare_extruder;
}
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) {
init_layer_delayed();
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()));
BoundingBox bb_(min_, max_);
// intersect of BB compare min max
if (bb.intersects(bb_) &&
if (bb.overlap(bb_) &&
l.intersection(l_, &i))
pts.push_back(i.cast<double>());
}

View file

@ -317,13 +317,16 @@ void Layer::build_up_down_graph(Layer& below, Layer& above)
coord_t* end = srcs + 4;
std::sort(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;
else if (begin + 2 <= end) {
// store a -1 based negative index into the "intersections" vector here.
m_intersections.emplace_back(srcs[0], srcs[1]);
pt.z() = -coord_t(m_intersections.size());
} else {
assert(begin + 2 == end);
if (begin + 2 <= end) {
// store a -1 based negative index into the "intersections" vector here.
m_intersections.emplace_back(srcs[0], srcs[1]);
pt.z() = -coord_t(m_intersections.size());
}
}
}
const std::vector<std::pair<coord_t, coord_t>>& intersections() const { return m_intersections; }

View file

@ -14,7 +14,6 @@
#include "Arrange.hpp"
#include "CustomGCode.hpp"
#include "enum_bitmask.hpp"
//#include "ModelVolumeType.hpp"
#include "TextConfiguration.hpp"
#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;
// 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,
float tessTol,
Vec2f p1,

View file

@ -397,22 +397,37 @@ static ClipperLib_Z::Paths clip_extrusion(const ClipperLib_Z::Path &subject, con
ClipperLib_Z::Clipper clipper;
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) {
// 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 end = e1top;
if (start.z() <= 0 && end.z() <= 0) {
start = e2bot;
end = e2top;
}
assert(start.z() > 0 && end.z() > 0);
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);
// Interpolate extrusion line width.
double length_sqr = (end - start).cast<double>().squaredNorm();
double dist_sqr = (pt - start).cast<double>().squaredNorm();
double t = std::sqrt(dist_sqr / length_sqr);
double length_sqr = (end - start).cast<double>().squaredNorm();
double dist_sqr = (pt - start).cast<double>().squaredNorm();
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);

View file

@ -66,9 +66,9 @@ bool has_duplicate_points(std::vector<Point> &&pts)
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;
const Point *prev = &pts.front();
for (size_t i = 1; i < pts.size(); ++i) {

File diff suppressed because it is too large Load diff

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));
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);
@ -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
// to determine the granularity.
// 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)
{
int sectorCount = int(ceil(2. * M_PI / fa));
int stackCount = int(ceil(M_PI / fa));
float sectorStep = float(2. * M_PI / sectorCount);
float stackStep = float(M_PI / stackCount);
// First build an icosahedron (taken from http://www.songho.ca/opengl/gl_sphere.html)
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;
vertices.reserve((stackCount - 1) * sectorCount + 2);
for (int i = 0; i <= stackCount; ++ i) {
// from pi/2 to -pi/2
double stackAngle = 0.5 * M_PI - stackStep * i;
double xy = radius * cos(stackAngle);
double z = radius * sin(stackAngle);
if (i == 0 || i == stackCount)
vertices.emplace_back(Vec3f(float(xy), 0.f, float(z)));
else
for (int j = 0; j < sectorCount; ++ j) {
// from 0 to 2pi
double sectorAngle = sectorStep * j;
vertices.emplace_back(Vec3d(xy * std::cos(sectorAngle), xy * std::sin(sectorAngle), z).cast<float>());
}
}
auto& indices = mesh.indices;
vertices.resize(12);
indices.reserve(20);
auto& facets = mesh.indices;
facets.reserve(2 * (stackCount - 1) * sectorCount);
for (int i = 0; i < stackCount; ++ i) {
// Beginning of current stack.
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);
float z, xy;
float hAngle1 = -PI / 2 - H_ANGLE / 2;
vertices[0] = stl_vertex(0, 0, radius); // the first top vertex at (0, 0, r)
for (int i = 1; i <= 5; ++i) {
z = radius * sinf(V_ANGLE);
xy = radius * cosf(V_ANGLE);
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;
}
}
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;
// Add three new triangles, reindex the old one.
const int last_index = indices.size() - 1;
indices.emplace_back(stl_triangle_vertex_indices(middle_vertices_idxs[0], middle_vertices_idxs[1], middle_vertices_idxs[2]));
new_neighbors[indices.size()-1] = Vec3i(last_index+2, last_index+3, i);
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;
}

View file

@ -241,7 +241,7 @@ Triangulation::Indices Triangulation::triangulate(const ExPolygon &expolygon){
Triangulation::Indices Triangulation::triangulate(const ExPolygons &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);
Changes changes = create_changes(pts, d_pts);
@ -262,7 +262,7 @@ Triangulation::Indices Triangulation::triangulate(const ExPolygons &expolygons,
{
assert(count_points(expolygons) == points.size());
// when contain duplicit coordinate in points will not work properly
assert(collect_duplications(points).empty());
assert(collect_duplicates(points).empty());
HalfEdges edges;
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
else
dest.insert(dest.end(), src.begin(), src.end());
// NOTE: insert reserve space when needed
}
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
// 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::size_type pos = 0;

View file

@ -437,9 +437,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();
@ -448,12 +448,16 @@ int GLVolumeCollection::load_object_volume(
this->volumes.emplace_back(new GLVolume());
GLVolume& v = *this->volumes.back();
v.set_color(color_from_model_volume(*model_volume));
// apply printable value from the instance
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()) {

View file

@ -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; }

File diff suppressed because it is too large Load diff

View file

@ -450,6 +450,14 @@ struct PageBedShape: ConfigWizardPage
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
{
wxTextCtrl *diam_nozzle;
@ -584,6 +592,7 @@ struct ConfigWizard::priv
PageBedShape *page_bed = nullptr;
PageDiameters *page_diams = nullptr;
PageTemperatures *page_temps = nullptr;
PageBuildVolume* page_bvolume = nullptr;
// Pointers to all pages (regardless or whether currently part of the ConfigWizardIndex)
std::vector<ConfigWizardPage*> all_pages;

View file

@ -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;
}

View file

@ -81,6 +81,11 @@ static const Slic3r::ColorRGBA ERROR_BG_LIGHT_COLOR = { 0.753f, 0.192f, 0.039f
// Number of floats
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 GUI {
@ -1498,6 +1503,10 @@ void GLCanvas3D::render()
}
#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();
@ -2379,10 +2388,11 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
if (!m_initialized)
return;
// see include/wx/defs.h enum wxKeyCode
int keyCode = evt.GetKeyCode();
int ctrlMask = wxMOD_CONTROL;
int shiftMask = wxMOD_SHIFT;
#ifdef SHOW_IMGUI_DEMO_WINDOW
static int cur = 0;
if (wxString("demo")[cur] == evt.GetUnicodeKey()) ++cur; else cur = 0;
if (cur == 4) { show_imgui_demo_window = !show_imgui_demo_window; cur = 0;}
#endif // SHOW_IMGUI_DEMO_WINDOW
auto imgui = wxGetApp().imgui();
if (imgui->update_key_data(evt)) {
@ -2390,6 +2400,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
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()))
return;
@ -3447,20 +3461,27 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
evt.Skip();
// 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) {
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();
if (hover_volume_idx < 0 || hover_volume_idx >= hover_object->volumes.size()) continue;
const ModelVolume* hover_volume = hover_object->volumes[hover_volume_idx];
if (hover_volume->text_configuration.has_value()) {
//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});
if (!hover_volume->text_configuration.has_value()) continue;
m_selection.add_volumes(Selection::EMode::Volume, {(unsigned) hover_volume_id});
if (type != GLGizmosManager::EType::Emboss)
m_gizmos.open_gizmo(GLGizmosManager::EType::Emboss);
wxGetApp().obj_list()->update_selections();
return;
}
wxGetApp().obj_list()->update_selections();
return;
}
}

View file

@ -970,16 +970,19 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu)
wxString name = _L("Edit text");
auto can_edit_text = []() {
const auto& sel = plater()->get_selection();
if (sel.volumes_count() != 1) return false;
auto cid = sel.get_volume(*sel.get_volume_idxs().begin());
const ModelVolume* vol = plater()->canvas3D()->get_model()
->objects[cid->object_idx()]->volumes[cid->volume_idx()];
return vol->text_configuration.has_value();
if (plater() != nullptr) {
const Selection& sel = plater()->get_selection();
if (sel.volumes_count() == 1) {
const GLVolume* gl_vol = sel.get_first_volume();
const ModelVolume* vol = plater()->model().objects[gl_vol->object_idx()]->volumes[gl_vol->volume_idx()];
return vol->text_configuration.has_value();
}
}
return false;
};
if (menu == &m_object_menu) {
auto menu_item_id = menu->FindItem(name);
if (menu != &m_text_part_menu) {
const int menu_item_id = menu->FindItem(name);
if (menu_item_id != wxNOT_FOUND)
menu->Destroy(menu_item_id);
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 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;
@ -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()
{
BoundingBoxf3 box = bounding_box();
// update cut_normal
Vec3d beg, end = beg = m_plane_center;
beg[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(end);
double dist = (m_plane_center - beg).norm();
// calculate normal for cut plane
Vec3d normal = m_cut_normal = end - beg;
m_cut_normal.normalize();
if (!is_looking_forward()) {
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())
return;
}
// calculate normal and offset for clipping plane
Vec3d normal = end - beg;
if (normal == Vec3d::Zero())
return;
double dist = (m_plane_center - beg).norm();
dist = std::clamp(dist, 0.0001, normal.norm());
normal.normalize();
const double offset = normal.dot(beg) + dist;
@ -1372,7 +1396,7 @@ void GLGizmoCut3D::render_clipper_cut()
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();
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;
}
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)) {
@ -1834,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;
@ -1897,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;
}
@ -1907,16 +1970,23 @@ 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;
const Camera& camera = wxGetApp().plater()->get_camera();
if (connector.attribs.type == CutConnectorType::Dowel &&
connector.attribs.style == CutConnectorStyle::Prizm) {
pos -= height * normal;
if (is_looking_forward())
pos -= height * normal;
else
pos += height * normal;
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 *
scale_transform(Vec3f(connector.radius, connector.radius, height).cast<double>());

View file

@ -73,6 +73,7 @@ class GLGizmoCut3D : public GLGizmoBase
GLModel m_angle_arc;
Vec3d m_old_center;
Vec3d m_cut_normal;
struct InvalidConnectorsStatistics
{
@ -160,6 +161,7 @@ public:
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_looking_forward() const;
/// <summary>
/// Drag of plane
@ -239,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();

File diff suppressed because it is too large Load diff

View file

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

View file

@ -257,20 +257,39 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt)
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
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) {
io.AddInputCharacter(key);
}
} else {
} else if (type == wxEVT_KEY_DOWN || type == wxEVT_KEY_UP) {
// Key up/down event
int key = evt.GetKeyCode();
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.KeyCtrl = evt.ControlDown();
io.KeyAlt = evt.AltDown();
@ -282,6 +301,7 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt)
return ret;
}
#include <array>
void ImGuiWrapper::new_frame()
{
if (m_new_frame_open) {
@ -292,6 +312,35 @@ void ImGuiWrapper::new_frame()
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();
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()
{
// 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;
if (!load_obj(path.c_str(), &triangle_mesh)) {
// 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);
}
// 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
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)
{
// Offset of clossed side to model
const float surface_offset = 1e-3f; // [in mm]
const float surface_offset = 0.015f; // [in mm]
float
front_move = (is_outside) ? emboss : surface_offset,
back_move = -((is_outside) ? surface_offset : emboss);

View file

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

View file

@ -154,6 +154,7 @@ void KBShortcutsDialog::fill_shortcuts()
{ "L", L("Gizmo FDM paint-on supports") },
{ "P", L("Gizmo FDM paint-on seam") },
{ "N", L("Gizmo Multi Material painting") },
{ "T", L("Gizmo Text emboss / engrave")},
{ "Esc", L("Unselect gizmo or clear selection") },
{ "K", L("Change camera type (perspective, orthographic)") },
{ "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});
}
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) :
std::optional<size_t>{};
size_t activ_index = 0;
if (activ_index_opt.has_value()) activ_index = *activ_index_opt;
if (activ_index >= m_style_items.size()) activ_index = 0;
size_t active_index = 0;
if (active_index_opt.has_value()) active_index = *active_index_opt;
if (active_index >= m_style_items.size()) active_index = 0;
// find valid font item
if (!load_style(activ_index)) {
m_style_items.erase(m_style_items.begin() + activ_index);
activ_index = 0;
while (m_style_items.empty() || !load_style(activ_index))
if (!load_style(active_index)) {
m_style_items.erase(m_style_items.begin() + active_index);
active_index = 0;
while (m_style_items.empty() || !load_style(active_index))
m_style_items.erase(m_style_items.begin());
// no one style from config is loadable
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)});
}
// try to load first default font
[[maybe_unused]] bool loaded = load_style(activ_index);
[[maybe_unused]] bool loaded = load_style(active_index);
assert(loaded);
}
}
}
bool StyleManager::store_styles_to_app_config(bool use_modification,
bool store_activ_index)
bool store_active_index)
{
assert(m_app_config != nullptr);
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;
}
if (store_activ_index)
if (store_active_index)
{
size_t style_index = exist_stored_style() ?
m_style_cache.style_index :
@ -200,7 +200,7 @@ bool StyleManager::load_style(const EmbossStyle &style, const wxFont &font)
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() {
while (!m_style_items.empty()) {
@ -228,7 +228,7 @@ void StyleManager::clear_imgui_font() { m_style_cache.atlas.Clear(); }
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;
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 store activ index into configuration</param>
/// <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>
/// Append actual style to style list
@ -185,7 +185,7 @@ public:
};
// check if exist selected font style in manager
bool is_activ_font();
bool is_active_font();
// Limits for imgui loaded font size
// 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_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)
{
@ -150,8 +150,8 @@ void EmbossStylesSerializable::store_style_index(AppConfig &cfg, unsigned index)
// store actual font index
cfg.clear_section(AppConfig::SECTION_EMBOSS_STYLE);
// activ font first index is +1 to correspond with section name
std::string activ_font = std::to_string(index);
cfg.set(AppConfig::SECTION_EMBOSS_STYLE, APP_CONFIG_ACTIVE_FONT, activ_font);
std::string active_font = std::to_string(index);
cfg.set(AppConfig::SECTION_EMBOSS_STYLE, APP_CONFIG_ACTIVE_FONT, active_font);
}
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") {
WHEN("make_sphere() is called with arguments 10, PI / 3") {
TriangleMesh sph = make_sphere(10, PI / 243.0);
THEN("Resulting mesh has one point at 0,0,-10 and one at 0,0,10") {
const std::vector<stl_vertex> &verts = sph.its.vertices;
REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return is_approx(t, Vec3f(0.f, 0.f, 10.f)); } ) == 1);
REQUIRE(std::count_if(verts.begin(), verts.end(), [](const Vec3f& t) { return is_approx(t, Vec3f(0.f, 0.f, -10.f)); } ) == 1);
THEN( "Edge length is smaller than limit but not smaller than half of it") {
double len = (sph.its.vertices[sph.its.indices[0][0]] - sph.its.vertices[sph.its.indices[0][1]]).norm();
double limit = 10*PI/243.;
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") {
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);
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);
@ -215,7 +215,7 @@ ExPolygons heal_and_check(const Polygons &polygons)
Pointfs intersections = intersection_points(shape);
Points shape_points = to_points(shape);
Points duplicits = collect_duplications(shape_points);
Points duplicits = collect_duplicates(shape_points);
//{
// BoundingBox bb(polygons_points);
// // bb.scale(svg_scale);