• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pcb2gcode / pcb2gcode / 21021097492

15 Jan 2026 05:42AM UTC coverage: 70.124% (+10.1%) from 60.064%
21021097492

push

github

web-flow
Merge pull request #752 from eyal0/integration_tests_in_ci

ci: Include integration tests as part of coverage.

4430 of 7541 branches covered (58.75%)

Branch coverage included in aggregate %.

3710 of 4067 relevant lines covered (91.22%)

15236187.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.13
/bg_operators.cpp
1
#include "geometry.hpp"
2
#include "geometry_int.hpp"
3
#include "bg_helpers.hpp"
4
#ifdef GEOS_VERSION
5
#include <geos/util/TopologyException.h>
6
#include <geos/geom/GeometryFactory.h>
7
#include "geos_helpers.hpp"
8
#endif // GEOS_VERSION
9

10
#include "bg_operators.hpp"
11

12
using std::unique_ptr;
13
using std::vector;
14

15
template <typename polygon_type_t, typename rhs_t>
16
bg::model::multi_polygon<polygon_type_t> operator-(
247✔
17
    const bg::model::multi_polygon<polygon_type_t>& lhs,
18
    const rhs_t& rhs) {
19
  if (bg::area(rhs) <= 0) {
247✔
20
    return lhs;
21
  }
22
  bg::model::multi_polygon<polygon_type_t> ret;
23
  bg::difference(lhs, rhs, ret);
123!
24
  return ret;
25
}
26

27
template multi_polygon_type_fp operator-(const multi_polygon_type_fp&, const multi_polygon_type_fp&);
28
template multi_polygon_type_fp operator-(const multi_polygon_type_fp&, const box_type_fp&);
29

30
template <typename rhs_t>
31
multi_polygon_type_fp operator-(const box_type_fp& lhs, const rhs_t& rhs) {
6!
32
  auto box_mp = multi_polygon_type_fp();
33
  bg::convert(lhs, box_mp);
34
  return box_mp - rhs;
12!
35
}
36

37
template multi_polygon_type_fp operator-(const box_type_fp&, const multi_polygon_type_fp&);
38

39
template <typename linestring_type_t, typename rhs_t>
40
bg::model::multi_linestring<linestring_type_t> operator-(
27,040✔
41
    const bg::model::multi_linestring<linestring_type_t>& lhs,
42
    const rhs_t& rhs) {
43
  if (bg::area(rhs) <= 0) {
27,040✔
44
    return lhs;
45
  }
46
  bg::model::multi_linestring<linestring_type_t> ret;
47
  if (bg::length(lhs) <= 0) {
24,619!
48
    return ret;
49
  }
50
  bg::difference(lhs, rhs, ret);
51
  return ret;
52
}
53

54
template multi_linestring_type_fp operator-(const multi_linestring_type_fp&, const multi_polygon_type_fp&);
55

56
template <typename linestring_type_t, typename rhs_t>
57
bg::model::multi_linestring<linestring_type_t> operator&(
28,060✔
58
    const bg::model::multi_linestring<linestring_type_t>& lhs,
59
    const rhs_t& rhs) {
60
  bg::model::multi_linestring<linestring_type_t> ret;
61
  if (bg::area(rhs) <= 0) {
28,060✔
62
    return ret;
63
  }
64
  if (bg::length(lhs) <= 0) {
28,052✔
65
    return ret;
66
  }
67
  bg::intersection(lhs, rhs, ret);
12,892!
68
  return ret;
69
}
70

71
template multi_linestring_type_fp operator&(const multi_linestring_type_fp&, const multi_polygon_type_fp&);
72

73
template <>
74
multi_linestring_type_fp operator&(const multi_linestring_type_fp& lhs, const box_type_fp& rhs) {
142!
75
  auto box_mp = multi_polygon_type_fp();
76
  bg::convert(rhs, box_mp);
77
  return lhs & box_mp;
284!
78
}
79

80
template <typename rhs_t>
81
multi_linestring_type_fp operator&(const linestring_type_fp& lhs,
142✔
82
                                   const rhs_t& rhs) {
83
  return multi_linestring_type_fp{lhs} & rhs;
426!
84
}
85

86
template multi_linestring_type_fp operator&(const linestring_type_fp&, const box_type_fp&);
87

88
template <typename polygon_type_t, typename rhs_t>
89
bg::model::multi_polygon<polygon_type_t> operator&(const bg::model::multi_polygon<polygon_type_t>& lhs,
12,065!
90
                                                   const rhs_t& rhs) {
91
  bg::model::multi_polygon<polygon_type_t> ret;
92
  if (bg::area(rhs) <= 0) {
12,065!
93
    return ret;
94
  }
95
  if (bg::area(lhs) <= 0) {
12,065✔
96
    return ret;
97
  }
98
  bg::intersection(lhs, rhs, ret);
12,050!
99
  return ret;
100
}
101

