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

pcb2gcode / pcb2gcode / 19811714133

24 Nov 2025 02:34PM UTC coverage: 59.007% (-15.0%) from 74.006%
19811714133

push

github

web-flow
Merge pull request #730 from mar0x/master

Enable windows build in CI

2199 of 4409 branches covered (49.88%)

Branch coverage included in aggregate %.

1902 of 2541 relevant lines covered (74.85%)

117318.67 hits per line

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

54.9
/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-(
52✔
17
    const bg::model::multi_polygon<polygon_type_t>& lhs,
18
    const rhs_t& rhs) {
19
  if (bg::area(rhs) <= 0) {
52✔
20
    return lhs;
21
  }
22
  bg::model::multi_polygon<polygon_type_t> ret;
23
  bg::difference(lhs, rhs, ret);
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) {
×
32
  auto box_mp = multi_polygon_type_fp();
33
  bg::convert(lhs, box_mp);
34
  return box_mp - rhs;
×
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-(
×
41
    const bg::model::multi_linestring<linestring_type_t>& lhs,
42
    const rhs_t& rhs) {
43
  if (bg::area(rhs) <= 0) {
×
44
    return lhs;
45
  }
46
  bg::model::multi_linestring<linestring_type_t> ret;
47
  if (bg::length(lhs) <= 0) {
×
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&(
×
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) {
×
62
    return ret;
63
  }
64
  if (bg::length(lhs) <= 0) {
×
65
    return ret;
66
  }
67
  bg::intersection(lhs, rhs, ret);
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) {
×
75
  auto box_mp = multi_polygon_type_fp();
76
  bg::convert(rhs, box_mp);
77
  return lhs & box_mp;
×
78
}
79

80
template <typename rhs_t>
81
multi_linestring_type_fp operator&(const linestring_type_fp& lhs,
×
82
                                   const rhs_t& rhs) {
83
  return multi_linestring_type_fp{lhs} & rhs;
×
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,
×
90
                                                   const rhs_t& rhs) {
91
  bg::model::multi_polygon<polygon_type_t> ret;
92
  if (bg::area(rhs) <= 0) {
×
93
    return ret;
94
  }
95
  if (bg::area(lhs) <= 0) {
×
96
    return ret;
97
  }
98
  bg::intersection(lhs, rhs, ret);
×
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) {
×
106
  return lhs & multi_polygon_type_fp{rhs};
×
107
}
×
108

109
template <>
110
multi_polygon_type_fp operator&(multi_polygon_type_fp const& lhs, box_type_fp const& rhs) {
×
111
  auto box_mp = multi_polygon_type_fp();
112
  bg::convert(rhs, box_mp);
113
  return lhs & box_mp;
×
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,
×
119
                                const rhs_t& rhs) {
120
  return multi_polygon_type_fp{lhs} & rhs;
×
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^(
151✔
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) {
151✔
130
    return lhs;
131
  }
132
  if (bg::area(lhs) <= 0) {
55✔
133
    return rhs;
134
  }
135
  bg::model::multi_polygon<polygon_type_t> ret;
136
  bg::sym_difference(lhs, rhs, ret);
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,
237✔
144
                                                   const rhs_t& rhs) {
145
  if (bg::area(rhs) <= 0) {
237✔
146
    return lhs;
147
  }
148
  if (bg::area(lhs) <= 0) {
205✔
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);
116✔
155
  return from_geos<multi_polygon_type_fp>(to_geos(lhs)->Union(geos_rhs.get()));
116!
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
}
116✔
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,
57!
180
                             const Addition& adder,
181
                             const std::vector<box_type_fp>& bboxes) {
182
  if (mpolys.size() == 0) {
57!
183
    return multi_polygon_type_fp();
184
  } else if (mpolys.size() == 1) {
57✔
185
    return mpolys.front();
186
  }
187
  size_t current = 0;
188
  std::vector<multi_polygon_type_fp> new_mpolys;
189
  std::vector<box_type_fp> new_bboxes;
190
  if (mpolys.size() % 2 == 1) {
36✔
191
    new_mpolys.push_back(mpolys[current]);
5!
192
    new_bboxes.push_back(bboxes[current]);
5!
193
    current++;
194
  }
195
  // There are at least two and the total number is even.
196
  for (; current < mpolys.size(); current += 2) {
246✔
197
    box_type_fp new_bbox = bboxes[current];
210✔
198
    bg::expand(new_bbox, bboxes[current+1]);
210✔
199
    new_bboxes.push_back(new_bbox);
210!
200
    if (!bg::intersects(bboxes[current], bboxes[current+1])) {
210✔
201
      new_mpolys.push_back(mpolys[current]);
114!
202
      new_mpolys.back().insert(new_mpolys.back().cend(), mpolys[current+1].cbegin(), mpolys[current+1].cend());
114!
203
    } else {
204
      new_mpolys.push_back(adder(mpolys[current], mpolys[current+1]));
192!
205
    }
206
  }
207
  return reduce(new_mpolys, adder, new_bboxes);
36!
208
}
36✔
209

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

221
void round(ring_type_fp& ring) {
374✔
222
  for (auto& point : ring) {
285,966✔
223
    point.x(std::round(point.x() * 1e10)/1e10);
285,592✔
224
    point.y(std::round(point.y() * 1e10)/1e10);
285,592✔
225
  }
226
}
374✔
227

228
void round(polygon_type_fp& p) {
306✔
229
  round(p.outer());
306✔
230
  for (auto& inner : p.inners()) {
374✔
231
    round(inner);
68✔
232
  }
233
}
306✔
234

235
void round(multi_polygon_type_fp& mp) {
243✔
236
  for (auto& p : mp) {
549✔
237
    round(p);
306✔
238
  }
239
}
243✔
240

241
multi_polygon_type_fp sum(const std::vector<multi_polygon_type_fp>& mpolys) {
83!
242
  if (mpolys.size() == 0) {
83!
243
    return {};
244
  } else if (mpolys.size() == 1) {
83✔
245
    return mpolys[0];
246
  }
247
#ifdef GEOS_VERSION
248
  std::vector<std::unique_ptr<geos::geom::Geometry>> geos_mpolys_tmp;
249
  for (const auto& mpoly : mpolys) {
322✔
250
    if (bg::area(mpoly) == 0) {
291✔
251
      continue;
48✔
252
    }
253
    auto mpoly_temp = mpoly;
254
    round(mpoly_temp);
243✔
255
    geos_mpolys_tmp.push_back(to_geos(mpoly_temp));
486!
256
  }
257
  auto geos_factory = geos::geom::GeometryFactory::create();
31!
258
  auto geos_collection = geos_factory->buildGeometry(std::move(geos_mpolys_tmp));
31!
259
  if (geos_collection->isEmpty()) {
31!
260
    return {};
261
  }
262
  try {
263
    std::unique_ptr<geos::geom::Geometry> geos_out(
264
        geos_collection->Union());
27!
265
    return from_geos<multi_polygon_type_fp>(geos_out);
27!
266
  } catch (const geos::util::TopologyException& e) {
27!
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
}
62✔
274

275
multi_polygon_type_fp symdiff(const std::vector<multi_polygon_type_fp>& mpolys) {
21!
276
  if (mpolys.size() == 0) {
21!
277
    return multi_polygon_type_fp();
278
  } else if (mpolys.size() == 1) {
21!
279
    return mpolys[0];
280
  }
281
  std::vector<box_type_fp> bboxes;
282
  bboxes.reserve(mpolys.size());
21!
283
  for (const auto& mpoly : mpolys) {
252✔
284
    bboxes.push_back(bg::return_envelope<box_type_fp>(mpoly));
231✔
285
  }
286
  return reduce(mpolys, operator^<polygon_type_fp>);
21!
287
}
21✔
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