Skip to content

Commit

Permalink
Adapt meson build dependencies to support legacy libpodofo
Browse files Browse the repository at this point in the history
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
Show file tree
Hide file tree
Showing 9 changed files with 795 additions and 8 deletions.
34 changes: 26 additions & 8 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,32 @@ if get_option('debug')
cpp_args += '-DCONNECTION_CHECK'
endif

# pkg-config is useless for podofo :(
# pkg-config is useless for old podofo :(
podofo_legacy = true
podofo_lib =cxx.find_library('podofo', dirs: '/usr/lib/podofo-0.9/', required: false, has_headers:['/usr/include/podofo-0.9/podofo/podofo.h'] )
if podofo_lib.found()
podofo = declare_dependency (
podofo = declare_dependency (
dependencies: podofo_lib,
include_directories: include_directories('/usr/include/podofo-0.9')
)
include_directories: include_directories('/usr/include/podofo-0.9')
)
else
podofo = dependency('libpodofo09', required:false)
if podofo.found()
cpp_args += '-DINC_PODOFO_WITHOUT_DIRECTORY'
else
podofo = dependency('libpodofo')
if podofo.version() == 'unknown' or podofo.version() < '0.10.0'
podofo_legacy = true
else
podofo_legacy = false
endif
endif
endif

if podofo_legacy
message('using legacy podofo')
endif

stdlibs = []
is_libstdcpp = cxx.get_define('__GLIBCXX__', prefix: '#include <vector>') != ''
if is_libstdcpp
Expand Down Expand Up @@ -666,10 +676,6 @@ src_export = files(
'src/export_util/tree_writer.cpp',
'src/export_util/tree_writer_fs.cpp',
'src/export_util/tree_writer_archive.cpp',
'src/export_pdf/canvas_pdf.cpp',
'src/export_pdf/export_pdf.cpp',
'src/export_pdf/export_pdf_board.cpp',
'src/export_pdf/export_pdf_util.cpp',
'src/export_pnp/export_pnp.cpp',
'src/export_bom/export_bom.cpp',
'src/export_odb/odb_export.cpp',
Expand All @@ -686,6 +692,18 @@ src_export = files(
'src/export_odb/structured_text_writer.cpp'
)

if podofo_legacy
src_export += 'src/export_pdf/legacy/canvas_pdf.cpp'
src_export += 'src/export_pdf/legacy/export_pdf.cpp'
src_export += 'src/export_pdf/legacy/export_pdf_board.cpp'
src_export += 'src/export_pdf/legacy/export_pdf_util.cpp'
else
src_export += 'src/export_pdf/canvas_pdf.cpp'
src_export += 'src/export_pdf/export_pdf.cpp'
src_export += 'src/export_pdf/export_pdf_board.cpp'
src_export += 'src/export_pdf/export_pdf_util.cpp'
endif

src_board_rules_check = files(
'src/rules/cache.cpp',
'src/board/board_rules_check.cpp',
Expand Down
309 changes: 309 additions & 0 deletions src/export_pdf/legacy/canvas_pdf.cpp
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
Loading

0 comments on commit 9727724

Please sign in to comment.