Merge branch 'fs_dir_per_glyph_SPE-1597' into fs_svg

# Conflicts:
#	src/libslic3r/Emboss.cpp
#	src/slic3r/GUI/TextLines.cpp
This commit is contained in:
Filip Sykala - NTB T15p 2023-08-10 10:17:34 +02:00
commit 14b22e7310
4 changed files with 95 additions and 113 deletions

View File

@ -1930,6 +1930,18 @@ void align_shape(ExPolygonsWithIds &shapes, const std::wstring &text, const Font
// Shapes have to match letters in text
assert(shapes.size() == text.length());
unsigned count_lines = get_count_lines(text);
int y_offset = get_align_y_offset(prop.align.second, count_lines, font, prop);
// Speed up for left aligned text
if (prop.align.first == FontProp::HorizontalAlign::left){
// already horizontaly aligned
for (ExPolygons shape : shapes)
for (ExPolygon &s : shape)
s.translate(Point(0, y_offset));
return;
}
BoundingBox shape_bb;
for (const ExPolygonsWithId& shape: shapes)
shape_bb.merge(get_extents(shape.expoly));
@ -1941,21 +1953,6 @@ void align_shape(ExPolygonsWithIds &shapes, const std::wstring &text, const Font
return line_bb;
};
int line_height = get_line_height(font, prop);
unsigned count_lines = get_count_lines(text);
int center_line = get_font_info(font, prop).ascent * ASCENT_CENTER;
int y_offset = get_align_y_offset(prop.align.second, count_lines, font, prop);
// Speed up for left aligned text
if (prop.align.first == FontProp::HorizontalAlign::left){
// already horizontaly aligned
for (ExPolygonsWithId& shape : shapes)
for (ExPolygon &s : shape.expoly)
s.translate(Point(0, y_offset));
return;
}
// Align x line by line
Point offset(
get_align_x_offset(prop.align.first, shape_bb, get_line_bb(0)),

View File

@ -2688,16 +2688,6 @@ void GLGizmoEmboss::draw_advanced()
m_text_lines.reset();
m_imgui->disabled_end(); // !can_use_per_glyph
m_imgui->disabled_begin(!per_glyph);
ImGui::SameLine();
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
if (m_imgui->slider_float("##base_line_y_offset", &m_text_lines.offset, -10.f, 10.f, "%f mm")) {
reinit_text_lines(m_text_lines.get_lines().size());
process();
} else if (ImGui::IsItemHovered())
ImGui::SetTooltip("TEST PURPOSE ONLY\nMove base line (up/down) for allign letters");
m_imgui->disabled_end(); // !per_glyph
auto draw_align = [&align = font_prop.align, input_offset = m_gui_cfg->advanced_input_offset, &icons = m_icons]() {
bool is_change = false;
ImGui::SameLine(input_offset);
@ -2761,6 +2751,8 @@ void GLGizmoEmboss::draw_advanced()
}
// input gap between lines
bool is_multiline = m_text_lines.get_lines().size() > 1;
m_imgui->disabled_begin(!is_multiline);
auto def_line_gap = stored_style ?
&stored_style->prop.line_gap : nullptr;
int min_line_gap = -half_ascent;
@ -2778,6 +2770,7 @@ void GLGizmoEmboss::draw_advanced()
exist_change = true;
}
}
m_imgui->disabled_end(); // !is_multiline
// input boldness
auto def_boldness = stored_style ?

View File

