WIP: Create another approach to heal shape BUT it is not working

This commit is contained in:
Filip Sykala - NTB T15p 2023-01-20 17:33:53 +01:00
parent 8c2ac9d83b
commit 8f09c3ac82
6 changed files with 377 additions and 174 deletions

View file

@ -20,43 +20,79 @@
#include "libslic3r/BoundingBox.hpp"
using namespace Slic3r;
using namespace Emboss;
using fontinfo_opt = std::optional<stbtt_fontinfo>;
// do not expose out of this file stbtt_ data types
namespace priv{
bool is_valid(const Emboss::FontFile &font, unsigned int index);
std::optional<stbtt_fontinfo> load_font_info(const unsigned char *data, unsigned int index = 0);
std::optional<Emboss::Glyph> get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness);
using Polygon = Slic3r::Polygon;
bool is_valid(const FontFile &font, unsigned int index);
fontinfo_opt load_font_info(const unsigned char *data, unsigned int index = 0);
std::optional<Glyph> get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness);
// take glyph from cache
const Emboss::Glyph* get_glyph(int unicode, const Emboss::FontFile &font, const FontProp &font_prop,
Emboss::Glyphs &cache, std::optional<stbtt_fontinfo> &font_info_opt);
const Glyph* get_glyph(int unicode, const FontFile &font, const FontProp &font_prop,
Glyphs &cache, fontinfo_opt &font_info_opt);
EmbossStyle create_style(std::wstring name, std::wstring path);
// scale and convert float to int coordinate
Point to_point(const stbtt__point &point);
// bad is contour smaller than 3 points
void remove_bad(Polygons &polygons);
void remove_bad(ExPolygons &expolygons);
// helpr for heal shape
bool remove_same_neighbor(Slic3r::Points &points);
bool remove_same_neighbor(Slic3r::Polygons &polygons);
// Return true when erase otherwise false
bool remove_same_neighbor(Points &points);
bool remove_same_neighbor(Polygons &polygons);
bool remove_same_neighbor(ExPolygons &expolygons);
// Try to remove self intersection by subtracting rect 2x2 px
bool remove_self_intersections(ExPolygons &shape, unsigned max_iteration = 10);
ExPolygon create_bounding_rect(const ExPolygons &shape);
void remove_small_islands(ExPolygons &shape, double minimal_area);
// NOTE: expolygons can't contain same_neighbor
Points collect_close_points(const ExPolygons &expolygons, double distance = .6);
// Heal duplicates points and self intersections
bool heal_dupl_inter(ExPolygons &shape, unsigned max_iteration);
bool heal_dupl_inter2(ExPolygons &shape, unsigned max_iteration); // by close_ex
void visualize_heal(const std::string& svg_filepath, const ExPolygons &expolygons);
const Points pts_2x2({Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1)});
const Points pts_3x3({Point(-1, -1), Point(1, -1), Point(1, 1), Point(-1, 1)});
// Reduce number of Points in polygons with respect to flatness
// Flatness is area that could be modified
void simplify(Polygon &polygon, float flatness);
void simplify(Polygons &polygons, float flatness);
};
bool priv::is_valid(const Emboss::FontFile &font, unsigned int index) {
void priv::simplify(Polygon &polygon, float flatness) {
polygon.douglas_peucker(flatness);
}
void priv::simplify(Polygons &polygons, float flatness) {
for (Polygon &polygon : polygons)
simplify(polygon, flatness);
// simplification could ceate empty polygon
remove_bad(polygons);
}
bool priv::is_valid(const FontFile &font, unsigned int index) {
if (font.data == nullptr) return false;
if (font.data->empty()) return false;
if (index >= font.infos.size()) return false;
return true;
}
std::optional<stbtt_fontinfo> priv::load_font_info(
fontinfo_opt priv::load_font_info(
const unsigned char *data, unsigned int index)
{
int font_offset = stbtt_GetFontOffsetForIndex(data, index);
@ -74,6 +110,23 @@ std::optional<stbtt_fontinfo> priv::load_font_info(
return font_info;
}
void priv::remove_bad(Polygons &polygons) {
polygons.erase(
std::remove_if(polygons.begin(), polygons.end(),
[](const Polygon &p) { return p.size() < 3; }),
polygons.end());
}
void priv::remove_bad(ExPolygons &expolygons) {
expolygons.erase(
std::remove_if(expolygons.begin(), expolygons.end(),
[](const ExPolygon &p) { return p.contour.size() < 3; }),
expolygons.end());
for (ExPolygon &expolygon : expolygons)
remove_bad(expolygon.holes);
}
bool priv::remove_same_neighbor(Slic3r::Points &points)
{
if (points.empty()) return false;
@ -85,15 +138,15 @@ bool priv::remove_same_neighbor(Slic3r::Points &points)
return true;
}
bool priv::remove_same_neighbor(Slic3r::Polygons &polygons) {
bool priv::remove_same_neighbor(Polygons &polygons) {
if (polygons.empty()) return false;
bool exist = false;
for (Slic3r::Polygon& polygon : polygons)
for (Polygon& polygon : polygons)
exist |= remove_same_neighbor(polygon.points);
// remove empty polygons
polygons.erase(
std::remove_if(polygons.begin(), polygons.end(),
[](const Slic3r::Polygon &p) { return p.empty(); }),
[](const Polygon &p) { return p.empty(); }),
polygons.end());
return exist;
}
@ -104,19 +157,18 @@ bool priv::remove_same_neighbor(ExPolygons &expolygons) {
for (ExPolygon &expoly : expolygons) {
exist |= remove_same_neighbor(expoly.contour.points);
Polygons &holes = expoly.holes;
for (Slic3r::Polygon &hole : holes)
for (Polygon &hole : holes)
exist |= remove_same_neighbor(hole.points);
// remove empy holes
holes.erase(
std::remove_if(holes.begin(), holes.end(),
[](const Slic3r::Polygon &p) { return p.empty(); }),
[](const Polygon &p) { return p.size() < 3; }),
holes.end());
}
// remove empty contours
expolygons.erase(
std::remove_if(expolygons.begin(), expolygons.end(),
[](const ExPolygon &p) { return p.contour.empty(); }),
expolygons.end());
// Removing of point could create polygon with less than 3 points
if (exist)
remove_bad(expolygons);
return exist;
}
@ -145,7 +197,7 @@ Points priv::collect_close_points(const ExPolygons &expolygons, double distance)
// do not doubled side point of segment
const ExPolygonsIndex id = ids.cvt(index);
const ExPolygon &expoly = expolygons[id.expolygons_index];
const Slic3r::Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
const Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
const Points &poly_pts = poly.points;
const Point &line_a = poly_pts[id.point_index];
const Point &line_b = (!ids.is_last_point(id)) ? poly_pts[id.point_index + 1] : poly_pts.front();
@ -159,7 +211,7 @@ Points priv::collect_close_points(const ExPolygons &expolygons, double distance)
};
for (const ExPolygon &expoly : expolygons) {
collect_close(expoly.contour.points);
for (const Slic3r::Polygon &hole : expoly.holes)
for (const Polygon &hole : expoly.holes)
collect_close(hole.points);
}
if (res.empty()) return {};
@ -198,7 +250,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
// do not doubled side point of segment
const ExPolygonsIndex id = ids.cvt(index);
const ExPolygon &expoly = expolygons[id.expolygons_index];
const Slic3r::Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
const Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
const Points &poly_pts = poly.points;
const Point &line_a = poly_pts[id.point_index];
const Point &line_b = (!ids.is_last_point(id)) ? poly_pts[id.point_index + 1] : poly_pts.front();
@ -213,7 +265,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
};
for (const ExPolygon &expoly : expolygons) {
check_points(expoly.contour.points);
for (const Slic3r::Polygon &hole : expoly.holes)
for (const Polygon &hole : expoly.holes)
check_points(hole.points);
}
@ -235,7 +287,7 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
ExPolygonsIndex id = ids.cvt(index);
ExPolygon &expoly = expolygons[id.expolygons_index];
Slic3r::Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
Polygon &poly = id.is_contour() ? expoly.contour : expoly.holes[id.hole_index()];
Points &pts = poly.points;
size_t count = it2 - it;
@ -272,6 +324,62 @@ bool Emboss::divide_segments_for_close_point(ExPolygons &expolygons, double dist
return true;
}
bool priv::remove_self_intersections(ExPolygons &shape, unsigned max_iteration) {
if (shape.empty())
return true;
Pointfs intersections_f = intersection_points(shape);
if (intersections_f.empty())
return true;
// create loop permanent memory
Polygons holes;
Points intersections;
while (--max_iteration) {
// convert intersections into Points
assert(intersections.empty());
intersections.reserve(intersections_f.size());
std::transform(intersections_f.begin(), intersections_f.end(), std::back_inserter(intersections),
[](const Vec2d &p) { return Point(std::floor(p.x()), std::floor(p.y())); });
// intersections should be unique poits
std::sort(intersections.begin(), intersections.end());
auto it = std::unique(intersections.begin(), intersections.end());
intersections.erase(it, intersections.end());
assert(holes.empty());
holes.reserve(intersections.size());
// Fix self intersection in result by subtracting hole 2x2
for (const Point &p : intersections) {
Polygon hole(priv::pts_2x2);
hole.translate(p);
holes.push_back(hole);
}
// union overlapped holes
if (holes.size() > 1)
holes = Slic3r::union_(holes);
shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes);
// TODO: find where diff ex could create same neighbor
priv::remove_same_neighbor(shape);
// find new intersections made by diff_ex
intersections_f = intersection_points(shape);
if (intersections_f.empty())
return true;
else {
// clear permanent vectors
holes.clear();
intersections.clear();
}
}
assert(max_iteration == 0);
assert(!intersections_f.empty());
return false;
}
ExPolygons Emboss::heal_shape(const Polygons &shape) {
// When edit this code check that font 'ALIENATE.TTF' and glyph 'i' still work
// fix of self intersections
@ -287,7 +395,7 @@ ExPolygons Emboss::heal_shape(const Polygons &shape) {
if (!duplicits.empty()) {
polygons.reserve(polygons.size() + duplicits.size());
for (const Point &p : duplicits) {
Slic3r::Polygon rect_3x3(priv::pts_3x3);
Polygon rect_3x3(priv::pts_3x3);
rect_3x3.translate(p);
polygons.push_back(rect_3x3);
}
@ -301,97 +409,164 @@ ExPolygons Emboss::heal_shape(const Polygons &shape) {
return res;
}
void priv::visualize_heal(const std::string &svg_filepath, const ExPolygons &expolygons) {
double svg_scale = SHAPE_SCALE / unscale<double>(1.);
Points pts = to_points(expolygons);
BoundingBox bb(pts);
// bb.scale(svg_scale);
SVG svg(svg_filepath, bb);
svg.draw(expolygons);
Points duplicits = collect_duplicates(pts);
svg.draw(duplicits, "black", 7 / SHAPE_SCALE);
Pointfs intersections_f = intersection_points(expolygons);
Points intersections;
intersections.reserve(intersections_f.size());
std::transform(intersections_f.begin(), intersections_f.end(), std::back_inserter(intersections),
[](const Vec2d &p) { return p.cast<int>(); });
svg.draw(intersections, "red", 8 / SHAPE_SCALE);
}
bool Emboss::heal_shape(ExPolygons &shape, unsigned max_iteration)
{
return priv::heal_dupl_inter(shape, max_iteration);
//return priv::heal_dupl_inter2(shape, max_iteration);
}
bool priv::heal_dupl_inter(ExPolygons &shape, unsigned max_iteration)
{
if (shape.empty()) return true;
Slic3r::Polygons holes;
// create loop permanent memory
Polygons holes;
Points intersections;
while (--max_iteration) {
priv::remove_same_neighbor(shape);
Pointfs intersections_f = intersection_points(shape);
Pointfs intersections = intersection_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;
// convert intersections into Points
assert(intersections.empty());
intersections.reserve(intersections_f.size());
std::transform(intersections_f.begin(), intersections_f.end(), std::back_inserter(intersections),
[](const Vec2d &p) { return Point(std::floor(p.x()), std::floor(p.y())); });
holes.clear();
holes.reserve(intersections.size() + duplicits.size() /* + close.size()*/);
// intersections should be unique poits
std::sort(intersections.begin(), intersections.end());
auto it = std::unique(intersections.begin(), intersections.end());
intersections.erase(it, intersections.end());
Points duplicits = collect_duplicates(to_points(shape));
// duplicits are already uniqua and sorted
// Check whether shape is already healed
if (intersections.empty() && duplicits.empty())
return true;
assert(holes.empty());
holes.reserve(intersections.size() + duplicits.size());
// Fix self intersection in result by subtracting hole 2x2
for (const Vec2d &p : intersections) {
Slic3r::Polygon hole(priv::pts_2x2);
Point tr(std::floor(p.x()), std::floor(p.y()));
hole.translate(tr);
holes.push_back(hole);
}
// fix duplicit points by hole 3x3 around duplicit point
for (const Point &p : duplicits) {
Slic3r::Polygon hole(priv::pts_3x3);
for (const Point &p : intersections) {
Polygon hole(priv::pts_2x2);
hole.translate(p);
holes.push_back(hole);
}
// fix close points in simmilar way as duplicits
//for (const Point &p : close) {
// Slic3r::Polygon hole(priv::pts_3x3);
// hole.translate(p);
// holes.push_back(hole);
//}
// Fix duplicit points by hole 3x3 around duplicit point
for (const Point &p : duplicits) {
Polygon hole(priv::pts_3x3);
hole.translate(p);
holes.push_back(hole);
}
holes = Slic3r::union_(holes);
shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes);
}
/* VISUALIZATION of BAD symbols for debug
{
double svg_scale = Emboss::SHAPE_SCALE / unscale<double>(1.);
BoundingBox bb(to_points(shape));
//bb.scale(svg_scale);
SVG svg("C:/data/temp/fix_self_intersection.svg", bb);
svg.draw(shape);
// svg.draw(polygons, "orange");
svg.draw(shape, "green");
svg.draw(duplicits, "lightgray", 13 / Emboss::SHAPE_SCALE);
Points duplicits3 = collect_duplicates(to_points(shape));
svg.draw(duplicits3, "black", 7 / Emboss::SHAPE_SCALE);
Pointfs pts2 = intersection_points(shape);
Points pts_i; pts_i.reserve(pts2.size());
for (auto p : pts2) pts_i.push_back(p.cast<int>());
svg.draw(pts_i, "red", 8 / Emboss::SHAPE_SCALE);
} //*/
if (max_iteration == 0) {
assert(false);
BoundingBox bb = get_extents(shape);
Point size = bb.size();
if (size.x() < 10) bb.max.x() += 10;
if (size.y() < 10) bb.max.y() += 10;
Polygon rect({// CCW
bb.min,
{bb.max.x(), bb.min.y()},
bb.max,
{bb.min.x(), bb.max.y()}});
Point offset = bb.size() * 0.1;
Polygon hole({// CW
bb.min + offset,
{bb.min.x() + offset.x(), bb.max.y() - offset.y()},
bb.max - offset,
{bb.max.x() - offset.x(), bb.min.y() + offset.y()}});
// BAD symbol
shape = {ExPolygon(rect, hole)};
return false;
// prepare for next loop
holes.clear();
intersections.clear();
}
assert(intersection_points(shape).empty());
assert(collect_duplicates(to_points(shape)).empty());
return true;
// priv::visualize_heal("C:/data/temp/heal.svg", shape);
assert(false);
shape = {priv::create_bounding_rect(shape)};
return false;
}
std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness)
bool priv::heal_dupl_inter2(ExPolygons &shape, unsigned max_iteration) {
priv::remove_same_neighbor(shape);
const float delta = 2.f;
const ClipperLib::JoinType joinType = ClipperLib::JoinType::jtRound;
// remove double points
while (max_iteration) {
--max_iteration;
// if(!priv::remove_self_intersections(shape, max_iteration)) break;
shape = Slic3r::union_ex(shape);
shape = Slic3r::closing_ex(shape, delta, joinType);
// double minimal_area = 1000;
// priv::remove_small_islands(shape, minimal_area);
// check that duplicits and intersections do NOT exists
Points duplicits = collect_duplicates(to_points(shape));
Pointfs intersections_f = intersection_points(shape);
if (duplicits.empty() && intersections_f.empty())
return true;
}
// priv::visualize_heal("C:/data/temp/heal.svg", shape);
assert(false);
shape = {priv::create_bounding_rect(shape)};
return false;
}
ExPolygon priv::create_bounding_rect(const ExPolygons &shape) {
BoundingBox bb = get_extents(shape);
Point size = bb.size();
if (size.x() < 10)
bb.max.x() += 10;
if (size.y() < 10)
bb.max.y() += 10;
Polygon rect({// CCW
bb.min,
{bb.max.x(), bb.min.y()},
bb.max,
{bb.min.x(), bb.max.y()}});
Point offset = bb.size() * 0.1;
Polygon hole({// CW
bb.min + offset,
{bb.min.x() + offset.x(), bb.max.y() - offset.y()},
bb.max - offset,
{bb.max.x() - offset.x(), bb.min.y() + offset.y()}});
return ExPolygon(rect, hole);
}
void priv::remove_small_islands(ExPolygons &expolygons, double minimal_area) {
if (expolygons.empty())
return;
// remove small expolygons contours
auto expoly_it = std::remove_if(expolygons.begin(), expolygons.end(),
[&minimal_area](const ExPolygon &p) { return p.contour.area() < minimal_area; });
expolygons.erase(expoly_it, expolygons.end());
// remove small holes in expolygons
for (ExPolygon &expoly : expolygons) {
Polygons& holes = expoly.holes;
auto it = std::remove_if(holes.begin(), holes.end(),
[&minimal_area](const Polygon &p) { return -p.area() < minimal_area; });
holes.erase(it, holes.end());
}
}
std::optional<Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, int unicode_letter, float flatness)
{
int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter);
if (glyph_index == 0) {
@ -404,7 +579,7 @@ std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, in
return {};
}
Emboss::Glyph glyph;
Glyph glyph;
stbtt_GetGlyphHMetrics(&font_info, glyph_index, &glyph.advance_width, &glyph.left_side_bearing);
stbtt_vertex *vertices;
@ -447,6 +622,14 @@ std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, in
// change outer cw to ccw and inner ccw to cw order
std::reverse(pts.begin(), pts.end());
{ // use douglas peucker to reduce amount of used points
pts.push_back(pts.front());
pts = MultiPoint::_douglas_peucker(pts, flatness);
pts.pop_back();
if (pts.size() < 3)
continue;
}
glyph_polygons.emplace_back(pts);
}
if (!glyph_polygons.empty())
@ -454,12 +637,12 @@ std::optional<Emboss::Glyph> priv::get_glyph(const stbtt_fontinfo &font_info, in
return glyph;
}
const Emboss::Glyph* priv::get_glyph(
int unicode,
const Emboss::FontFile & font,
const FontProp & font_prop,
Emboss::Glyphs & cache,
std::optional<stbtt_fontinfo> &font_info_opt)
const Glyph* priv::get_glyph(
int unicode,
const FontFile & font,
const FontProp & font_prop,
Glyphs & cache,
fontinfo_opt &font_info_opt)
{
// TODO: Use resolution by printer configuration, or add it into FontProp
const float RESOLUTION = 0.0125f; // [in mm]
@ -482,7 +665,7 @@ const Emboss::Glyph* priv::get_glyph(
// Fix for very small flatness because it create huge amount of points from curve
if (flatness < RESOLUTION) flatness = RESOLUTION;
std::optional<Emboss::Glyph> glyph_opt =
std::optional<Glyph> glyph_opt =
priv::get_glyph(*font_info_opt, unicode, flatness);
// IMPROVE: multiple loadig glyph without data
@ -494,26 +677,26 @@ const Emboss::Glyph* priv::get_glyph(
// scale glyph size
glyph_opt->advance_width =
static_cast<int>(glyph_opt->advance_width / Emboss::SHAPE_SCALE);
static_cast<int>(glyph_opt->advance_width / SHAPE_SCALE);
glyph_opt->left_side_bearing =
static_cast<int>(glyph_opt->left_side_bearing / Emboss::SHAPE_SCALE);
static_cast<int>(glyph_opt->left_side_bearing / SHAPE_SCALE);
if (!glyph_opt->shape.empty()) {
if (font_prop.boldness.has_value()) {
float delta = *font_prop.boldness / Emboss::SHAPE_SCALE /
float delta = *font_prop.boldness / SHAPE_SCALE /
font_prop.size_in_mm;
glyph_opt->shape = Slic3r::union_ex(offset_ex(glyph_opt->shape, delta));
}
if (font_prop.skew.has_value()) {
const float &ratio = *font_prop.skew;
auto skew = [&ratio](Slic3r::Polygon &polygon) {
auto skew = [&ratio](Polygon &polygon) {
for (Slic3r::Point &p : polygon.points) {
p.x() += p.y() * ratio;
}
};
for (ExPolygon &expolygon : glyph_opt->shape) {
skew(expolygon.contour);
for (Slic3r::Polygon &hole : expolygon.holes) skew(hole);
for (Polygon &hole : expolygon.holes) skew(hole);
}
}
}
@ -529,8 +712,8 @@ EmbossStyle priv::create_style(std::wstring name, std::wstring path) {
}
Point priv::to_point(const stbtt__point &point) {
return Point(static_cast<int>(std::round(point.x / Emboss::SHAPE_SCALE)),
static_cast<int>(std::round(point.y / Emboss::SHAPE_SCALE)));
return Point(static_cast<int>(std::round(point.x / SHAPE_SCALE)),
static_cast<int>(std::round(point.y / SHAPE_SCALE)));
}
#ifdef _WIN32
@ -738,7 +921,7 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
}
#endif
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(
std::unique_ptr<FontFile> Emboss::create_font_file(
std::unique_ptr<std::vector<unsigned char>> data)
{
int collection_size = stbtt_GetNumberOfFonts(data->data());
@ -767,10 +950,10 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(
infos.emplace_back(FontFile::Info{ascent, descent, linegap, units_per_em});
}
return std::make_unique<Emboss::FontFile>(std::move(data), std::move(infos));
return std::make_unique<FontFile>(std::move(data), std::move(infos));
}
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(const char *file_path)
std::unique_ptr<FontFile> Emboss::create_font_file(const char *file_path)
{
FILE *file = std::fopen(file_path, "rb");
if (file == nullptr) {
@ -833,7 +1016,7 @@ static bool load_hfont(void* hfont, DWORD &dwTable, DWORD &dwOffset, size_t& siz
return true;
}
void * Emboss::can_load(HFONT hfont)
void *Emboss::can_load(void *hfont)
{
DWORD dwTable=0, dwOffset=0;
size_t size = 0;
@ -841,7 +1024,7 @@ void * Emboss::can_load(HFONT hfont)
return hfont;
}
std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
std::unique_ptr<FontFile> Emboss::create_font_file(void *hfont)
{
HDC hdc = ::CreateCompatibleDC(NULL);
if (hdc == NULL) {
@ -868,7 +1051,7 @@ std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
}
#endif // _WIN32
std::optional<Emboss::Glyph> Emboss::letter2glyph(const FontFile &font,
std::optional<Glyph> Emboss::letter2glyph(const FontFile &font,
unsigned int font_index,
int letter,
float flatness)
@ -885,7 +1068,7 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
std::function<bool()> was_canceled)
{
assert(font_with_cache.has_value());
std::optional<stbtt_fontinfo> font_info_opt;
fontinfo_opt font_info_opt;
Point cursor(0, 0);
ExPolygons result;
const FontFile& font = *font_with_cache.font_file;
@ -893,7 +1076,7 @@ ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
*font_prop.collection_number : 0;
if (!priv::is_valid(font, font_index)) return {};
const FontFile::Info& info = font.infos[font_index];
Emboss::Glyphs& cache = *font_with_cache.cache;
Glyphs& cache = *font_with_cache.cache;
std::wstring ws = boost::nowide::widen(text);
for (wchar_t wc: ws){
if (wc == '\n') {
@ -953,7 +1136,7 @@ void Emboss::apply_transformation(const FontProp &font_prop,
bool Emboss::is_italic(const FontFile &font, unsigned int font_index)
{
if (font_index >= font.infos.size()) return false;
std::optional<stbtt_fontinfo> font_info_opt = priv::load_font_info(font.data->data(), font_index);
fontinfo_opt font_info_opt = priv::load_font_info(font.data->data(), font_index);
if (!font_info_opt.has_value()) return false;
stbtt_fontinfo *info = &(*font_info_opt);
@ -1036,7 +1219,7 @@ double Emboss::get_shape_scale(const FontProp &fp, const FontFile &ff)
int unit_per_em = ff.infos[font_index].unit_per_em;
double scale = fp.size_in_mm / unit_per_em;
// Shape is scaled for store point coordinate as integer
return scale * Emboss::SHAPE_SCALE;
return scale * SHAPE_SCALE;
}
namespace priv {
@ -1055,7 +1238,7 @@ void add_quad(uint32_t i1,
indexed_triangle_set polygons2model_unique(
const ExPolygons &shape2d,
const Emboss::IProjection &projection,
const IProjection &projection,
const Points &points)
{
// CW order of triangle indices
@ -1091,7 +1274,7 @@ indexed_triangle_set polygons2model_unique(
// quads around - zig zag by triangles
size_t polygon_offset = 0;
auto add_quads = [&polygon_offset,&result, &count_point]
(const Slic3r::Polygon& polygon) {
(const Polygon& polygon) {
uint32_t polygon_points = polygon.points.size();
// previous index
uint32_t prev = polygon_offset + polygon_points - 1;
@ -1105,7 +1288,7 @@ indexed_triangle_set polygons2model_unique(
for (const ExPolygon &expolygon : shape2d) {
add_quads(expolygon.contour);
for (const Slic3r::Polygon &hole : expolygon.holes) add_quads(hole);
for (const Polygon &hole : expolygon.holes) add_quads(hole);
}
return result;
@ -1113,7 +1296,7 @@ indexed_triangle_set polygons2model_unique(
indexed_triangle_set polygons2model_duplicit(
const ExPolygons &shape2d,
const Emboss::IProjection &projection,
const IProjection &projection,
const Points &points,
const Points &duplicits)
{
@ -1161,7 +1344,7 @@ indexed_triangle_set polygons2model_duplicit(
// quads around - zig zag by triangles
size_t polygon_offset = 0;
auto add_quads = [&polygon_offset, &result, count_point, &changes]
(const Slic3r::Polygon &polygon) {
(const Polygon &polygon) {
uint32_t polygon_points = polygon.points.size();
// previous index
uint32_t prev = changes[polygon_offset + polygon_points - 1];
@ -1176,7 +1359,7 @@ indexed_triangle_set polygons2model_duplicit(
for (const ExPolygon &expolygon : shape2d) {
add_quads(expolygon.contour);
for (const Slic3r::Polygon &hole : expolygon.holes) add_quads(hole);
for (const Polygon &hole : expolygon.holes) add_quads(hole);
}
return result;
}