102
template multi_polygon_type_fp operator&(const multi_polygon_type_fp&, const multi_polygon_type_fp&);
103

104
template <>
105
multi_polygon_type_fp operator&(multi_polygon_type_fp const& lhs, polygon_type_fp const& rhs) {
1,798✔
106
  return lhs & multi_polygon_type_fp{rhs};
5,394!
107
}
108

109
template <>
110
multi_polygon_type_fp operator&(multi_polygon_type_fp const& lhs, box_type_fp const& rhs) {
596!
111
  auto box_mp = multi_polygon_type_fp();
112
  bg::convert(rhs, box_mp);
113
  return lhs & box_mp;
1,192!
114
}
115

116

117
template <typename point_type_t, typename rhs_t>
118
multi_polygon_type_fp operator&(const bg::model::polygon<point_type_t>& lhs,
6,888✔
119
                                const rhs_t& rhs) {
120
  return multi_polygon_type_fp{lhs} & rhs;
20,664!
121
}
122

123
template multi_polygon_type_fp operator&(polygon_type_fp const&, multi_polygon_type_fp const&);
124

125
template <typename polygon_type_t>
126
bg::model::multi_polygon<polygon_type_t> operator^(
2,433✔
127
    const bg::model::multi_polygon<polygon_type_t>& lhs,
128
    const bg::model::multi_polygon<polygon_type_t>& rhs) {
129
  if (bg::area(rhs) <= 0) {
2,433✔
130
    return lhs;
131
  }
132
  if (bg::area(lhs) <= 0) {
480✔
133
    return rhs;
134
  }
135
  bg::model::multi_polygon<polygon_type_t> ret;
136
  bg::sym_difference(lhs, rhs, ret);
15!
137
  return ret;
138
}
139

140
template multi_polygon_type_fp operator^(const multi_polygon_type_fp&, const multi_polygon_type_fp&);
141

142
template <typename polygon_type_t, typename rhs_t>
143
bg::model::multi_polygon<polygon_type_t> operator+(const bg::model::multi_polygon<polygon_type_t>& lhs,
2,808✔
144
                                                   const rhs_t& rhs) {
145
  if (bg::area(rhs) <= 0) {
2,808✔
146
    return lhs;
147
  }
148
  if (bg::area(lhs) <= 0) {
2,417✔
149
    bg::model::multi_polygon<polygon_type_t> ret;
150
    bg::convert(rhs, ret);
151
    return ret;
152
  }
153
#ifdef GEOS_VERSION
154
  auto geos_rhs = to_geos(rhs);
1,823✔
155
  return from_geos<multi_polygon_type_fp>(to_geos(lhs)->Union(geos_rhs.get()));
1,823!
156
#else // !GEOS_VERSION
157
  // This optimization fixes a bug in boost geometry when shapes are bordering
158
  // somwhat but not overlapping.  This is exposed by EasyEDA that makes lots of
159
  // shapes like that.
160
  const auto lhs_box = bg::return_envelope<box_type_fp>(lhs);
161
  const auto rhs_box = bg::return_envelope<box_type_fp>(rhs);
162
  if (lhs_box.max_corner().x() == rhs_box.min_corner().x() ||
163
      rhs_box.max_corner().x() == lhs_box.min_corner().x() ||
164
      lhs_box.max_corner().y() == rhs_box.min_corner().y() ||
165
      rhs_box.max_corner().y() == lhs_box.min_corner().y()) {
166
    multi_polygon_type_fp new_rhs;
167
    bg::convert(rhs, new_rhs);
168
    return bg_helpers::buffer(lhs, 0.00001) + bg_helpers::buffer(new_rhs, 0.00001);
169
  }
170
  bg::model::multi_polygon<polygon_type_t> ret;
171
  bg::union_(lhs, rhs, ret);
172
  return ret;
173
#endif //GEOS_VERSION
174
}
175

176
template multi_polygon_type_fp operator+(const multi_polygon_type_fp&, const multi_polygon_type_fp&);
177