@ -45,50 +45,8 @@ const Slic3r::Polygon *largest(const Slic3r::Polygons &polygons)
return result;
}
indexed_triangle_set its_create_belt(const Slic3r::Polygon &polygon, float width_half) {
// Improve: Create torus instead of flat belt path (with model overlaps)
assert(!polygon.empty());
if (polygon.empty())
return {};
// add a small positive offset to avoid z-fighting
float offset = static_cast<float>(scale_(0.015f));
Polygons polygons_expanded = expand(polygon, offset);
const Slic3r::Polygon *polygon_expanded_ptr = largest(polygons_expanded);
assert(polygon_expanded_ptr != nullptr);
if (polygon_expanded_ptr == nullptr || polygon_expanded_ptr->empty())
return {};
const Slic3r::Polygon &polygon_expanded = *polygon_expanded_ptr;
// inspired by 3DScene.cpp void GLVolume::SinkingContours::update()
indexed_triangle_set model;
size_t count = polygon_expanded.size();
model.vertices.reserve(2 * count);
model.indices.reserve(2 * count);
for (const Point &point : polygon_expanded.points) {
Vec2f point_d = unscale(point).cast<float>();
Vec3f vertex(point_d.x(), point_d.y(), width_half);
model.vertices.push_back(vertex);
vertex.z() *= -1;
model.vertices.push_back(vertex);
}
unsigned int prev_i = count - 1;
for (unsigned int i = 0; i < count; ++i) {
// t .. top
// b .. bottom
unsigned int t1 = prev_i * 2;
unsigned int b1 = t1 + 1;
unsigned int t2 = i * 2;
unsigned int b2 = t2 + 1;
model.indices.emplace_back(t1, b1, t2);
model.indices.emplace_back(b2, t2, b1);
prev_i = i;
}
return model;
}
// Be careful it is not water tide and contain self intersections
// It is only for visualization purposes
indexed_triangle_set its_create_torus(const Slic3r::Polygon &polygon, float radius, size_t steps = 20)
{
assert(!polygon.empty());
@ -117,11 +75,6 @@ indexed_triangle_set its_create_torus(const Slic3r::Polygon &polygon, float radi
Vec2f dir = prev + next;
return Vec2f(-dir.x(), dir.y());
};
std::vector<Vec2f> points_norm(points_d.size());
points_norm.front() = calc_norm(line_norm.back(), line_norm[1]);
for (size_t i = 1; i < points_d.size() - 1; ++i)
points_norm[i] = calc_norm(line_norm[i - 1], line_norm[i + 1]);
points_norm.back() = calc_norm(line_norm[points_d.size() - 2], line_norm.front());
// precalculate sinus and cosinus
double angle_step = 2 * M_PI / steps;
@ -135,38 +88,73 @@ indexed_triangle_set its_create_torus(const Slic3r::Polygon &polygon, float radi
);
}
indexed_triangle_set sphere = its_make_sphere(radius, 2 * PI / steps);
// create torus model along polygon path
indexed_triangle_set model;
model.vertices.reserve(steps * count);
model.indices.reserve(2 * steps * count);
model.vertices.reserve(2 * steps * count + sphere.vertices.size()*count);
model.indices.reserve(2 * steps * count + sphere.indices.size()*count);
const Vec2f *prev_prev_point_d = &points_d[count-2]; // one before back
const Vec2f *prev_point_d = &points_d.back();
auto calc_angle = [](const Vec2f &d0, const Vec2f &d1) {
double dot = d0.dot(d1);
double det = d0.x() * d1.y() - d0.y() * d1.x(); // Determinant
return std::atan2(det, dot); // atan2(y, x) or atan2(sin, cos)
};
// opposit previos direction of line - for calculate angle
Vec2f opposit_prev_dir = (*prev_prev_point_d) - (*prev_point_d);
for (size_t i = 0; i < count; ++i) {
const Vec2f point_d = points_d[i];
const Vec2f norm = points_norm[i];
const Vec2f & point_d = points_d[i];
// line segment direction
Vec2f dir = point_d - (*prev_point_d);
double angle = calc_angle(opposit_prev_dir, dir);
double allowed_preccission = 1e-6;
if (angle >= (PI - allowed_preccission) ||
angle <= (-PI + allowed_preccission))
continue; // it is almost line
// perpendicular direction to line
Vec2d p_dir(dir.y(), -dir.x());
p_dir.normalize(); // Should done with double preccission
// p_dir is tube unit side vector
// tube unit top vector is z direction
// Tube
int prev_index = model.vertices.size() + 2 * sin_cos.size() - 2;
for (const auto &[s, c] : sin_cos) {
Vec2f xy = s * norm + point_d;
model.vertices.emplace_back(xy.x(), xy.y(), c);
Vec2f side = (s * p_dir).cast<float>();
Vec2f xy0 = side + (*prev_point_d);
Vec2f xy1 = side + point_d;
model.vertices.emplace_back(xy0.x(), xy0.y(), c); // pointing of prev index
model.vertices.emplace_back(xy1.x(), xy1.y(), c);
// create triangle indices
int f0 = prev_index;
int s0 = f0 + 1;
int f1 = model.vertices.size() - 2;
int s1 = f1 + 1;
prev_index = f1;
model.indices.emplace_back(s0, f0, s1);
model.indices.emplace_back(f1, s1, f0);
}
prev_prev_point_d = prev_point_d;
prev_point_d = &point_d;
opposit_prev_dir = -dir;
}
unsigned int prev_i = count - 1;
for (unsigned int i = 0; i < count; ++i) {
// TODO: solve <180, =180 and >180 angle
// to not create self intersection
// t .. top
// b .. bottom
unsigned int prev_t = (prev_i+1) * steps - 1;
unsigned int t = (i+1) * steps - 1;
for (size_t s = 0; s < steps; ++s) {
unsigned int prev_b = prev_i * steps + s;
unsigned int b = i * steps + s;
model.indices.emplace_back(prev_t, prev_b, t);
model.indices.emplace_back(b, t, prev_b);
prev_t = prev_b;
t = b;
}
prev_i = i;
// sphere on each point
for (Vec2f& p: points_d){
indexed_triangle_set sphere_copy = sphere;
its_translate(sphere_copy, Vec3f(p.x(), p.y(), 0.f));
its_merge(model, sphere_copy);
}
return model;
}
@ -194,7 +182,8 @@ TextLines select_closest_contour(const std::vector<Polygons> &line_contours) {
size_t line_idx;
Vec2d hit_point;
double distance = AABBTreeLines::squared_distance_to_indexed_lines(linesf, tree, zero, line_idx, hit_point);
// double distance =
AABBTreeLines::squared_distance_to_indexed_lines(linesf, tree, zero, line_idx, hit_point);
// conversion between index of point and expolygon
ExPolygonsIndices cvt(expolygons);
@ -213,16 +202,14 @@ TextLines select_closest_contour(const std::vector<Polygons> &line_contours) {
inline Eigen::AngleAxis<double> get_rotation() { return Eigen::AngleAxis(-M_PI_2, Vec3d::UnitX()); }
indexed_triangle_set create_its(const TextLines &lines)
indexed_triangle_set create_its(const TextLines &lines, float radius)
{
const float model_half_width = 0.75; // [in volume mm]
indexed_triangle_set its;
// create model from polygons
for (const TextLine &line : lines) {
const Slic3r::Polygon &polygon = line.polygon;
if (polygon.empty()) continue;
indexed_triangle_set line_its = its_create_belt(polygon, model_half_width);
//indexed_triangle_set line_its = its_create_torus(polygon, model_half_width);
indexed_triangle_set line_its = its_create_torus(polygon, radius);
auto transl = Eigen::Translation3d(0., line.y, 0.);
Transform3d tr = transl * get_rotation();
its_transform(line_its, tr);
@ -231,9 +218,9 @@ indexed_triangle_set create_its(const TextLines &lines)
return its;
}
GLModel::Geometry create_geometry(const TextLines &lines)
GLModel::Geometry create_geometry(const TextLines &lines, float radius)
{
indexed_triangle_set its = create_its(lines);
indexed_triangle_set its = create_its(lines, radius);
GLModel::Geometry geometry;
geometry.format = {GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3};
@ -280,7 +267,9 @@ void TextLinesModel::init(const Transform3d &text_tr,
m_model.reset();
m_lines.clear();
double first_line_center = this->offset + line_height_mm / 3 + get_align_y_offset_in_mm(align, count_lines, ff, fp);
// size_in_mm .. contain volume scale and should be ascent value in mm
double line_offset = fp.size_in_mm * ascent_ratio_offset;
double first_line_center = line_offset + get_align_y_offset_in_mm(align, count_lines, ff, fp);
std::vector<float> line_centers(count_lines);
for (size_t i = 0; i < count_lines; ++i)
line_centers[i] = static_cast<float>(first_line_center - i * line_height_mm);
@ -326,8 +315,9 @@ void TextLinesModel::init(const Transform3d &text_tr,
for (size_t i = 0; i < count_lines; ++i)
m_lines[i].y = line_centers[i];
float radius = static_cast<float>(line_height_mm / 20.);
//*
GLModel::Geometry geometry = create_geometry(m_lines);
GLModel::Geometry geometry = create_geometry(m_lines, radius);
if (geometry.vertices_count() == 0 || geometry.indices_count() == 0)
return;
m_model.init_from(std::move(geometry));

View File

@ -17,9 +17,6 @@ namespace Slic3r::GUI {
class TextLinesModel
{
public:
// line offset in y direction (up/down)
float offset = 0;
/// <summary>
/// Initialize model and lines
/// </summary>
@ -41,6 +38,11 @@ private:
// Keep model for visualization text lines
GLModel m_model;
// Used to move slice (text line) on place where is approx vertical center of text
// When copy value const double ASCENT_CENTER from Emboss.cpp and Vertical align is center than
// text line will cross object center
const double ascent_ratio_offset = 1/3.;
};
} // namespace Slic3r::GUI