aboutsummaryrefslogtreecommitdiff
path: root/src/out_flattener.cpp
blob: edb93b7410059190779534d6a42508891e96b85e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
 * This file is part of gerbolyze, a vector image preprocessing toolchain 
 * Copyright (C) 2021 Jan Sebastian Götte <gerbolyze@jaseg.de>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <cmath>
#include <algorithm>
#include <string>
#include <iostream>
#include <iomanip>
#include <clipper.hpp>
#include <gerbolyze.hpp>
#include <svg_import_defs.h>
#include <svg_geom.h>

using namespace gerbolyze;
using namespace std;

namespace gerbolyze {
    class Flattener_D {
    public:
        ClipperLib::Clipper c;
    };
}

Flattener::Flattener(PolygonSink &sink) : m_sink(sink) {
    d = new Flattener_D();
    d->c.StrictlySimple(true);
}

Flattener::~Flattener() {
    delete d;
}

void Flattener::header(d2p origin, d2p size) {
    m_sink.header(origin, size);
}

Flattener &Flattener::operator<<(GerberPolarityToken pol) {
    if (m_current_polarity != pol) {
        m_current_polarity = pol;
    }

    return *this;
}

Flattener &Flattener::operator<<(const Polygon &poly) {
    ClipperLib::Path le_path;
    for (auto &p : poly) {
        le_path.push_back({(ClipperLib::cInt)round(p[0] * clipper_scale), (ClipperLib::cInt)round(p[1] * clipper_scale)});
    }

    ClipperLib::Paths out;

    if (m_current_polarity == GRB_POL_DARK) {
        d->c.AddPath(le_path, ClipperLib::ptSubject, true);
        d->c.Execute(ClipperLib::ctUnion, out, ClipperLib::pftNonZero);

    } else { /* clear */
        d->c.AddPath(le_path, ClipperLib::ptClip, true);
        d->c.Execute(ClipperLib::ctDifference, out, ClipperLib::pftNonZero);
    }

    d->c.Clear();
    d->c.AddPaths(out, ClipperLib::ptSubject, true);

    return *this;
}

void Flattener::footer() {
    ClipperLib::PolyTree t_out;
    d->c.Execute(ClipperLib::ctDifference, t_out, ClipperLib::pftNonZero);
    d->c.Clear();

    m_sink << GRB_POL_DARK;

    ClipperLib::Paths out;
    cerr << "deholing" << endl;
    dehole_polytree(t_out, out);
    for (auto &poly : out) {
        Polygon poly_out;
        for (auto &p : poly) {
            poly_out.push_back({p.X / clipper_scale, p.Y / clipper_scale});
        }
        m_sink << poly_out;
    }

    m_sink.footer();
}