16bool OnLine(
const double x1,
const double y1,
const double x2,
const double y2,
17 const double u,
const double v) {
19 double epsx = 1.e-10 * std::max({
fabs(x1),
fabs(x2),
fabs(u)});
20 double epsy = 1.e-10 * std::max({
fabs(y1),
fabs(y2),
fabs(v)});
21 epsx = std::max(1.e-10, epsx);
22 epsy = std::max(1.e-10, epsy);
24 if ((
fabs(x1 - u) <= epsx &&
fabs(y1 - v) <= epsy) ||
25 (
fabs(x2 - u) <= epsx &&
fabs(y2 - v) <= epsy)) {
28 }
else if (
fabs(x1 - x2) <= epsx &&
fabs(y1 - y2) <= epsy) {
32 double xc = 0., yc = 0.;
35 const double dx = (x2 - x1);
36 const double dy = (y2 - y1);
37 const double xl = ((u - x1) * dx + (v - y1) * dy) / (dx * dx + dy * dy);
50 const double dx = (x1 - x2);
51 const double dy = (y1 - y2);
52 const double xl = ((u - x2) * dx + (v - y2) * dy) / (dx * dx + dy * dy);
65 if (
fabs(u - xc) < epsx &&
fabs(v - yc) < epsy) {
73bool Crossing(
const double x1,
const double y1,
const double x2,
74 const double y2,
const double u1,
const double v1,
75 const double u2,
const double v2,
double& xc,
double& yc) {
77 std::array<std::array<double, 2>, 2> a;
82 const double det = a[0][0] * a[1][1] - a[1][0] * a[0][1];
89 epsx = std::max(epsx, 1.e-10);
90 epsy = std::max(epsy, 1.e-10);
92 if (OnLine(x1, y1, x2, y2, u1, v1)) {
96 }
else if (OnLine(x1, y1, x2, y2, u2, v2)) {
100 }
else if (OnLine(u1, v1, u2, v2, x1, y1)) {
104 }
else if (OnLine(u1, v1, u2, v2, x2, y2)) {
108 }
else if (
fabs(det) < epsx * epsy) {
113 const double aux = a[1][1];
114 a[1][1] = a[0][0] / det;
116 a[1][0] = -a[1][0] / det;
117 a[0][1] = -a[0][1] / det;
119 xc = a[0][0] * (x1 * y2 - x2 * y1) + a[1][0] * (u1 * v2 - u2 * v1);
120 yc = a[0][1] * (x1 * y2 - x2 * y1) + a[1][1] * (u1 * v2 - u2 * v1);
122 if (OnLine(x1, y1, x2, y2, xc, yc) && OnLine(u1, v1, u2, v2, xc, yc)) {
132bool Crossing(
const double x1,
const double y1,
133 const double x2,
const double y2,
134 const double u1,
const double v1,
135 const double u2,
const double v2) {
137 std::array<std::array<double, 2>, 2> a;
143 const double det = a[0][0] * a[1][1] - a[0][1] * a[1][0];
145 const double epsx = std::max(1.e-10 * std::max({std::abs(x1), std::abs(x2),
146 std::abs(u1), std::abs(u2)}),
148 const double epsy = std::max(1.e-10 * std::max({std::abs(y1), std::abs(y2),
149 std::abs(v1), std::abs(v2)}),
152 if (OnLine(x1, y1, x2, y2, u1, v1) || OnLine(x1, y1, x2, y2, u2, v2) ||
153 OnLine(u1, v1, u2, v2, x1, y1) || OnLine(u1, v1, u2, v2, x2, y2)) {
157 if (std::abs(det) < epsx * epsy) {
162 std::swap(a[0][0], a[1][1]);
163 const double invdet = 1. / det;
166 a[0][1] = -a[0][1] * invdet;
167 a[1][0] = -a[1][0] * invdet;
169 const double xc = a[0][0] * (x1 * y2 - x2 * y1) +
170 a[0][1] * (u1 * v2 - u2 * v1);
171 const double yc = a[1][0] * (x1 * y2 - x2 * y1) +
172 a[1][1] * (u1 * v2 - u2 * v1);
174 if (OnLine(x1, y1, x2, y2, xc, yc) && OnLine(u1, v1, u2, v2, xc, yc)) {
187void Inside(
const std::vector<double>& xpl,
const std::vector<double>& ypl,
188 const double x,
const double y,
bool& inside,
bool& edge) {
192 const unsigned int npl = xpl.size();
193 if (ypl.size() != npl)
return;
197 }
else if (npl == 2) {
198 edge = OnLine(xpl[0], ypl[0], xpl[1], ypl[1], x, y);
202 const double xmin = *std::min_element(std::begin(xpl), std::end(xpl));
203 const double xmax = *std::max_element(std::begin(xpl), std::end(xpl));
204 const double ymin = *std::min_element(std::begin(ypl), std::end(ypl));
205 const double ymax = *std::max_element(std::begin(ypl), std::end(ypl));
208 double epsx = 1.e-8 * std::max(fabs(xmin), fabs(xmax));
209 double epsy = 1.e-8 * std::max(fabs(ymin), fabs(ymax));
210 epsx = std::max(epsx, 1.e-8);
211 epsy = std::max(epsy, 1.e-8);
214 if (fabs(xmax - xmin) <= epsx) {
215 if (y >= ymin - epsy && y <= ymax + epsy &&
216 fabs(xmax + xmin - 2 * x) <= epsx) {
221 }
else if (fabs(ymax - ymin) <= epsy) {
222 if (x >= xmin - epsx && x <= xmax + epsx &&
223 fabs(ymax + ymin - 2 * y) <= epsy) {
230 double xinf = xmin - fabs(xmax - xmin);
231 double yinf = ymin - fabs(ymax - ymin);
233 unsigned int nIter = 0;
235 while (!ok && nIter < 100) {
238 unsigned int nCross = 0;
239 for (
unsigned int j = 0; j < npl; ++j) {
240 const unsigned int jj = j < npl - 1 ? j + 1 : 0;
242 if (OnLine(xpl[j], ypl[j], xpl[jj], ypl[jj], x, y)) {
247 double xc = 0., yc = 0.;
248 if (Crossing(x, y, xinf, yinf, xpl[j], ypl[j], xpl[jj], ypl[jj], xc,
253 if (OnLine(x, y, xinf, yinf, xpl[j], ypl[j])) {
262 if (nCross != 2 * (nCross / 2)) inside =
true;
268 std::cerr <<
"Polygon::Inside:\n Warning. Unable to verify "
269 <<
"whether a point is internal; setting to edge.\n";
274double Area(
const std::vector<double>& xp,
const std::vector<double>& yp) {
277 const unsigned int n = xp.size();
278 for (
unsigned int i = 0; i < n; ++i) {
279 const unsigned int ii = i < n - 1 ? i + 1 : 0;
280 f += xp[i] * yp[ii] - xp[ii] * yp[i];
286 const std::vector<double>& yp) {
294 if (xp.size() != yp.size())
return false;
295 const unsigned int np = xp.size();
296 if (xp.size() < 3)
return false;
306 for (
unsigned int i = 1; i < np; ++i) {
307 xmin = std::min(xmin, xp[i]);
308 ymin = std::min(ymin, yp[i]);
309 xmax = std::max(xmax, xp[i]);
310 ymax = std::max(ymax, yp[i]);
311 const double dx = xp[i] - xp[0];
312 const double dy = yp[i] - yp[0];
313 const double d = dx * dx + dy * dy;
322 double epsx = 1.e-6 * (std::abs(xmax) + std::abs(xmin));
323 double epsy = 1.e-6 * (std::abs(ymax) + std::abs(ymin));
324 if (epsx <= 0) epsx = 1.e-6;
325 if (epsy <= 0) epsy = 1.e-6;
327 if (std::abs(xmax - xmin) <= epsx && std::abs(ymax - ymin) <= epsy) {
332 if (d1 <= epsx * epsx + epsy * epsy || i1 == 0)
return false;
337 for (
unsigned int i = 1; i < np; ++i) {
338 if (i == i1)
continue;
339 const double dx = xp[i] - xp[0];
340 const double dy = yp[i] - yp[0];
341 const double d = std::abs(x1 * dy - y1 * dx);
347 if (d2 <= epsx * epsy || i2 <= 0) {
356 std::vector<double>& zp) {
361 unsigned int np = xp.size();
364 const double xmin = *std::min_element(std::begin(xp), std::end(xp));
365 const double xmax = *std::max_element(std::begin(xp), std::end(xp));
366 const double ymin = *std::min_element(std::begin(yp), std::end(yp));
367 const double ymax = *std::max_element(std::begin(yp), std::end(yp));
368 const double zmin = *std::min_element(std::begin(zp), std::end(zp));
369 const double zmax = *std::max_element(std::begin(zp), std::end(zp));
371 const double epsx = std::max(1.e-10 * std::abs(xmax - xmin), 1.e-6);
372 const double epsy = std::max(1.e-10 * std::abs(ymax - ymin), 1.e-6);
373 const double epsz = std::max(1.e-10 * std::abs(zmax - zmin), 1.e-6);
377 for (
unsigned int i = 2; i < np; ++i) {
378 const double x1 = xp[i - 1] - xp[0];
379 const double y1 = yp[i - 1] - yp[0];
380 const double z1 = zp[i - 1] - zp[0];
381 xsurf += std::abs((yp[i] - yp[0]) * z1 - y1 * (zp[i] - zp[0]));
382 ysurf += std::abs((xp[i] - xp[0]) * z1 - x1 * (zp[i] - zp[0]));
383 zsurf += std::abs((xp[i] - xp[0]) * y1 - x1 * (yp[i] - yp[0]));
386 std::vector<bool> mark(np,
false);
388 for (
unsigned int i = 0; i < np; ++i) {
389 if (mark[i])
continue;
390 for (
unsigned int j = i + 1; j < np; ++j) {
391 if (std::abs(xp[i] - xp[j]) <= epsx && std::abs(yp[i] - yp[j]) <= epsy &&
392 std::abs(zp[i] - zp[j]) <= epsz) {
398 unsigned int nNew = 0;
399 for (
unsigned int i = 0; i < np; ++i) {
400 if (mark[i])
continue;
416 unsigned int iaxis = 0;
417 if (xsurf > ysurf && xsurf > zsurf) {
419 }
else if (ysurf > zsurf) {
425 unsigned int nPass = 0;
431 for (
unsigned int i = 0; i < np; ++i) {
432 const unsigned int ii = (i + 1) % np;
433 for (
unsigned int j = i + 2; j < np; ++j) {
434 const unsigned int jj = (j + 1) % np;
435 if (j + 1 >= np && jj >= i)
continue;
437 if (iaxis == 1 && !Crossing(yp[i], zp[i], yp[ii], zp[ii],
438 yp[j], zp[j], yp[jj], zp[jj])) {
440 }
else if (iaxis == 2 && !Crossing(xp[i], zp[i], xp[ii], zp[ii],
441 xp[j], zp[j], xp[jj], zp[jj])) {
443 }
else if (iaxis == 3 && !Crossing(xp[i], yp[i], xp[ii], yp[ii],
444 xp[j], yp[j], xp[jj], yp[jj])) {
448 for (
unsigned int k = 0; k < (j - i) / 2; ++k) {
449 const unsigned int k1 = (i + k + 1) % np;
450 const unsigned int k2 = (j - k) % np;
451 std::swap(xp[k1], xp[k2]);
452 std::swap(yp[k1], yp[k2]);
453 std::swap(zp[k1], zp[k2]);
460 if (repass && nPass > np) {
461 std::cerr <<
"Butterfly: unable to eliminate the internal crossings;\n"
462 <<
" plot probably incorrect.\n";
bool NonTrivial(const std::vector< double > &xp, const std::vector< double > &yp)
Check whether a set of points builds a non-trivial polygon.
double Area(const std::vector< double > &xp, const std::vector< double > &yp)
Determine the (signed) area of a polygon.
void EliminateButterflies(std::vector< double > &xp, std::vector< double > &yp, std::vector< double > &zp)
void Inside(const std::vector< double > &xpl, const std::vector< double > &ypl, const double x, const double y, bool &inside, bool &edge)
double RndmUniform()
Draw a random number uniformly distributed in the range [0, 1).
DoubleAc fabs(const DoubleAc &f)