mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 20:15:55 +08:00
Fix emboss of polygons with same point in shape.
This commit is contained in:
parent
867c1bd2e0
commit
f282d62163
@ -12,10 +12,10 @@
|
|||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
|
||||||
// do not expose out of this file stbtt_ data types
|
// do not expose out of this file stbtt_ data types
|
||||||
class Privat
|
class Private
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Privat() = delete;
|
Private() = delete;
|
||||||
|
|
||||||
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::Font &font);
|
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::Font &font);
|
||||||
static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness = 2.f);
|
static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness = 2.f);
|
||||||
@ -23,9 +23,17 @@ public:
|
|||||||
Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt);
|
Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt);
|
||||||
|
|
||||||
static FontItem create_font_item(std::wstring name, std::wstring path);
|
static FontItem create_font_item(std::wstring name, std::wstring path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TODO: move to ExPolygon utils
|
||||||
|
/// Remove multi points. When exist multi point dilate it by rect 3x3 and union result.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="expolygons">Shape which can contain same point, will be extended by dilatation rects</param>
|
||||||
|
/// <returns>ExPolygons with only unique points</returns>
|
||||||
|
static ExPolygons dilate_to_unique_points(ExPolygons &expolygons);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<stbtt_fontinfo> Privat::load_font_info(const Emboss::Font &font)
|
std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::Font &font)
|
||||||
{
|
{
|
||||||
int font_offset = stbtt_GetFontOffsetForIndex(font.buffer.data(), font.index);
|
int font_offset = stbtt_GetFontOffsetForIndex(font.buffer.data(), font.index);
|
||||||
if (font_offset < 0) {
|
if (font_offset < 0) {
|
||||||
@ -40,7 +48,7 @@ std::optional<stbtt_fontinfo> Privat::load_font_info(const Emboss::Font &font)
|
|||||||
return font_info;
|
return font_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Emboss::Glyph> Privat::get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness)
|
std::optional<Emboss::Glyph> Private::get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness)
|
||||||
{
|
{
|
||||||
int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter);
|
int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter);
|
||||||
if (glyph_index == 0) {
|
if (glyph_index == 0) {
|
||||||
@ -97,7 +105,7 @@ std::optional<Emboss::Glyph> Privat::get_glyph(stbtt_fontinfo &font_info, int un
|
|||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Emboss::Glyph> Privat::get_glyph(
|
std::optional<Emboss::Glyph> Private::get_glyph(
|
||||||
int unicode,
|
int unicode,
|
||||||
const Emboss::Font & font,
|
const Emboss::Font & font,
|
||||||
const FontProp & font_prop,
|
const FontProp & font_prop,
|
||||||
@ -110,12 +118,12 @@ std::optional<Emboss::Glyph> Privat::get_glyph(
|
|||||||
|
|
||||||
|
|
||||||
if (!font_info_opt.has_value()) {
|
if (!font_info_opt.has_value()) {
|
||||||
font_info_opt = Privat::load_font_info(font);
|
font_info_opt = Private::load_font_info(font);
|
||||||
// can load font info?
|
// can load font info?
|
||||||
if (!font_info_opt.has_value()) return {};
|
if (!font_info_opt.has_value()) return {};
|
||||||
}
|
}
|
||||||
std::optional<Emboss::Glyph> glyph_opt =
|
std::optional<Emboss::Glyph> glyph_opt =
|
||||||
Privat::get_glyph(*font_info_opt, unicode, font_prop.flatness);
|
Private::get_glyph(*font_info_opt, unicode, font_prop.flatness);
|
||||||
|
|
||||||
// IMPROVE: multiple loadig glyph without data
|
// IMPROVE: multiple loadig glyph without data
|
||||||
// has definition inside of font?
|
// has definition inside of font?
|
||||||
@ -124,11 +132,77 @@ std::optional<Emboss::Glyph> Privat::get_glyph(
|
|||||||
return glyph_opt;
|
return glyph_opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
FontItem Privat::create_font_item(std::wstring name, std::wstring path) {
|
FontItem Private::create_font_item(std::wstring name, std::wstring path) {
|
||||||
return FontItem(boost::nowide::narrow(name.c_str()),
|
return FontItem(boost::nowide::narrow(name.c_str()),
|
||||||
boost::nowide::narrow(path.c_str()));
|
boost::nowide::narrow(path.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExPolygons Private::dilate_to_unique_points(ExPolygons &expolygons)
|
||||||
|
{
|
||||||
|
std::set<Point> points;
|
||||||
|
std::set<Point> multi_points;
|
||||||
|
auto find_multipoint = [&points, &multi_points](const Points &pts) {
|
||||||
|
for (const Point &p : pts) {
|
||||||
|
auto it = points.find(p);
|
||||||
|
if (it != points.end())
|
||||||
|
multi_points.insert(p);
|
||||||
|
else
|
||||||
|
points.insert(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (const ExPolygon &expolygon : expolygons) {
|
||||||
|
find_multipoint(expolygon.contour.points);
|
||||||
|
for (const Slic3r::Polygon &hole : expolygon.holes)
|
||||||
|
find_multipoint(hole.points);
|
||||||
|
}
|
||||||
|
// speed up, no multipoints
|
||||||
|
if (multi_points.empty()) return expolygons;
|
||||||
|
|
||||||
|
// CCW rectangle around zero with size 3*3 px for dilatation
|
||||||
|
const Points rect_3_3{Point(1, 1), Point(-1, 1), Point(-1, -1), Point(1, -1)};
|
||||||
|
const Points rect_side{Point(1, 0), Point(0, 1), Point(-1, 0), Point(0, -1)};
|
||||||
|
|
||||||
|
// all new added points for reduction
|
||||||
|
std::set<Point> rects_points;
|
||||||
|
|
||||||
|
// extends expolygons with dilatation rectangle
|
||||||
|
expolygons.reserve(expolygons.size() + multi_points.size());
|
||||||
|
for (const Point &multi_point : multi_points) {
|
||||||
|
Slic3r::Polygon rect(rect_3_3); // copy points
|
||||||
|
rect.translate(multi_point);
|
||||||
|
for (const Point p : rect.points) rects_points.insert(p);
|
||||||
|
// add side point to be sure with result
|
||||||
|
for (const Point p : rect_side) rects_points.insert(p + multi_point);
|
||||||
|
expolygons.emplace_back(rect);
|
||||||
|
}
|
||||||
|
ExPolygons result = union_ex(expolygons);
|
||||||
|
|
||||||
|
// reduce new created close points
|
||||||
|
auto reduce_close_points = [&rects_points](Points &pts) {
|
||||||
|
bool is_first = false;
|
||||||
|
size_t offset = 0;
|
||||||
|
bool is_prev_rect = false;
|
||||||
|
for (size_t i = 0; i < pts.size(); i++) {
|
||||||
|
const Point &p = pts[i];
|
||||||
|
bool is_rect = (rects_points.find(p) != rects_points.end());
|
||||||
|
if (is_prev_rect && is_rect) ++offset;
|
||||||
|
if (offset != 0) pts[i - offset] = p;
|
||||||
|
if (i == 0 && is_rect) is_first = true;
|
||||||
|
is_prev_rect = is_rect;
|
||||||
|
}
|
||||||
|
// remove last
|
||||||
|
if (is_first && is_prev_rect) ++offset;
|
||||||
|
if (offset != 0)
|
||||||
|
pts.erase(pts.begin() + (pts.size() - offset), pts.end());
|
||||||
|
};
|
||||||
|
for (ExPolygon &expolygon : result) {
|
||||||
|
reduce_close_points(expolygon.contour.points);
|
||||||
|
for (Slic3r::Polygon &hole : expolygon.holes)
|
||||||
|
reduce_close_points(hole.points);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <wingdi.h>
|
#include <wingdi.h>
|
||||||
@ -255,7 +329,7 @@ FontList Emboss::get_font_list_by_register() {
|
|||||||
if (pos >= font_name_w.size()) continue;
|
if (pos >= font_name_w.size()) continue;
|
||||||
// remove TrueType text from name
|
// remove TrueType text from name
|
||||||
font_name_w = std::wstring(font_name_w, 0, pos);
|
font_name_w = std::wstring(font_name_w, 0, pos);
|
||||||
font_list.emplace_back(Privat::create_font_item(font_name_w, path_w));
|
font_list.emplace_back(Private::create_font_item(font_name_w, path_w));
|
||||||
} while (result != ERROR_NO_MORE_ITEMS);
|
} while (result != ERROR_NO_MORE_ITEMS);
|
||||||
delete[] font_name;
|
delete[] font_name;
|
||||||
delete[] fileTTF_name;
|
delete[] fileTTF_name;
|
||||||
@ -290,7 +364,7 @@ FontList Emboss::get_font_list_by_enumeration() {
|
|||||||
|
|
||||||
FontList font_list;
|
FontList font_list;
|
||||||
for (const std::wstring &font_name : font_names) {
|
for (const std::wstring &font_name : font_names) {
|
||||||
font_list.emplace_back(Privat::create_font_item(font_name, L""));
|
font_list.emplace_back(Private::create_font_item(font_name, L""));
|
||||||
}
|
}
|
||||||
return font_list;
|
return font_list;
|
||||||
}
|
}
|
||||||
@ -312,7 +386,7 @@ FontList Emboss::get_font_list_by_folder() {
|
|||||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
|
||||||
std::wstring file_name(fd.cFileName);
|
std::wstring file_name(fd.cFileName);
|
||||||
// TODO: find font name instead of filename
|
// TODO: find font name instead of filename
|
||||||
result.emplace_back(Privat::create_font_item(file_name, search_dir + file_name));
|
result.emplace_back(Private::create_font_item(file_name, search_dir + file_name));
|
||||||
} while (::FindNextFile(hFind, &fd));
|
} while (::FindNextFile(hFind, &fd));
|
||||||
::FindClose(hFind);
|
::FindClose(hFind);
|
||||||
}
|
}
|
||||||
@ -351,7 +425,7 @@ std::optional<Emboss::Font> Emboss::load_font(std::vector<unsigned char> data)
|
|||||||
res.index = 0;
|
res.index = 0;
|
||||||
res.count = index;
|
res.count = index;
|
||||||
|
|
||||||
auto font_info = Privat::load_font_info(res);
|
auto font_info = Private::load_font_info(res);
|
||||||
if (!font_info.has_value()) return {};
|
if (!font_info.has_value()) return {};
|
||||||
const stbtt_fontinfo *info = &(*font_info);
|
const stbtt_fontinfo *info = &(*font_info);
|
||||||
// load information about line gap
|
// load information about line gap
|
||||||
@ -434,9 +508,9 @@ std::optional<Emboss::Glyph> Emboss::letter2glyph(const Font &font,
|
|||||||
int letter,
|
int letter,
|
||||||
float flatness)
|
float flatness)
|
||||||
{
|
{
|
||||||
auto font_info_opt = Privat::load_font_info(font);
|
auto font_info_opt = Private::load_font_info(font);
|
||||||
if (!font_info_opt.has_value()) return {};
|
if (!font_info_opt.has_value()) return {};
|
||||||
return Privat::get_glyph(*font_info_opt, (int) letter, flatness);
|
return Private::get_glyph(*font_info_opt, (int) letter, flatness);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExPolygons Emboss::text2shapes(Font & font,
|
ExPolygons Emboss::text2shapes(Font & font,
|
||||||
@ -458,14 +532,14 @@ ExPolygons Emboss::text2shapes(Font & font,
|
|||||||
if (wc == '\t') {
|
if (wc == '\t') {
|
||||||
// '\t' = 4*space => same as imgui
|
// '\t' = 4*space => same as imgui
|
||||||
const int count_spaces = 4;
|
const int count_spaces = 4;
|
||||||
std::optional<Glyph> space_opt = Privat::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt);
|
std::optional<Glyph> space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt);
|
||||||
if (!space_opt.has_value()) continue;
|
if (!space_opt.has_value()) continue;
|
||||||
cursor.x() += count_spaces *(space_opt->advance_width + font_prop.char_gap);
|
cursor.x() += count_spaces *(space_opt->advance_width + font_prop.char_gap);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unicode = static_cast<int>(wc);
|
int unicode = static_cast<int>(wc);
|
||||||
std::optional<Glyph> glyph_opt = Privat::get_glyph(unicode, font, font_prop, font.cache, font_info_opt);
|
std::optional<Glyph> glyph_opt = Private::get_glyph(unicode, font, font_prop, font.cache, font_info_opt);
|
||||||
if (!glyph_opt.has_value()) continue;
|
if (!glyph_opt.has_value()) continue;
|
||||||
|
|
||||||
// move glyph to cursor position
|
// move glyph to cursor position
|
||||||
@ -475,8 +549,8 @@ ExPolygons Emboss::text2shapes(Font & font,
|
|||||||
cursor.x() += glyph_opt->advance_width + font_prop.char_gap;
|
cursor.x() += glyph_opt->advance_width + font_prop.char_gap;
|
||||||
expolygons_append(result, expolygons);
|
expolygons_append(result, expolygons);
|
||||||
}
|
}
|
||||||
return Slic3r::union_ex(result);
|
result = Slic3r::union_ex(result);
|
||||||
// TODO: simplify after union! Do NOT create 2 close vertices (may cause problem in triangulation)
|
return Private::dilate_to_unique_points(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
|
indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
|
||||||
|
@ -12,7 +12,7 @@ inline void insert_points(Points& points, const Polygon &polygon) {
|
|||||||
points.insert(points.end(), polygon.points.begin(), polygon.points.end());
|
points.insert(points.end(), polygon.points.begin(), polygon.points.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void insert_edge(Slic3r::Triangulation::HalfEdges &edges, uint32_t &offset, const Polygon &polygon) {
|
inline void insert_edge(Triangulation::HalfEdges &edges, uint32_t &offset, const Polygon &polygon) {
|
||||||
const Points &pts = polygon.points;
|
const Points &pts = polygon.points;
|
||||||
for (uint32_t i = 1; i < pts.size(); ++i) {
|
for (uint32_t i = 1; i < pts.size(); ++i) {
|
||||||
uint32_t i2 = i + offset;
|
uint32_t i2 = i + offset;
|
||||||
@ -52,13 +52,13 @@ Triangulation::Indices Triangulation::triangulate(const Points &points, const Ha
|
|||||||
}
|
}
|
||||||
|
|
||||||
// triangle can not contain forbiden edge
|
// triangle can not contain forbiden edge
|
||||||
for (const std::pair<uint32_t, uint32_t> &edge : half_edges) {
|
for (const HalfEdge &edge : half_edges) {
|
||||||
const CDT::Vertex_handle &vh1 = vertices_handle[edge.first];
|
const CDT::Vertex_handle &vh1 = vertices_handle[edge.first];
|
||||||
const CDT::Vertex_handle &vh2 = vertices_handle[edge.second];
|
const CDT::Vertex_handle &vh2 = vertices_handle[edge.second];
|
||||||
cdt.insert_constraint(vh1, vh2);
|
cdt.insert_constraint(vh1, vh2);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto faces = cdt.finite_face_handles();
|
auto faces = cdt.finite_face_handles();
|
||||||
std::vector<Vec3i> indices;
|
std::vector<Vec3i> indices;
|
||||||
indices.reserve(faces.size());
|
indices.reserve(faces.size());
|
||||||
for (CDT::Face_handle face : faces) {
|
for (CDT::Face_handle face : faces) {
|
||||||
|
@ -20,8 +20,9 @@ public:
|
|||||||
using Indices = std::vector<Vec3i>;
|
using Indices = std::vector<Vec3i>;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connect points by triangulation to create filled surface by triangle
|
/// Connect points by triangulation to create filled surface by triangles
|
||||||
/// indices
|
/// Input points have to be unique
|
||||||
|
/// Inspiration for make unique points is Emboss::dilate_to_unique_points
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="points">Points to connect</param>
|
/// <param name="points">Points to connect</param>
|
||||||
/// <param name="edges">Constraint for edges, pair is from point(first) to
|
/// <param name="edges">Constraint for edges, pair is from point(first) to
|
||||||
|
@ -307,7 +307,7 @@ void GLGizmoEmboss::initialize()
|
|||||||
|
|
||||||
void GLGizmoEmboss::load_font_list()
|
void GLGizmoEmboss::load_font_list()
|
||||||
{
|
{
|
||||||
AppConfig *cfg = wxGetApp().app_config;
|
const AppConfig *cfg = wxGetApp().app_config;
|
||||||
std::string font_list_str = cfg->get(AppConfig::SECTION_EMBOSS, M_APP_CFG_FONT_LIST);
|
std::string font_list_str = cfg->get(AppConfig::SECTION_EMBOSS, M_APP_CFG_FONT_LIST);
|
||||||
if (!font_list_str.empty()) {
|
if (!font_list_str.empty()) {
|
||||||
std::optional<FontList> fl = TextConfigurationSerialization::deserialize_font_list(font_list_str);
|
std::optional<FontList> fl = TextConfigurationSerialization::deserialize_font_list(font_list_str);
|
||||||
@ -598,9 +598,8 @@ void GLGizmoEmboss::draw_font_list()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoEmboss::draw_text_input() {
|
void GLGizmoEmboss::draw_text_input()
|
||||||
|
{
|
||||||
|
|
||||||
static const ImGuiInputTextFlags flags =
|
static const ImGuiInputTextFlags flags =
|
||||||
ImGuiInputTextFlags_AllowTabInput |
|
ImGuiInputTextFlags_AllowTabInput |
|
||||||
ImGuiInputTextFlags_AutoSelectAll ;
|
ImGuiInputTextFlags_AutoSelectAll ;
|
||||||
@ -764,7 +763,6 @@ void GLGizmoEmboss::load_imgui_font() {
|
|||||||
builder.AddRanges(m_imgui->get_glyph_ranges());
|
builder.AddRanges(m_imgui->get_glyph_ranges());
|
||||||
builder.AddText(m_text.c_str());
|
builder.AddText(m_text.c_str());
|
||||||
|
|
||||||
// must live same as font in atlas
|
|
||||||
m_imgui_font_ranges.clear();
|
m_imgui_font_ranges.clear();
|
||||||
builder.BuildRanges(&m_imgui_font_ranges);
|
builder.BuildRanges(&m_imgui_font_ranges);
|
||||||
int font_size = static_cast<int>(
|
int font_size = static_cast<int>(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user