One GLModel for all lines

This commit is contained in:
Filip Sykala - NTB T15p 2023-05-02 12:26:58 +02:00
parent b7549ae414
commit 7fa1e39fec
6 changed files with 181 additions and 109 deletions

View File

@ -1207,6 +1207,15 @@ std::optional<Glyph> Emboss::letter2glyph(const FontFile &font,
return priv::get_glyph(*font_info_opt, letter, flatness);
}
int Emboss::get_line_height(const FontFile &font, const FontProp &prop) {
unsigned int font_index = prop.collection_number.value_or(0);
assert(priv::is_valid(font, font_index));
const FontFile::Info &info = font.infos[font_index];
int line_height = info.ascent - info.descent + info.linegap;
line_height += prop.line_gap.value_or(0);
return static_cast<int>(line_height / SHAPE_SCALE);
}
namespace {
ExPolygons letter2shapes(
@ -1220,16 +1229,9 @@ ExPolygons letter2shapes(
const FontFile &font = *font_with_cache.font_file;
if (letter == '\n') {
unsigned int font_index = font_prop.collection_number.value_or(0);
assert(priv::is_valid(font, font_index));
const FontFile::Info &info = font.infos[font_index];
int line_height = info.ascent - info.descent + info.linegap;
if (font_prop.line_gap.has_value())
line_height += *font_prop.line_gap;
line_height = static_cast<int>(line_height / SHAPE_SCALE);
cursor.x() = 0;
cursor.y() -= line_height;
// 2d shape has opposit direction of y
cursor.y() -= get_line_height(font, font_prop);
return {};
}
if (letter == '\t') {

View File

@ -154,6 +154,7 @@ namespace Emboss
ExPolygons text2shapes (FontFileWithCache &font, const char *text, const FontProp &font_prop, const std::function<bool()> &was_canceled = []() {return false;});
std::vector<ExPolygons> text2vshapes(FontFileWithCache &font, const std::wstring& text, const FontProp &font_prop, const std::function<bool()>& was_canceled = []() {return false;});
/// Sum of character '\n'
unsigned get_count_lines(const std::wstring &ws);
unsigned get_count_lines(const std::string &text);
@ -226,6 +227,14 @@ namespace Emboss
/// <returns>Conversion to mm</returns>
double get_shape_scale(const FontProp &fp, const FontFile &ff);
/// <summary>
/// Read from font file and properties height of line with spacing
/// </summary>
/// <param name="font">Infos for collections</param>
/// <param name="prop">Collection index + Additional line gap</param>
/// <returns>Line height with spacing in ExPolygon size</returns>
int get_line_height(const FontFile &font, const FontProp &prop);
/// <summary>
/// Project spatial point
/// </summary>

View File

@ -1020,6 +1020,26 @@ EmbossStyles GLGizmoEmboss::create_default_styles()
return styles;
}
void GLGizmoEmboss::init_text_lines(){
assert(m_style_manager.is_active_font());
if (!m_style_manager.is_active_font())
return;
const auto& ffc = m_style_manager.get_font_file_with_cache();
assert(ffc.has_value());
if (!ffc.has_value())
return;
const auto &ff_ptr = ffc.font_file;
assert(ff_ptr != nullptr);
if (ff_ptr == nullptr)
return;
const FontProp& fp = m_style_manager.get_font_prop();
const FontFile &ff = *ff_ptr;
double line_height = TextLinesModel::calc_line_height(ff, fp);
m_text_lines.init(m_parent.get_selection(), line_height);
}
void GLGizmoEmboss::set_volume_by_selection()
{
const Selection &selection = m_parent.get_selection();
@ -1155,7 +1175,7 @@ void GLGizmoEmboss::set_volume_by_selection()
}
if (tc.style.prop.per_glyph)
m_text_lines.init(m_parent.get_selection());
init_text_lines();
m_text = tc.text;
m_volume = volume;
@ -3163,7 +3183,7 @@ void GLGizmoEmboss::draw_advanced()
if (ImGui::Checkbox("##PerGlyph", per_glyph)) {
if (*per_glyph) {
if (!m_text_lines.is_init())
m_text_lines.init(m_parent.get_selection());
init_text_lines();
}
exist_change = true;
} else if (ImGui::IsItemHovered()) {
@ -3172,7 +3192,7 @@ void GLGizmoEmboss::draw_advanced()
} else {
ImGui::SetTooltip("%s", _u8L("Set position and orientation of projection per Glyph.").c_str());
if (!m_text_lines.is_init())
m_text_lines.init(m_parent.get_selection());
init_text_lines();
}
} else if (!*per_glyph && m_text_lines.is_init())
m_text_lines.reset();

View File

@ -314,6 +314,7 @@ private:
// Keep information about curvature of text line around surface
TextLinesModel m_text_lines;
void init_text_lines();
// Rotation gizmo
GLGizmoRotate m_rotate_gizmo;

View File

@ -45,10 +45,54 @@ const Slic3r::Polygon *largest(const Slic3r::Polygons &polygons)
return result;
}
GLModel create_model(const Slic3r::Polygon &polygon, float width_half = 0.5f, ColorRGBA color = ColorRGBA(0.f, 1.f, .2f, 0.5f))
indexed_triangle_set create_its(const Slic3r::Polygon &polygon, float width_half) {
// Improve: Create torus instead of flat 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;
}
/* GLModel create_model(const Slic3r::Polygon &polygon, float width_half = 0.5f, ColorRGBA color = ColorRGBA(0.f, 1.f, .2f, 0.5f))
{
// Improve: Create torus instead of flat path (with model overlaps)
assert(!polygon.empty());
if (polygon.empty())
return {};
@ -92,62 +136,86 @@ GLModel create_model(const Slic3r::Polygon &polygon, float width_half = 0.5f, Co
prev_i = i;
}
// line .. y offset from volume(define line for sliced polygon)
GLModel gl_model;
gl_model.init_from(std::move(init_data));
return gl_model;
}*/
// select closest contour for each line
TextLines select_closest_contour(const std::vector<Polygons> &line_contours) {
TextLines result;
result.reserve(line_contours.size());
Vec2d zero(0., 0.);
for (const Polygons &polygons : line_contours){
if (polygons.empty()) {
result.emplace_back();
continue;
}
// Improve: use int values and polygons only
// Slic3r::Polygons polygons = union_(polygons);
// std::vector<Slic3r::Line> lines = to_lines(polygons);
// AABBTreeIndirect::Tree<2, Point> tree;
// size_t line_idx;
// Point hit_point;
// Point::Scalar distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, point, line_idx, hit_point);
ExPolygons expolygons = union_ex(polygons);
std::vector<Linef> linesf = to_linesf(expolygons);
AABBTreeIndirect::Tree2d tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
size_t line_idx;
Vec2d 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);
ExPolygonsIndex index = cvt.cvt(static_cast<uint32_t>(line_idx));
const Slic3r::Polygon& polygon = index.is_contour() ?
expolygons[index.expolygons_index].contour :
expolygons[index.expolygons_index].holes[index.hole_index()];
Point hit_point_int = hit_point.cast<Point::coord_type>();
TextLine tl{polygon, index.point_index, hit_point_int};
result.emplace_back(tl);
}
return result;
}
GLModel create_model(const Polygons &polygons, float width_half = 0.5f, ColorRGBA color = ColorRGBA(0.f, 1.f, .2f, 0.5f))
GLModel create_model(const TextLines &lines, const std::vector<float> &line_centers)
{
assert(!polygons.empty());
double model_half_width = 0.5; // [in volume mm]
ColorRGBA color(.7f, .7f, .7f, .7f); // Gray
// add a small positive offset to avoid z-fighting
float offset = static_cast<float>(scale_(0.015f));
Polygons polygons_expanded = expand(polygons, offset);
indexed_triangle_set its;
auto rot = Eigen::AngleAxis(M_PI_2, Vec3d::UnitX());
// inspired by 3DScene.cpp void GLVolume::SinkingContours::update()
GLModel::Geometry init_data;
init_data.format = {GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3};
init_data.color = color;
size_t count = count_points(polygons);
init_data.reserve_vertices(2 * count);
init_data.reserve_indices(2 * count);
unsigned int vertices_counter = 0;
for (const Slic3r::Polygon &polygon : polygons_expanded) {
for (const Point &point : polygon.points) {
Vec2f point_d = unscale(point).cast<float>();
Vec3f vertex(point_d.x(), point_d.y(), width_half);
init_data.add_vertex(vertex);
vertex.z() *= -1;
init_data.add_vertex(vertex);
}
auto points_count = static_cast<unsigned int>(polygon.points.size());
unsigned int prev_i = points_count - 1;
for (unsigned int i = 0; i < points_count; i++) {
// t .. top
// b .. bottom
unsigned int t1 = vertices_counter + prev_i * 2;
unsigned int b1 = t1 + 1;
unsigned int t2 = vertices_counter + i * 2;
unsigned int b2 = t2 + 1;
init_data.add_triangle(t1, b1, t2);
init_data.add_triangle(b2, t2, b1);
prev_i = i;
}
vertices_counter += 2 * points_count;
assert(lines.size() == line_centers.size());
// create model from polygons
for (size_t i = 0; i < lines.size(); ++i) {
const Slic3r::Polygon &polygon = lines[i].polygon;
if (polygon.empty()) continue;
double line_center = line_centers[i];
indexed_triangle_set line_its = create_its(polygon, model_half_width);
auto transl = Eigen::Translation3d(0., -line_center, 0.);
Transform3d tr = transl * rot;
its_transform(line_its, tr);
its_merge(its, line_its);
}
GLModel gl_model;
gl_model.init_from(std::move(init_data));
gl_model.init_from(its);
gl_model.set_color(color);
return gl_model;
}
} // namespace
void TextLinesModel::init(const Selection &selection)
void TextLinesModel::init(const Selection &selection, double line_height)
{
const GLVolume *gl_volume_ptr = selection.get_first_volume();
if (gl_volume_ptr == nullptr)
@ -172,13 +240,10 @@ void TextLinesModel::init(const Selection &selection)
if (count_lines == 0)
return;
// TODO: Calc correct line height by line gap + font file info
// Be carefull it is not correct !!!
double line_height = tc_opt->style.prop.size_in_mm;
double first_line_center = -(count_lines / 2) * line_height - ((count_lines % 2 == 0)? line_height/2. : 0.);
double first_line_center = -((count_lines / 2) * line_height) - ((count_lines % 2 == 0)? line_height/2. : 0.);
std::vector<float> line_centers(count_lines);
for (size_t i = 0; i < count_lines; ++i)
line_centers[i] = first_line_center + i * line_height;
line_centers[i] = static_cast<float>(first_line_center + i * line_height);
const Transform3d &mv_trafo = gl_volume.get_volume_transformation().get_matrix();
@ -209,48 +274,13 @@ void TextLinesModel::init(const Selection &selection)
}
}
lines.reserve(count_lines);
lines.clear();
// select closest contour
Vec2d zero(0., 0.);
for (const Polygons &polygons : line_contours) {
// Improve: use int values and polygons only
// Slic3r::Polygons polygons = union_(polygons);
// std::vector<Slic3r::Line> lines = to_lines(polygons);
// AABBTreeIndirect::Tree<2, Point> tree;
// size_t line_idx;
// Point hit_point;
// Point::Scalar distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, point, line_idx, hit_point);
ExPolygons expolygons = union_ex(polygons);
std::vector<Linef> linesf = to_linesf(expolygons);
AABBTreeIndirect::Tree2d tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(linesf);
size_t line_idx;
Vec2d 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);
ExPolygonsIndex index = cvt.cvt(static_cast<uint32_t>(line_idx));
const Polygon& polygon = index.is_contour() ? expolygons[index.expolygons_index].contour :
expolygons[index.expolygons_index].holes[index.hole_index()];
Point hit_point_int = hit_point.cast<Point::coord_type>();
TextLine tl{polygon, index.point_index, hit_point_int};
lines.emplace_back(tl);
}
ColorRGBA color(.7f, .7f, .7f, .7f); // Gray
// TODO: create model from all lines
model = create_model(lines.front().polygon, 0.7f, color);
m_lines = select_closest_contour(line_contours);
m_model = create_model(m_lines, line_centers);
}
void TextLinesModel::render(const Transform3d &text_world)
{
if (!model.is_initialized())
if (!m_model.is_initialized())
return;
GUI_App &app = wxGetApp();
@ -259,10 +289,9 @@ void TextLinesModel::render(const Transform3d &text_world)
return;
const Camera &camera = app.plater()->get_camera();
auto rot = Eigen::AngleAxis(M_PI_2, Vec3d::UnitX());
shader->start_using();
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * text_world * rot);
shader->set_uniform("view_model_matrix", camera.get_view_matrix() * text_world);
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
bool is_depth_test = glIsEnabled(GL_DEPTH_TEST);
@ -274,7 +303,7 @@ void TextLinesModel::render(const Transform3d &text_world)
glsafe(::glEnable(GL_BLEND));
// glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
model.render();
m_model.render();
if (!is_depth_test)
glsafe(::glDisable(GL_DEPTH_TEST));
@ -283,3 +312,10 @@ void TextLinesModel::render(const Transform3d &text_world)
shader->stop_using();
}
double TextLinesModel::calc_line_height(const Slic3r::Emboss::FontFile &ff, const FontProp &fp)
{
int line_height = Emboss::get_line_height(ff, fp); // In shape size
double scale = Emboss::get_shape_scale(fp, ff);
return line_height * scale;
}

View File

@ -2,10 +2,12 @@
#define slic3r_TextLines_hpp_
#include <vector>
#include "libslic3r/Polygon.hpp"
#include "libslic3r/Point.hpp"
#include <libslic3r/Polygon.hpp>
#include <libslic3r/Point.hpp>
#include <libslic3r/Emboss.hpp>
#include "slic3r/GUI/GLModel.hpp"
namespace Slic3r::GUI {
class Selection;
@ -29,17 +31,19 @@ using TextLines = std::vector<TextLine>;
class TextLinesModel
{
public:
void init(const Selection &selection);
// line_height in mm
void init(const Selection &selection, double line_height);
void render(const Transform3d &text_world);
bool is_init() const { return model.is_initialized(); }
void reset() { model.reset(); }
const TextLines &get_lines() const { return lines; }
bool is_init() const { return m_model.is_initialized(); }
void reset() { m_model.reset(); }
const TextLines &get_lines() const { return m_lines; }
static double calc_line_height(const Slic3r::Emboss::FontFile& ff, const FontProp& fp);
private:
TextLines lines;
TextLines m_lines;
// Keep model for visualization text lines
GLModel model;
GLModel m_model;
};
} // namespace Slic3r::GUI