178
template <typename Addition>
179
multi_polygon_type_fp reduce(const std::vector<multi_polygon_type_fp>& mpolys,
487!
180
                             const Addition& adder,
181
                             const std::vector<box_type_fp>& bboxes) {
182
  if (mpolys.size() == 0) {
487!
183
    return multi_polygon_type_fp();
184
  } else if (mpolys.size() == 1) {
487✔
185
    return mpolys.front();
186
  }
187
  size_t current = 0;
188
  std::vector<multi_polygon_type_fp> new_mpolys;
391✔
189
  std::vector<box_type_fp> new_bboxes;
190
  if (mpolys.size() % 2 == 1) {
391✔
191
    new_mpolys.push_back(mpolys[current]);
152!
192
    new_bboxes.push_back(bboxes[current]);
152!
193
    current++;
194
  }
195
  // There are at least two and the total number is even.
196
  for (; current < mpolys.size(); current += 2) {
4,349✔
197
    box_type_fp new_bbox = bboxes[current];
3,958✔
198
    bg::expand(new_bbox, bboxes[current+1]);
3,958✔
199
    new_bboxes.push_back(new_bbox);
3,958!
200
    if (!bg::intersects(bboxes[current], bboxes[current+1])) {
3,958✔
201
      new_mpolys.push_back(mpolys[current]);
2,005!
202
      new_mpolys.back().insert(new_mpolys.back().cend(), mpolys[current+1].cbegin(), mpolys[current+1].cend());
2,005!
203
    } else {
204
      new_mpolys.push_back(adder(mpolys[current], mpolys[current+1]));
3,906!
205
    }
206
  }
207
  return reduce(new_mpolys, adder, new_bboxes);
391!
208
}
209

210
template <typename Addition>
211
multi_polygon_type_fp reduce(const std::vector<multi_polygon_type_fp>& mpolys,
96!
212
                             const Addition& adder) {
213
  std::vector<box_type_fp> bboxes;
214
  bboxes.reserve(mpolys.size());
96!
215
  for (const auto& mpoly : mpolys) {
4,150✔
216
    bboxes.push_back(bg::return_envelope<box_type_fp>(mpoly));
4,054✔
217
  }
218
  return reduce(mpolys, adder, bboxes);
192!
219
}
220

221
void round(ring_type_fp& ring) {
6,243✔
222
  for (auto& point : ring) {
2,355,960✔
223
    point.x(std::round(point.x() * 1e10)/1e10);
2,349,717✔
224
    point.y(std::round(point.y() * 1e10)/1e10);
2,349,717✔
225
  }
226
}
6,243✔
227

228
void round(polygon_type_fp& p) {
5,549✔
229
  round(p.outer());
5,549✔
230
  for (auto& inner : p.inners()) {
6,243✔
231
    round(inner);
694✔
232
  }
233
}
5,549✔
234

235
void round(multi_polygon_type_fp& mp) {
4,624✔
236
  for (auto& p : mp) {
10,173✔
237
    round(p);
5,549✔
238
  }
239
}
4,624✔
240

241
multi_polygon_type_fp sum(const std::vector<multi_polygon_type_fp>& mpolys) {
542✔
242
  if (mpolys.size() == 0) {
542✔
243
    return {};
244
  } else if (mpolys.size() == 1) {
541✔
245
    return mpolys[0];
246
  }
247
#ifdef GEOS_VERSION
248
  std::vector<std::unique_ptr<geos::geom::Geometry>> geos_mpolys_tmp;
193✔
249
  for (const auto& mpoly : mpolys) {
5,457✔
250
    if (bg::area(mpoly) == 0) {
5,264✔
251
      continue;
640✔
252
    }
253
    auto mpoly_temp = mpoly;
254
    round(mpoly_temp);
4,624✔
255
    geos_mpolys_tmp.push_back(to_geos(mpoly_temp));
9,248!
256
  }
257
  auto geos_factory = geos::geom::GeometryFactory::create();
193!
258
  auto geos_collection = geos_factory->buildGeometry(std::move(geos_mpolys_tmp));
386!
259
  if (geos_collection->isEmpty()) {
193!
260
    return {};
261
  }
262
  try {
263
    std::unique_ptr<geos::geom::Geometry> geos_out(
264
        geos_collection->Union());
386!
265
    return from_geos<multi_polygon_type_fp>(geos_out);
193!
266
  } catch (const geos::util::TopologyException& e) {
×
267
    std::cerr << "\nError: Internal error with libgeos.  Upgrading geos may help." << std::endl;
×
268
    throw;
×
269
  }
270
#else // !GEOS_VERSION
271
  return reduce(mpolys, operator+<polygon_type_fp, multi_polygon_type_fp>);
272
#endif // GEOS_VERSION
273
}
274

275
multi_polygon_type_fp symdiff(const std::vector<multi_polygon_type_fp>& mpolys) {
96!
276
  if (mpolys.size() == 0) {
96!
277
    return multi_polygon_type_fp();
278
  } else if (mpolys.size() == 1) {
96!
279
    return mpolys[0];
280
  }
281
  std::vector<box_type_fp> bboxes;
282
  bboxes.reserve(mpolys.size());
96!
283
  for (const auto& mpoly : mpolys) {
4,150✔
284
    bboxes.push_back(bg::return_envelope<box_type_fp>(mpoly));
4,054✔
285
  }
286
  return reduce(mpolys, operator^<polygon_type_fp>);
96!
287
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc