add is italic check for font file
This commit is contained in:
parent
82ee1c5e4a
commit
b1b8eee3c9
4 changed files with 82 additions and 81 deletions
|
@ -45,12 +45,12 @@ std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::Font &font)
|
|||
{
|
||||
int font_offset = stbtt_GetFontOffsetForIndex(font.buffer.data(), font.index);
|
||||
if (font_offset < 0) {
|
||||
std::cerr << "Font index("<<font.index<<") doesn't exist.";
|
||||
std::cerr << "Font index("<<font.index<<") doesn't exist." << std::endl;
|
||||
return {};
|
||||
}
|
||||
stbtt_fontinfo font_info;
|
||||
if (stbtt_InitFont(&font_info, font.buffer.data(), font_offset) == 0) {
|
||||
std::cerr << "Can't initialize font.";
|
||||
std::cerr << "Can't initialize font." << std::endl;
|
||||
return {};
|
||||
}
|
||||
return font_info;
|
||||
|
@ -437,7 +437,7 @@ std::optional<Emboss::Font> Emboss::load_font(std::vector<unsigned char> data)
|
|||
--index; // last one is bad
|
||||
// at least one font must be inside collection
|
||||
if (index < 1) {
|
||||
std::cerr << "There is no font collection inside data.";
|
||||
std::cerr << "There is no font collection inside data." << std::endl;
|
||||
return {};
|
||||
}
|
||||
// select default font on index 0
|
||||
|
@ -457,18 +457,18 @@ std::optional<Emboss::Font> Emboss::load_font(const char *file_path)
|
|||
{
|
||||
FILE *file = fopen(file_path, "rb");
|
||||
if (file == nullptr) {
|
||||
std::cerr << "Couldn't open " << file_path << " for reading.";
|
||||
std::cerr << "Couldn't open " << file_path << " for reading." << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
// find size of file
|
||||
if (fseek(file, 0L, SEEK_END) != 0) {
|
||||
std::cerr << "Couldn't fseek file " << file_path << " for size measure.";
|
||||
std::cerr << "Couldn't fseek file " << file_path << " for size measure." << std::endl;
|
||||
return {};
|
||||
}
|
||||
size_t size = ftell(file);
|
||||
if (size == 0) {
|
||||
std::cerr << "Size of font file is zero. Can't read.";
|
||||
std::cerr << "Size of font file is zero. Can't read." << std::endl;
|
||||
return {};
|
||||
}
|
||||
rewind(file);
|
||||
|
@ -476,7 +476,7 @@ std::optional<Emboss::Font> Emboss::load_font(const char *file_path)
|
|||
std::vector<unsigned char> buffer(size);
|
||||
size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file);
|
||||
if (count_loaded_bytes != size) {
|
||||
std::cerr << "Different loaded(from file) data size.";
|
||||
std::cerr << "Different loaded(from file) data size." << std::endl;
|
||||
return {};
|
||||
}
|
||||
return load_font(std::move(buffer));
|
||||
|
@ -488,7 +488,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
|
|||
{
|
||||
HDC hdc = ::CreateCompatibleDC(NULL);
|
||||
if (hdc == NULL) {
|
||||
std::cerr << "Can't create HDC by CreateCompatibleDC(NULL).";
|
||||
std::cerr << "Can't create HDC by CreateCompatibleDC(NULL)." << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -506,7 +506,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
|
|||
}
|
||||
|
||||
if (size == 0 || size == GDI_ERROR) {
|
||||
std::cerr << "HFONT doesn't have size.";
|
||||
std::cerr << "HFONT doesn't have size." << std::endl;
|
||||
::DeleteDC(hdc);
|
||||
return {};
|
||||
}
|
||||
|
@ -515,7 +515,7 @@ std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
|
|||
size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer.data(), size);
|
||||
::DeleteDC(hdc);
|
||||
if (size != loaded_size) {
|
||||
std::cerr << "Different loaded(from HFONT) data size.";
|
||||
std::cerr << "Different loaded(from HFONT) data size." << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -601,6 +601,43 @@ ExPolygons Emboss::text2shapes(Font & font,
|
|||
return Private::dilate_to_unique_points(result);
|
||||
}
|
||||
|
||||
bool Emboss::is_italic(Font &font) {
|
||||
std::optional<stbtt_fontinfo> font_info_opt =
|
||||
Private::load_font_info(font);
|
||||
|
||||
if (!font_info_opt.has_value()) return false;
|
||||
stbtt_fontinfo *info = &(*font_info_opt);
|
||||
|
||||
// https://docs.microsoft.com/cs-cz/typography/opentype/spec/name
|
||||
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html
|
||||
// 2 ==> Style / Subfamily name
|
||||
int name_id = 2;
|
||||
int length;
|
||||
const char* value = stbtt_GetFontNameString(info, &length,
|
||||
STBTT_PLATFORM_ID_MICROSOFT,
|
||||
STBTT_MS_EID_UNICODE_BMP,
|
||||
STBTT_MS_LANG_ENGLISH,
|
||||
name_id);
|
||||
|
||||
// value is big endian utf-16 i need extract only normal chars
|
||||
std::string value_str;
|
||||
value_str.reserve(length / 2);
|
||||
for (int i = 1; i < length; i += 2)
|
||||
value_str.push_back(value[i]);
|
||||
|
||||
// lower case
|
||||
std::transform(value_str.begin(), value_str.end(), value_str.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
|
||||
const std::vector<std::string> italics({"italic", "oblique"});
|
||||
for (const std::string &it : italics) {
|
||||
if (value_str.find(it) != std::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
indexed_triangle_set Emboss::polygons2model(const ExPolygons &shape2d,
|
||||
const IProject &projection)
|
||||
{
|
||||
|
|
|
@ -102,6 +102,14 @@ public:
|
|||
const char * text,
|
||||
const FontProp &font_prop);
|
||||
|
||||
/// <summary>
|
||||
/// Read information from naming table of font file
|
||||
/// search for italic (or oblique), bold italic (or bold oblique)
|
||||
/// </summary>
|
||||
/// <param name="font">Selector of font</param>
|
||||
/// <returns>True when the font description contains italic/obligue otherwise False</returns>
|
||||
static bool is_italic(Font &font);
|
||||
|
||||
/// <summary>
|
||||
/// Project 2d point into space
|
||||
/// Could be plane, sphere, cylindric, ...
|
||||
|
|
|
@ -177,4 +177,31 @@ TEST_CASE("triangle intersection", "[]")
|
|||
Vec2d i = Private::get_intersection(point, dir, triangle);
|
||||
CHECK(abs(i.x()) < std::numeric_limits<double>::epsilon());
|
||||
CHECK(abs(i.y() - 1.) < std::numeric_limits<double>::epsilon());
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
TEST_CASE("Italic check", "[]")
|
||||
{
|
||||
//std::string s1 = "italic";
|
||||
//std::string s2 = "italic";
|
||||
//auto pos = s1.find(s2);
|
||||
//std::cout << ((pos != std::string::npos) ? "good" : "bad");
|
||||
|
||||
std::string dir_path = "C:/Windows/Fonts";
|
||||
for (const auto &entry : fs::directory_iterator(dir_path)) {
|
||||
if (entry.is_directory()) continue;
|
||||
const fs::path& act_path = entry.path();
|
||||
std::string ext = act_path.extension().u8string();
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||
if (ext != ".ttf") continue;
|
||||
std::string path_str = act_path.u8string();
|
||||
auto font_opt = Emboss::load_font(path_str.c_str());
|
||||
if (!font_opt.has_value()) continue;
|
||||
|
||||
std::cout << ((Emboss::is_italic(*font_opt)) ? "[yes] " : "[no ] ")
|
||||
<< entry.path() << std::endl;
|
||||
}
|
||||
}
|
|
@ -215,50 +215,6 @@ bool is_similar(const indexed_triangle_set &from,
|
|||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("Reduce one edge by Quadric Edge Collapse", "[its]")
|
||||
{
|
||||
indexed_triangle_set its;
|
||||
its.vertices = {Vec3f(-1.f, 0.f, 0.f), Vec3f(0.f, 1.f, 0.f),
|
||||
Vec3f(1.f, 0.f, 0.f), Vec3f(0.f, 0.f, 1.f),
|
||||
// vertex to be removed
|
||||
Vec3f(0.9f, .1f, -.1f)};
|
||||
its.indices = {Vec3i(1, 0, 3), Vec3i(2, 1, 3), Vec3i(0, 2, 3),
|
||||
Vec3i(0, 1, 4), Vec3i(1, 2, 4), Vec3i(2, 0, 4)};
|
||||
// edge to remove is between vertices 2 and 4 on trinagles 4 and 5
|
||||
|
||||
indexed_triangle_set its_ = its; // copy
|
||||
// its_write_obj(its, "tetrhedron_in.obj");
|
||||
uint32_t wanted_count = its.indices.size() - 1;
|
||||
its_quadric_edge_collapse(its, wanted_count);
|
||||
// its_write_obj(its, "tetrhedron_out.obj");
|
||||
CHECK(its.indices.size() == 4);
|
||||
CHECK(its.vertices.size() == 4);
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
CHECK(its.indices[i] == its_.indices[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
if (i == 2) continue;
|
||||
CHECK(its.vertices[i] == its_.vertices[i]);
|
||||
}
|
||||
|
||||
const Vec3f &v = its.vertices[2]; // new vertex
|
||||
const Vec3f &v2 = its_.vertices[2]; // moved vertex
|
||||
const Vec3f &v4 = its_.vertices[4]; // removed vertex
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
bool is_between = (v[i] < v4[i] && v[i] > v2[i]) ||
|
||||
(v[i] > v4[i] && v[i] < v2[i]);
|
||||
CHECK(is_between);
|
||||
}
|
||||
CompareConfig cfg;
|
||||
cfg.max_average_distance = 0.014f;
|
||||
cfg.max_distance = 0.75f;
|
||||
|
||||
CHECK(is_similar(its, its_, cfg));
|
||||
CHECK(is_similar(its_, its, cfg));
|
||||
}
|
||||
|
||||
#include "test_utils.hpp"
|
||||
TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]")
|
||||
{
|
||||
|
@ -282,30 +238,3 @@ TEST_CASE("Simplify mesh by Quadric edge collapse to 5%", "[its]")
|
|||
CHECK(is_similar(its, mesh.its, cfg));
|
||||
}
|
||||
|
||||
bool exist_triangle_with_twice_vertices(const std::vector<stl_triangle_vertex_indices>& indices)
|
||||
{
|
||||
for (const auto &face : indices)
|
||||
if (face[0] == face[1] ||
|
||||
face[0] == face[2] ||
|
||||
face[1] == face[2]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("Simplify trouble case", "[its]")
|
||||
{
|
||||
TriangleMesh tm = load_model("simplification.obj");
|
||||
REQUIRE_FALSE(tm.empty());
|
||||
float max_error = std::numeric_limits<float>::max();
|
||||
uint32_t wanted_count = 0;
|
||||
its_quadric_edge_collapse(tm.its, wanted_count, &max_error);
|
||||
CHECK(!exist_triangle_with_twice_vertices(tm.its.indices));
|
||||
}
|
||||
|
||||
TEST_CASE("Simplified cube should not be empty.", "[its]")
|
||||
{
|
||||
auto its = its_make_cube(1, 2, 3);
|
||||
float max_error = std::numeric_limits<float>::max();
|
||||
uint32_t wanted_count = 0;
|
||||
its_quadric_edge_collapse(its, wanted_count, &max_error);
|
||||
CHECK(!its.indices.empty());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue