-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adapt meson build dependencies to support legacy libpodofo
Keep old pdf export implementation for libpodofo up to version 0.9.8. Meson build tries to detect the correct podofo version. With 0.10.0 it is possible to use pkgconfig. Signed-off-by: Frank Kunz <[email protected]>
- Loading branch information
Frank Kunz
committed
Oct 29, 2023
1 parent
3e89a09
commit 9727724
Showing
9 changed files
with
795 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,309 @@ | ||
#include "canvas_pdf.hpp" | ||
#include "common/pdf_export_settings.hpp" | ||
#include "util/str_util.hpp" | ||
#include "util/geom_util.hpp" | ||
#include "common/polygon.hpp" | ||
#include "common/hole.hpp" | ||
#include "canvas/appearance.hpp" | ||
#include "board/plane.hpp" | ||
|
||
namespace horizon { | ||
|
||
double to_pt(double x_nm) | ||
{ | ||
return x_nm * .000002834645669291339; | ||
} | ||
|
||
CanvasPDF::CanvasPDF(PoDoFo::PdfPainter &p, PoDoFo::PdfFont &f, const PDFExportSettings &s) | ||
: Canvas::Canvas(), painter(p), font(f), settings(s), metrics(font.GetFontMetrics()) | ||
{ | ||
img_mode = true; | ||
Appearance apperarance; | ||
layer_colors = apperarance.layer_colors; | ||
} | ||
|
||
bool CanvasPDF::pdf_layer_visible(int l) const | ||
{ | ||
if (layer_filter == false) | ||
return true; | ||
else | ||
return l == current_layer; | ||
} | ||
|
||
Color CanvasPDF::get_pdf_layer_color(int layer) const | ||
{ | ||
if (use_layer_colors) | ||
return get_layer_color(layer); | ||
else | ||
return Color(0, 0, 0); | ||
} | ||
|
||
void CanvasPDF::img_line(const Coordi &p0, const Coordi &p1, const uint64_t width, int layer, bool tr) | ||
{ | ||
if (!pdf_layer_visible(layer)) | ||
return; | ||
painter.Save(); | ||
auto w = std::max(width, settings.min_line_width); | ||
painter.SetStrokeWidth(to_pt(w)); | ||
Coordi rp0 = p0; | ||
Coordi rp1 = p1; | ||
if (tr) { | ||
rp0 = transform.transform(p0); | ||
rp1 = transform.transform(p1); | ||
} | ||
auto color = get_pdf_layer_color(layer); | ||
painter.SetStrokingColor(color.r, color.g, color.b); | ||
painter.DrawLine(to_pt(rp0.x), to_pt(rp0.y), to_pt(rp1.x), to_pt(rp1.y)); | ||
painter.Restore(); | ||
} | ||
|
||
void CanvasPDF::img_draw_text(const Coordf &p, float size, const std::string &rtext, int angle, bool flip, | ||
TextOrigin origin, int layer, uint64_t width, TextData::Font tfont, bool center, | ||
bool mirror) | ||
{ | ||
if (!settings.include_text) | ||
return; | ||
if (!pdf_layer_visible(layer)) | ||
return; | ||
|
||
angle = wrap_angle(angle); | ||
bool backwards = (angle > 16384) && (angle <= 49152); | ||
float yshift = 0; | ||
switch (origin) { | ||
case TextOrigin::CENTER: | ||
yshift = 0; | ||
break; | ||
default: | ||
yshift = size / 2; | ||
} | ||
|
||
std::string text(rtext); | ||
trim(text); | ||
std::stringstream ss(text); | ||
std::string line; | ||
unsigned int n_lines = std::count(text.begin(), text.end(), '\n'); | ||
unsigned int i_line = 0; | ||
float lineskip = size * 1.35 + width; | ||
if (mirror) { | ||
lineskip *= -1; | ||
} | ||
font.SetFontSize(to_pt(size) * 1.6); | ||
while (std::getline(ss, line, '\n')) { | ||
line = TextData::trim(line); | ||
int64_t line_width = metrics->StringWidthMM(line.c_str()) * 1000; | ||
|
||
Placement tf; | ||
tf.shift.x = p.x; | ||
tf.shift.y = p.y; | ||
|
||
Placement tr; | ||
if (flip) | ||
tr.set_angle(32768 - angle); | ||
else | ||
tr.set_angle(angle); | ||
if (backwards ^ mirror) | ||
tf.shift += tr.transform(Coordi(0, -lineskip * (n_lines - i_line))); | ||
else | ||
tf.shift += tr.transform(Coordi(0, -lineskip * i_line)); | ||
|
||
int xshift = 0; | ||
if (backwards) { | ||
tf.set_angle(angle - 32768); | ||
xshift = -line_width; | ||
} | ||
else { | ||
tf.set_angle(angle); | ||
} | ||
tf.mirror = flip; | ||
if (center) { | ||
if (backwards) { | ||
xshift += line_width / 2; | ||
} | ||
else { | ||
xshift -= line_width / 2; | ||
} | ||
} | ||
double fangle = tf.get_angle_rad(); | ||
painter.Save(); | ||
Coordi p0(xshift, yshift); | ||
Coordi pt = tf.transform(p0); | ||
|
||
painter.SetTransformationMatrix(cos(fangle), sin(fangle), -sin(fangle), cos(fangle), to_pt(pt.x), to_pt(pt.y)); | ||
PoDoFo::PdfString pstr(reinterpret_cast<const PoDoFo::pdf_utf8 *>(line.c_str())); | ||
painter.DrawText(0, to_pt(size) / -2, pstr); | ||
painter.Restore(); | ||
|
||
i_line++; | ||
} | ||
} | ||
|
||
void CanvasPDF::img_polygon(const Polygon &ipoly, bool tr) | ||
{ | ||
if (!pdf_layer_visible(ipoly.layer)) | ||
return; | ||
painter.Save(); | ||
auto color = get_pdf_layer_color(ipoly.layer); | ||
painter.SetColor(color.r, color.g, color.b); | ||
painter.SetStrokingColor(color.r, color.g, color.b); | ||
painter.SetStrokeWidth(to_pt(settings.min_line_width)); | ||
if (ipoly.usage == nullptr) { // regular patch | ||
draw_polygon(ipoly, tr); | ||
if (fill) | ||
painter.Fill(); | ||
else | ||
painter.Stroke(); | ||
} | ||
else if (auto plane = dynamic_cast<const Plane *>(ipoly.usage.ptr)) { | ||
for (const auto &frag : plane->fragments) { | ||
for (const auto &path : frag.paths) { | ||
bool first = true; | ||
for (const auto &it : path) { | ||
Coordi p(it.X, it.Y); | ||
if (tr) | ||
p = transform.transform(p); | ||
if (first) | ||
painter.MoveTo(to_pt(p.x), to_pt(p.y)); | ||
else | ||
painter.LineTo(to_pt(p.x), to_pt(p.y)); | ||
first = false; | ||
} | ||
painter.ClosePath(); | ||
} | ||
} | ||
if (fill) | ||
painter.Fill(true); | ||
else | ||
painter.Stroke(); | ||
} | ||
painter.Restore(); | ||
} | ||
|
||
void CanvasPDF::img_hole(const Hole &hole) | ||
{ | ||
if (!pdf_layer_visible(PDFExportSettings::HOLES_LAYER)) | ||
return; | ||
painter.Save(); | ||
|
||
auto color = get_pdf_layer_color(PDFExportSettings::HOLES_LAYER); | ||
painter.SetColor(color.r, color.g, color.b); | ||
painter.SetStrokingColor(color.r, color.g, color.b); | ||
painter.SetStrokeWidth(to_pt(settings.min_line_width)); | ||
|
||
auto hole2 = hole; | ||
if (settings.set_holes_size) { | ||
hole2.diameter = settings.holes_diameter; | ||
} | ||
draw_polygon(hole2.to_polygon(), true); | ||
if (fill) | ||
painter.Fill(true); | ||
else | ||
painter.Stroke(); | ||
painter.Restore(); | ||
} | ||
|
||
// c is the arc center. | ||
// angles must be in radians, c and r must be in mm. | ||
// See "How to determine the control points of a Bézier curve that approximates a | ||
// small circular arc" by Richard ADeVeneza, Nov 2004 | ||
// https://www.tinaja.com/glib/bezcirc2.pdf | ||
static Coordd pdf_arc_segment(PoDoFo::PdfPainter &painter, const Coordd c, const double r, double a0, double a1) | ||
{ | ||
const auto da = a0 - a1; | ||
assert(da != 0); | ||
assert(std::abs(da) <= M_PI / 2 + 1e-6); | ||
|
||
// Shift to bisect at x axis | ||
const auto theta = (a0 + a1) / 2; | ||
const auto phi = da / 2; | ||
|
||
// Compute points of unit circle for given delta angle | ||
const auto p0 = Coordd(cos(phi), sin(phi)); | ||
const auto p1 = Coordd((4 - p0.x) / 3, (1 - p0.x) * (3 - p0.x) / (3 * p0.y)); | ||
const auto p2 = Coordd(p1.x, -p1.y); | ||
const auto p3 = Coordd(p0.x, -p0.y); | ||
|
||
// Transform points | ||
const auto c1 = p1.rotate(theta) * r + c; | ||
const auto c2 = p2.rotate(theta) * r + c; | ||
const auto c3 = p3.rotate(theta) * r + c; | ||
|
||
painter.CubicBezierTo(to_pt(c1.x), to_pt(c1.y), to_pt(c2.x), to_pt(c2.y), to_pt(c3.x), to_pt(c3.y)); | ||
return c3; // end point | ||
} | ||
|
||
static void pdf_arc(PoDoFo::PdfPainter &painter, const Coordd start, const Coordd c, const Coordd end, bool cw) | ||
{ | ||
const auto r = (start - c).mag(); | ||
|
||
// Get angles relative to the x axis | ||
double a0 = (start - c).angle(); | ||
double a1 = (end - c).angle(); | ||
|
||
// Circle or large arc | ||
if (cw && a0 <= a1) { | ||
a0 += 2 * M_PI; | ||
} | ||
else if (!cw && a0 >= a1) { | ||
a0 -= 2 * M_PI; | ||
} | ||
|
||
const double da = (cw) ? -M_PI / 2 : M_PI / 2; | ||
if (cw) { | ||
assert(a0 > a1); | ||
} | ||
else { | ||
assert(a0 < a1); | ||
} | ||
double e = a1 - a0; | ||
while (std::abs(e) > 1e-6) { | ||
const auto d = (cw) ? std::max(e, da) : std::min(e, da); | ||
const auto a = a0 + d; | ||
pdf_arc_segment(painter, c, r, a0, a); | ||
a0 = a; | ||
e = a1 - a0; | ||
} | ||
} | ||
|
||
|
||
void CanvasPDF::draw_polygon(const Polygon &ipoly, bool tr) | ||
{ | ||
assert(ipoly.usage == nullptr); | ||
bool first = true; | ||
for (auto it = ipoly.vertices.cbegin(); it < ipoly.vertices.cend(); it++) { | ||
Coordd p = it->position; | ||
if (tr) | ||
p = transform.transform(p); | ||
auto it_next = it + 1; | ||
if (it_next == ipoly.vertices.cend()) { | ||
it_next = ipoly.vertices.cbegin(); | ||
} | ||
if (first) { | ||
painter.MoveTo(to_pt(p.x), to_pt(p.y)); | ||
} | ||
if (it->type == Polygon::Vertex::Type::LINE) { | ||
if (!first) { | ||
painter.LineTo(to_pt(p.x), to_pt(p.y)); | ||
} | ||
} | ||
else if (it->type == Polygon::Vertex::Type::ARC) { | ||
Coordd end = it_next->position; | ||
Coordd c = project_onto_perp_bisector(end, it->position, it->arc_center); | ||
if (!first) | ||
painter.LineTo(to_pt(p.x), to_pt(p.y)); | ||
|
||
if (tr) { | ||
c = transform.transform(c); | ||
end = transform.transform(end); | ||
} | ||
pdf_arc(painter, p, c, end, it->arc_reverse); | ||
} | ||
first = false; | ||
} | ||
|
||
painter.ClosePath(); | ||
} | ||
|
||
void CanvasPDF::request_push() | ||
{ | ||
} | ||
} // namespace horizon |
Oops, something went wrong.