17unsigned int NextPoint(
const unsigned int i,
const unsigned int n) {
18 const unsigned int j = i + 1;
22unsigned int PrevPoint(
const unsigned int i,
const unsigned int n) {
23 return i > 0 ? i - 1 : n - 1;
26double Mag(
const std::array<double, 3>& a) {
27 return sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
30std::array<double, 3> UnitVector(
const std::array<double, 3>& a) {
32 const double mag = Mag(a);
33 if (mag < 1.e-12)
return a;
34 const std::array<double, 3> b = {a[0] / mag, a[1] / mag, a[2] / mag};
37std::array<double, 3> CrossProduct(
const std::array<double, 3>& u,
38 const std::array<double, 3>& v) {
40 const std::array<double, 3> w = {u[1] * v[2] - u[2] * v[1],
41 u[2] * v[0] - u[0] * v[2],
42 u[0] * v[1] - u[1] * v[0]};
46std::array<double, 3> LocalToGlobal(
const double x,
const double y,
48 const std::array<std::array<double, 3>, 3>& dcos,
49 const std::array<double, 3>& t) {
52 std::array<double, 4> u = {
x,
y,
z, 1.};
54 std::array<std::array<double, 4>, 4> rot;
55 rot[0] = {dcos[0][0], dcos[1][0], dcos[2][0], 0.};
56 rot[1] = {dcos[0][1], dcos[1][1], dcos[2][1], 0.};
57 rot[2] = {dcos[0][2], dcos[1][2], dcos[2][2], 0.};
58 rot[3] = {0., 0., 0., 1.};
60 std::array<double, 4> v = {0., 0., 0., 0.};
61 for (
int i = 0; i < 4; ++i) {
62 for (
int j = 0; j < 4; ++j) {
63 v[i] += rot[i][j] * u[j];
66 const std::array<double, 3> a = {v[0] + t[0], v[1] + t[1], v[2] + t[2]};
71double Lambda(
const double x1,
const double x0,
const double x2,
72 const double y1,
const double y0,
const double y2) {
74 if ((x1 - x2) == 0. && (y1 - y2) == 0.) {
75 std::cerr <<
"ComponentNeBem3d::Lambda: Zero length segment.\n";
80 const double dx1 = x0 - x1;
81 const double dy1 = y0 - y1;
82 const double dx2 = x0 - x2;
83 const double dy2 = y0 - y2;
84 if (dx1 * dx1 + dy1 * dy1 < dx2 * dx2 + dy2 * dy2) {
94 xl = 1. - dy2 / (y1 - y2);
96 xl = 1. - dx2 / (x1 - x2);
104bool OnLine(
const double x1,
const double y1,
const double x2,
const double y2,
105 const double u,
const double v) {
107 double epsx = 1.e-10 * std::max({
fabs(x1),
fabs(x2),
fabs(u)});
108 double epsy = 1.e-10 * std::max({
fabs(y1),
fabs(y2),
fabs(v)});
109 epsx = std::max(1.e-10, epsx);
110 epsy = std::max(1.e-10, epsy);
112 if ((
fabs(x1 - u) <= epsx &&
fabs(y1 - v) <= epsy) ||
113 (
fabs(x2 - u) <= epsx &&
fabs(y2 - v) <= epsy)) {
116 }
else if (
fabs(x1 - x2) <= epsx &&
fabs(y1 - y2) <= epsy) {
120 double xc = 0., yc = 0.;
123 const double dx = (x2 - x1);
124 const double dy = (y2 - y1);
125 const double xl = ((u - x1) * dx + (v - y1) * dy) / (dx * dx + dy * dy);
129 }
else if (xl > 1.) {
138 const double dx = (x1 - x2);
139 const double dy = (y1 - y2);
140 const double xl = ((u - x2) * dx + (v - y2) * dy) / (dx * dx + dy * dy);
144 }
else if (xl > 1.) {
153 if (
fabs(u - xc) < epsx &&
fabs(v - yc) < epsy) {
161bool Crossing(
const double x1,
const double y1,
const double x2,
162 const double y2,
const double u1,
const double v1,
163 const double u2,
const double v2,
double& xc,
double& yc) {
165 std::array<std::array<double, 2>, 2> a;
170 const double det = a[0][0] * a[1][1] - a[1][0] * a[0][1];
177 epsx = std::max(epsx, 1.e-10);
178 epsy = std::max(epsy, 1.e-10);
180 if (OnLine(x1, y1, x2, y2, u1, v1)) {
184 }
else if (OnLine(x1, y1, x2, y2, u2, v2)) {
188 }
else if (OnLine(u1, v1, u2, v2, x1, y1)) {
192 }
else if (OnLine(u1, v1, u2, v2, x2, y2)) {
196 }
else if (
fabs(det) < epsx * epsy) {
201 const double aux = a[1][1];
202 a[1][1] = a[0][0] / det;
204 a[1][0] = -a[1][0] / det;
205 a[0][1] = -a[0][1] / det;
207 xc = a[0][0] * (x1 * y2 - x2 * y1) + a[1][0] * (u1 * v2 - u2 * v1);
208 yc = a[0][1] * (x1 * y2 - x2 * y1) + a[1][1] * (u1 * v2 - u2 * v1);
210 if (OnLine(x1, y1, x2, y2, xc, yc) && OnLine(u1, v1, u2, v2, xc, yc)) {
218void AddPoints(
const std::vector<double>& xp1,
const std::vector<double>& yp1,
219 const std::vector<double>& xp2,
const std::vector<double>& yp2,
220 std::vector<double>& xl, std::vector<double>& yl,
221 std::vector<int>& flags, std::vector<double>& qs,
222 const double epsx,
const double epsy) {
230 std::vector<Point> points;
232 const unsigned int np1 = xp1.size();
233 const unsigned int np2 = xp2.size();
234 for (
unsigned int i = 0; i < np1; ++i) {
235 const double xi0 = xp1[i];
236 const double yi0 = yp1[i];
237 const double xi1 = xp1[NextPoint(i, np1)];
238 const double yi1 = yp1[NextPoint(i, np1)];
246 for (
unsigned int j = 0; j < np2; ++j) {
247 const double xj0 = xp2[j];
248 const double yj0 = yp2[j];
249 if (
fabs(xj0 - xi0) < epsx &&
fabs(yj0 - yi0) < epsy) {
252 const double xj1 = xp2[NextPoint(j, np2)];
253 const double yj1 = yp2[NextPoint(j, np2)];
254 if (OnLine(xj0, yj0, xj1, yj1, xi0, yi0) &&
255 (
fabs(xj0 - xi0) > epsx ||
fabs(yj0 - yi0) > epsy) &&
256 (
fabs(xj1 - xi0) > epsx ||
fabs(yj1 - yi0) > epsy)) {
260 points.push_back(std::move(p1));
262 std::vector<Point> pointsOther;
263 for (
unsigned int j = 0; j < np2; ++j) {
264 const double xj0 = xp2[j];
265 const double yj0 = yp2[j];
267 if (OnLine(xi0, yi0, xi1, yi1, xj0, yj0) &&
268 (
fabs(xi0 - xj0) > epsx ||
fabs(yi0 - yj0) > epsy) &&
269 (
fabs(xi1 - xj0) > epsx ||
fabs(yi1 - yj0) > epsy)) {
274 pointsOther.push_back(std::move(p2));
276 const double xj1 = xp2[NextPoint(j, np2)];
277 const double yj1 = yp2[NextPoint(j, np2)];
279 double xc = 0., yc = 0.;
280 bool add = Crossing(xi0, yi0, xi1, yi1, xj0, yj0, xj1, yj1, xc, yc);
282 if ((
fabs(xi0 - xc) < epsx &&
fabs(yi0 - yc) < epsy) ||
283 (
fabs(xi1 - xc) < epsx &&
fabs(yi1 - yc) < epsy) ||
284 (
fabs(xj0 - xc) < epsx &&
fabs(yj0 - yc) < epsy) ||
285 (
fabs(xj1 - xc) < epsx &&
fabs(yj1 - yc) < epsy)) {
288 if ((
fabs(xi0 - xj0) < epsx &&
fabs(yi0 - yj0) < epsy) ||
289 (
fabs(xi0 - xj1) < epsx &&
fabs(yi0 - yj1) < epsy) ||
290 (
fabs(xi1 - xj0) < epsx &&
fabs(yi1 - yj0) < epsy) ||
291 (
fabs(xi1 - xj1) < epsx &&
fabs(yi1 - yj1) < epsy)) {
300 pointsOther.push_back(std::move(p2));
304 for (
auto& p : pointsOther) {
305 p.q = Lambda(xi0, p.x, xi1, yi0, p.y, yi1);
309 pointsOther.begin(), pointsOther.end(),
310 [](
const Point& lhs,
const Point& rhs) { return (lhs.q < rhs.q); });
311 points.insert(points.end(), pointsOther.begin(), pointsOther.end());
314 for (
const Point& p : points) {
317 flags.push_back(p.flag);
324 const double epsx,
const double epsy) {
325 const auto& xp1 = panel1.
xv;
326 const auto& yp1 = panel1.
yv;
327 const auto& xp2 = panel2.
xv;
328 const auto& yp2 = panel2.
yv;
329 if (xp1.empty() || xp2.empty())
return false;
330 const unsigned int np1 = xp1.size();
331 const unsigned int np2 = xp2.size();
334 for (
unsigned int i = 0; i < np1; ++i) {
337 for (
unsigned int j = 0; j < np2; ++j) {
338 if (
fabs(xp2[j] - xp1[i]) < epsx &&
fabs(yp2[j] - yp1[i]) < epsy) {
342 const unsigned int jj = NextPoint(j, np2);
343 if (OnLine(xp2[j], yp2[j], xp2[jj], yp2[jj], xp1[i], yp1[i])) {
348 if (!match)
return false;
352 for (
unsigned int i = 0; i < np2; ++i) {
355 for (
unsigned int j = 0; j < np1; ++j) {
356 if (
fabs(xp2[i] - xp1[j]) < epsx &&
fabs(yp2[i] - yp1[j]) < epsy) {
360 const unsigned int jj = NextPoint(j, np1);
361 if (OnLine(xp1[j], yp1[j], xp1[jj], yp1[jj], xp2[i], yp2[i])) {
366 if (!match)
return false;
382 const double z,
double& ex,
double& ey,
383 double& ez,
double& v,
Medium*& m,
385 ex = ey = ez = v = 0.;
396 std::cerr <<
m_className <<
"::ElectricField: Initialisation failed.\n";
405 const double z,
double& ex,
double& ey,
406 double& ez,
Medium*& m,
int& status) {
419 if (length < MinDist) {
420 std::cerr <<
m_className <<
"::SetTargetElementSize: Value must be > "
424 m_targetElementSize = length;
429 m_primitives.clear();
433 std::cerr <<
m_className <<
"::Initialise: Geometry not set.\n";
439 std::map<int, Solid*> solids;
440 std::map<int, Solid::BoundaryCondition> bc;
441 std::map<int, double> volt;
442 std::map<int, double> eps;
443 std::map<int, double> charge;
445 std::vector<Panel> panelsIn;
446 for (
unsigned int i = 0; i < nSolids; ++i) {
449 if (!solid)
continue;
453 const auto id = solid->GetId();
455 bc[id] = solid->GetBoundaryConditionType();
456 volt[id] = solid->GetBoundaryPotential();
457 charge[id] = solid->GetBoundaryChargeDensity();
477 const double epsang = 1.e-6;
478 const double epsxyz = 1.e-6;
481 const unsigned int nIn = panelsIn.size();
483 std::cout <<
m_className <<
"::Initialise: Retrieved "
484 << nIn <<
" panels from the solids.\n";
487 std::vector<bool> mark(nIn,
false);
489 for (
unsigned int i = 0; i < nIn; ++i) {
491 if (mark[i])
continue;
493 const double a1 = panelsIn[i].a;
494 const double b1 = panelsIn[i].b;
495 const double c1 = panelsIn[i].c;
496 const auto& xp1 = panelsIn[i].xv;
497 const auto& yp1 = panelsIn[i].yv;
498 const auto& zp1 = panelsIn[i].zv;
499 const unsigned int np1 = xp1.size();
501 const double d1 = a1 * xp1[0] + b1 * yp1[0] + c1 * zp1[0];
503 std::cout <<
" Panel " << i <<
"\n Norm vector: "
504 << a1 <<
", " << b1 <<
", " << c1 <<
", " << d1 <<
".\n";
507 std::array<std::array<double, 3>, 3> rot;
508 if (fabs(c1) <= fabs(a1) && fabs(c1) <= fabs(b1)) {
510 rot[0][0] = b1 / sqrt(a1 * a1 + b1 * b1);
511 rot[0][1] = -a1 / sqrt(a1 * a1 + b1 * b1);
513 }
else if (fabs(b1) <= fabs(a1) && fabs(b1) <= fabs(c1)) {
515 rot[0][0] = c1 / sqrt(a1 * a1 + c1 * c1);
517 rot[0][2] = -a1 / sqrt(a1 * a1 + c1 * c1);
521 rot[0][1] = c1 / sqrt(b1 * b1 + c1 * c1);
522 rot[0][2] = -b1 / sqrt(b1 * b1 + c1 * c1);
527 rot[1][0] = rot[2][1] * rot[0][2] - rot[2][2] * rot[0][1];
528 rot[1][1] = rot[2][2] * rot[0][0] - rot[2][0] * rot[0][2];
529 rot[1][2] = rot[2][0] * rot[0][1] - rot[2][1] * rot[0][0];
531 std::vector<double> xp(np1, 0.);
532 std::vector<double> yp(np1, 0.);
533 std::vector<double> zp(np1, 0.);
535 for (
unsigned int k = 0; k < np1; ++k) {
536 xp[k] = rot[0][0] * xp1[k] + rot[0][1] * yp1[k] + rot[0][2] * zp1[k];
537 yp[k] = rot[1][0] * xp1[k] + rot[1][1] * yp1[k] + rot[1][2] * zp1[k];
538 zp[k] = rot[2][0] * xp1[k] + rot[2][1] * yp1[k] + rot[2][2] * zp1[k];
543 std::vector<Panel> newPanels;
544 std::vector<int> vol1;
545 std::vector<int> vol2;
546 Panel panel1 = panelsIn[i];
550 vol1.push_back(panel1.
volume);
552 newPanels.push_back(std::move(panel1));
554 for (
unsigned int j = i + 1; j < nIn; ++j) {
555 if (mark[j])
continue;
556 const double a2 = panelsIn[j].a;
557 const double b2 = panelsIn[j].b;
558 const double c2 = panelsIn[j].c;
559 const auto& xp2 = panelsIn[j].xv;
560 const auto& yp2 = panelsIn[j].yv;
561 const auto& zp2 = panelsIn[j].zv;
562 const unsigned int np2 = xp2.size();
564 const double d2 = a2 * xp2[0] + b2 * yp2[0] + c2 * zp2[0];
566 const double dot = a1 * a2 + b1 * b2 + c1 * c2;
568 const double offset = d1 - d2 * dot;
569 if (fabs(fabs(dot) - 1.) > epsang || fabs(offset) > epsxyz)
continue;
572 if (
m_debug) std::cout <<
" Match with panel " << j <<
".\n";
578 for (
unsigned int k = 0; k < np2; ++k) {
579 xp[k] = rot[0][0] * xp2[k] + rot[0][1] * yp2[k] + rot[0][2] * zp2[k];
580 yp[k] = rot[1][0] * xp2[k] + rot[1][1] * yp2[k] + rot[1][2] * zp2[k];
581 zp[k] = rot[2][0] * xp2[k] + rot[2][1] * yp2[k] + rot[2][2] * zp2[k];
586 Panel panel2 = panelsIn[j];
590 vol1.push_back(panel2.
volume);
592 newPanels.push_back(std::move(panel2));
594 std::vector<bool> obsolete(newPanels.size(),
false);
596 unsigned int jmin = 0;
600 const unsigned int n = newPanels.size();
601 for (
unsigned int j = 0; j < n; ++j) {
602 if (obsolete[j] || j < jmin)
continue;
603 if (vol1[j] >= 0 && vol2[j] >= 0)
continue;
604 const auto& panelj = newPanels[j];
605 for (
unsigned int k = j + 1; k < n; ++k) {
606 if (obsolete[k])
continue;
607 if (vol1[k] >= 0 && vol2[k] >= 0)
continue;
608 const auto& panelk = newPanels[k];
609 if (
m_debug) std::cout <<
" Cutting " << j <<
", " << k <<
".\n";
611 std::vector<Panel> panelsOut;
612 std::vector<int> itypo;
613 EliminateOverlaps(panelj, panelk, panelsOut, itypo);
614 const unsigned int nOut = panelsOut.size();
617 const double epsx = epsxyz;
618 const double epsy = epsxyz;
620 const bool equal1 = Equal(panelj, panelsOut[0], epsx, epsy);
621 const bool equal2 = Equal(panelj, panelsOut[1], epsx, epsy);
622 const bool equal3 = Equal(panelk, panelsOut[0], epsx, epsy);
623 const bool equal4 = Equal(panelk, panelsOut[1], epsx, epsy);
624 if ((equal1 || equal3) && (equal2 || equal4)) {
626 std::cout <<
" Original and new panels are identical.\n";
634 if (
m_debug) std::cout <<
" Change flag: " << change <<
".\n";
636 if (!change)
continue;
642 for (
unsigned int l = 0; l < nOut; ++l) {
644 vol1.push_back(std::max(vol1[j], vol2[j]));
646 }
else if (itypo[l] == 2) {
647 vol1.push_back(std::max(vol1[k], vol2[k]));
650 vol1.push_back(std::max(vol1[j], vol2[j]));
651 vol2.push_back(std::max(vol1[k], vol2[k]));
653 newPanels.push_back(std::move(panelsOut[l]));
654 obsolete.push_back(
false);
664 const unsigned int nNew = newPanels.size();
665 for (
unsigned int j = 0; j < nNew; ++j) {
666 if (obsolete[j])
continue;
668 int interfaceType = 0;
669 double potential = 0.;
671 double chargeDensity = 0.;
673 std::cout <<
" Volume 1: " << vol1[j]
674 <<
". Volume 2: " << vol2[j] <<
".\n";
676 if (vol1[j] < 0 && vol2[j] < 0) {
679 }
else if (vol1[j] < 0 || vol2[j] < 0) {
681 const auto vol = vol1[j] < 0 ? vol2[j] : vol1[j];
682 interfaceType = InterfaceType(bc[vol]);
685 if (fabs(eps[vol] - 1.) < 1.e-6) {
689 lambda = (eps[vol] - 1.) / (eps[vol] + 1.);
692 potential = volt[vol];
695 chargeDensity = charge[vol];
698 const auto bc1 = bc[vol1[j]];
699 const auto bc2 = bc[vol2[j]];
702 interfaceType = InterfaceType(bc1);
706 potential = volt[vol1[j]];
708 chargeDensity = charge[vol1[j]];
714 const double v1 = volt[vol1[j]];
715 const double v2 = volt[vol2[j]];
716 if (fabs(v1 - v2) < 1.e-6 * (1. + fabs(v1) + fabs(v2))) {
722 interfaceType = InterfaceType(bc2);
725 potential = volt[vol2[j]];
727 chargeDensity = charge[vol2[j]];
730 const double eps1 = eps[vol1[j]];
731 const double eps2 = eps[vol2[j]];
732 if (fabs(eps1 - eps2) < 1.e-6 * (1. + fabs(eps1) + fabs(eps2))) {
736 lambda = (eps1 - eps2) / (eps1 + eps2);
742 if (interfaceType < 0) {
743 std::cout <<
" Conflicting boundary conditions. Skip.\n";
744 }
else if (interfaceType < 1) {
745 std::cout <<
" Trivial interface. Skip.\n";
746 }
else if (interfaceType > 5) {
747 std::cout <<
" Interface type " << interfaceType
748 <<
" is not implemented. Skip.\n";
751 if (interfaceType < 1 || interfaceType > 5)
continue;
753 std::vector<Panel> panelsOut;
755 if (
m_debug) std::cout <<
" Creating primitives.\n";
756 MakePrimitives(newPanels[j], panelsOut);
758 for (
auto& panel : panelsOut) {
759 const auto& up = panel.xv;
760 const auto& vp = panel.yv;
761 const auto& wp = panel.zv;
762 const unsigned int np = up.size();
767 for (
unsigned int k = 0; k < np; ++k) {
768 xp[k] = rot[0][0] * up[k] + rot[1][0] * vp[k] + rot[2][0] * wp[k];
769 yp[k] = rot[0][1] * up[k] + rot[1][1] * vp[k] + rot[2][1] * wp[k];
770 zp[k] = rot[0][2] * up[k] + rot[1][2] * vp[k] + rot[2][2] * wp[k];
773 primitive.a = panel.a;
774 primitive.b = panel.b;
775 primitive.c = panel.c;
779 primitive.v = potential;
780 primitive.q = chargeDensity;
781 primitive.lambda = lambda;
782 primitive.interface = interfaceType;
784 primitive.elementSize = -1.;
785 if (solids.find(vol1[j]) != solids.end()) {
786 const auto solid = solids[vol1[j]];
788 primitive.elementSize = solid->GetDiscretisationLevel(panel);
791 m_primitives.push_back(std::move(primitive));
798 <<
" Created " << m_primitives.size() <<
" primitives.\n";
802 for (
const auto& primitive : m_primitives) {
803 const auto nVertices = primitive.xv.size();
804 if (nVertices < 2 || nVertices > 4)
continue;
805 std::vector<Element> elements;
807 double targetSize = primitive.elementSize;
808 if (targetSize < MinDist) targetSize = m_targetElementSize;
809 if (nVertices == 2) {
810 DiscretizeWire(primitive, targetSize, elements);
811 }
else if (nVertices == 3) {
812 DiscretizeTriangle(primitive, targetSize, elements);
813 }
else if (nVertices == 4) {
814 DiscretizeRectangle(primitive, targetSize, elements);
816 for (
auto& element: elements) {
817 element.interface = primitive.interface;
818 element.lambda = primitive.lambda;
819 element.bc = primitive.v;
820 element.assigned = primitive.q;
821 element.solution = 0.;
823 m_elements.insert(m_elements.end(),
824 std::make_move_iterator(elements.begin()),
825 std::make_move_iterator(elements.end()));
875bool ComponentNeBem3d::DiscretizeWire(
const Primitive& primitive,
876 const double targetSize, std::vector<Element>& elements)
const {
878 const double dx = primitive.xv[1] - primitive.xv[0];
879 const double dy = primitive.yv[1] - primitive.yv[0];
880 const double dz = primitive.zv[1] - primitive.zv[0];
881 const double lw =
sqrt(dx * dx + dy * dy + dz * dz);
883 unsigned int nSegments = NbOfSegments(lw, targetSize);
884 const double elementSize = lw / nSegments;
888 const std::array<double, 3> zu = {dx / lw, dy / lw, dz / lw};
890 std::array<double, 3> xu;
892 xu = {-zu[1], zu[0], 0.};
894 xu = {-zu[2], 0., zu[0]};
896 xu = {0., zu[2], -zu[1]};
900 const std::array<double, 3> yu = UnitVector(CrossProduct(zu, xu));
901 const std::array<std::array<double, 3>, 3> dcos = {xu, yu, zu};
903 const double xincr = dx / nSegments;
904 const double yincr = dy / nSegments;
905 const double zincr = dz / nSegments;
908 const double radius = 1.;
909 const double dA = TwoPi * radius * elementSize;
910 for (
unsigned int i = 0; i < nSegments; ++i) {
911 const double x0 = primitive.xv[0] + i * xincr;
912 const double y0 = primitive.yv[0] + i * yincr;
913 const double z0 = primitive.zv[0] + i * zincr;
915 element.origin = {x0 + 0.5 * xincr, y0 + 0.5 * yincr, z0 + 0.5 * zincr};
916 element.xv = {x0, x0 + xincr};
917 element.yv = {y0, y0 + yincr};
918 element.zv = {z0, z0 + zincr};
920 element.lz = elementSize;
924 element.collocationPoint = element.origin;
925 elements.push_back(std::move(element));
930bool ComponentNeBem3d::DiscretizeTriangle(
const Primitive& primitive,
931 const double targetSize, std::vector<Element>& elements)
const {
934 std::array<double, 3> corner = {primitive.xv[1], primitive.yv[1],
937 const double dx1 = primitive.xv[0] - primitive.xv[1];
938 const double dy1 = primitive.yv[0] - primitive.yv[1];
939 const double dz1 = primitive.zv[0] - primitive.zv[1];
940 const double dx2 = primitive.xv[2] - primitive.xv[1];
941 const double dy2 = primitive.yv[2] - primitive.yv[1];
942 const double dz2 = primitive.zv[2] - primitive.zv[1];
944 std::array<double, 3> nu = {primitive.a, primitive.b, primitive.c};
948 double lx =
sqrt(dx1 * dx1 + dy1 * dy1 + dz1 * dz1);
949 double lz =
sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2);
950 std::array<double, 3> xu = {dx1 / lx, dy1 / lx, dz1 / lx};
951 std::array<double, 3> zu = {dx2 / lz, dy2 / lz, dz2 / lz};
952 std::array<double, 3> yu = CrossProduct(zu, xu);
953 constexpr double tol = 1.e-3;
954 if ((
fabs(yu[0] - nu[0]) > tol) || (
fabs(yu[1] - nu[1]) > tol) ||
955 (
fabs(yu[2] - nu[2]) > tol)) {
959 xu = {dx2 / lx, dy2 / lx, dz2 / lx};
960 zu = {dx1 / lz, dy1 / lz, dz1 / lz};
961 yu = CrossProduct(zu, xu);
962 if ((
fabs(yu[0] - nu[0]) > tol) || (
fabs(yu[1] - nu[1]) > tol) ||
963 (
fabs(yu[2] - nu[2]) > tol)) {
965 std::cerr <<
m_className <<
"::DiscretizeTriangle:\n"
966 <<
" Could not establish direction vectors.\n";
970 std::array<std::array<double, 3>, 3> dcos = {xu, yu, zu};
980 unsigned int nx = NbOfSegments(lx, targetSize);
981 unsigned int nz = NbOfSegments(lz, targetSize);
982 double elementSizeX = lx / nx;
983 double elementSizeZ = lz / nz;
986 double ar = elementSizeX / elementSizeZ;
989 elementSizeZ = 0.1 * elementSizeX;
990 nz = std::max(
static_cast<int>(lz / elementSizeZ), 1);
991 elementSizeZ = lz / nz;
995 elementSizeX = 0.1 * elementSizeZ;
996 nx = std::max(
static_cast<int>(lx / elementSizeX), 1);
997 elementSizeX = lx / nx;
999 const double dxdz = lx / lz;
1000 for (
unsigned int k = 0; k < nz; ++k) {
1002 const double zlo = k * elementSizeZ;
1003 const double zhi = (k + 1) * elementSizeZ;
1004 double xlo = (lz - zlo) * dxdz;
1005 double xhi = (lz - zhi) * dxdz;
1008 triangle.origin = LocalToGlobal(xhi, 0., zlo, dcos, corner);
1010 const double triangleSizeX = xlo - xhi;
1011 triangle.lx = triangleSizeX;
1012 triangle.lz = elementSizeZ;
1013 triangle.dA = 0.5 * triangleSizeX * elementSizeZ;
1014 triangle.dcos = dcos;
1016 const double xv0 = triangle.origin[0];
1017 const double yv0 = triangle.origin[1];
1018 const double zv0 = triangle.origin[2];
1019 const double xv1 = xv0 + triangleSizeX * xu[0];
1020 const double yv1 = yv0 + triangleSizeX * xu[1];
1021 const double zv1 = zv0 + triangleSizeX * xu[2];
1022 const double xv2 = xv0 + elementSizeZ * zu[0];
1023 const double yv2 = yv0 + elementSizeZ * zu[1];
1024 const double zv2 = zv0 + elementSizeZ * zu[2];
1026 triangle.xv = {xv0, xv1, xv2};
1027 triangle.yv = {yv0, yv1, yv2};
1028 triangle.zv = {zv0, zv1, zv2};
1032 const double xb = triangleSizeX / 3.;
1033 const double yb = 0.;
1034 const double zb = elementSizeZ / 3.;
1035 triangle.collocationPoint = LocalToGlobal(xb, yb, zb, dcos, triangle.origin);
1036 elements.push_back(std::move(triangle));
1038 if (k == nz - 1)
continue;
1041 const int nRect = xhi <= elementSizeX ? 1 : (int)(xhi / elementSizeX);
1042 const double rectSizeX = xhi / nRect;
1043 const double zc = 0.5 * (zlo + zhi);
1044 for (
int i = 0; i < nRect; ++i) {
1046 const double xc = (i + 0.5) * rectSizeX;
1047 const double yc = 0.;
1048 std::array<double, 3> centre = LocalToGlobal(xc, yc, zc, dcos, corner);
1051 rect.origin = centre;
1052 rect.lx = rectSizeX;
1053 rect.lz = elementSizeZ;
1054 rect.dA = rectSizeX * elementSizeZ;
1058 rect.collocationPoint = centre;
1060 const double hx = 0.5 * rectSizeX;
1061 const double hz = 0.5 * elementSizeZ;
1062 std::array<double, 3> p0 = LocalToGlobal(-hx, 0., -hz, dcos, centre);
1063 std::array<double, 3> p1 = LocalToGlobal( hx, 0., -hz, dcos, centre);
1064 std::array<double, 3> p2 = LocalToGlobal( hx, 0., hz, dcos, centre);
1065 std::array<double, 3> p3 = LocalToGlobal(-hx, 0., hz, dcos, centre);
1067 rect.xv = {p0[0], p1[0], p2[0], p3[0]};
1068 rect.yv = {p0[1], p1[1], p2[1], p3[1]};
1069 rect.zv = {p0[2], p1[2], p2[2], p3[2]};
1070 elements.push_back(std::move(rect));
1076bool ComponentNeBem3d::DiscretizeRectangle(
const Primitive& primitive,
1077 const double targetSize, std::vector<Element>& elements)
const {
1079 std::array<double, 3> origin = {
1080 0.25 * std::accumulate(primitive.xv.begin(), primitive.xv.end(), 0.),
1081 0.25 * std::accumulate(primitive.yv.begin(), primitive.yv.end(), 0.),
1082 0.25 * std::accumulate(primitive.zv.begin(), primitive.zv.end(), 0.)};
1085 const double dx1 = primitive.xv[1] - primitive.xv[0];
1086 const double dy1 = primitive.yv[1] - primitive.yv[0];
1087 const double dz1 = primitive.zv[1] - primitive.zv[0];
1088 const double dx2 = primitive.xv[2] - primitive.xv[1];
1089 const double dy2 = primitive.yv[2] - primitive.yv[1];
1090 const double dz2 = primitive.zv[2] - primitive.zv[1];
1091 double lx =
sqrt(dx1 * dx1 + dy1 * dy1 + dz1 * dz1);
1092 double lz =
sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2);
1093 const std::array<double, 3> xu = {dx1 / lx, dy1 / lx, dz1 / lx};
1094 const std::array<double, 3> yu = {primitive.a, primitive.b, primitive.c};
1095 const std::array<double, 3> zu = CrossProduct(xu, yu);
1096 const std::array<std::array<double, 3>, 3> dcos = {xu, yu, zu};
1099 unsigned int nx = NbOfSegments(lx, targetSize);
1100 unsigned int nz = NbOfSegments(lz, targetSize);
1102 double elementSizeX = lx / nx;
1103 double elementSizeZ = lz / nz;
1106 double ar = elementSizeX / elementSizeZ;
1109 elementSizeZ = 0.1 * elementSizeX;
1110 nz = std::max(
static_cast<int>(lz / elementSizeZ), 1);
1111 elementSizeZ = lz / nz;
1115 elementSizeX = 0.1 * elementSizeZ;
1116 nx = std::max(
static_cast<int>(lx / elementSizeX), 1);
1117 elementSizeX = lx / nx;
1120 const double dA = elementSizeX * elementSizeZ;
1121 for (
unsigned int i = 0; i < nx; ++i) {
1123 const double xav = -0.5 * lx + (i + 0.5) * elementSizeX;
1124 for (
unsigned int k = 0; k < nz; ++k) {
1125 const double zav = -0.5 * lz + (k + 0.5) * elementSizeZ;
1127 std::array<double, 3> centre = LocalToGlobal(xav, 0., zav, dcos, origin);
1129 element.origin = centre;
1130 element.lx = elementSizeX;
1131 element.lz = elementSizeZ;
1133 element.dcos = dcos;
1134 element.collocationPoint = centre;
1136 const double hx = 0.5 * elementSizeX;
1137 const double hz = 0.5 * elementSizeZ;
1138 std::array<double, 3> p0 = LocalToGlobal(-hx, 0., -hz, dcos, centre);
1139 std::array<double, 3> p1 = LocalToGlobal( hx, 0., -hz, dcos, centre);
1140 std::array<double, 3> p2 = LocalToGlobal( hx, 0., hz, dcos, centre);
1141 std::array<double, 3> p3 = LocalToGlobal(-hx, 0., hz, dcos, centre);
1143 element.xv = {p0[0], p1[0], p2[0], p3[0]};
1144 element.yv = {p0[1], p1[1], p2[1], p3[1]};
1145 element.zv = {p0[2], p1[2], p2[2], p3[2]};
1146 elements.push_back(std::move(element));
1152unsigned int ComponentNeBem3d::NbOfSegments(
const double length,
1153 const double target)
const {
1156 if (length < MinDist)
return 1;
1157 unsigned int n =
static_cast<unsigned int>(length / target);
1158 if (n < m_minNbElementsOnLength) {
1160 n = m_minNbElementsOnLength;
1161 if (length < n * MinDist) {
1163 n =
static_cast<unsigned int>(length / MinDist);
1170 return std::min(n, m_maxNbElementsOnLength);
1173bool ComponentNeBem3d::EliminateOverlaps(
const Panel& panel1,
1174 const Panel& panel2,
1175 std::vector<Panel>& panelsOut,
1176 std::vector<int>& itypo) {
1181 const auto& xp1 = panel1.xv;
1182 const auto& yp1 = panel1.yv;
1183 const auto& zp1 = panel1.zv;
1184 const auto& xp2 = panel2.xv;
1185 const auto& yp2 = panel2.yv;
1186 const auto& zp2 = panel2.zv;
1188 if (xp1.size() <= 2 || xp2.size() <= 2) {
1192 const double xmin1 = *std::min_element(std::begin(xp1), std::end(xp1));
1193 const double ymin1 = *std::min_element(std::begin(yp1), std::end(yp1));
1194 const double xmax1 = *std::max_element(std::begin(xp1), std::end(xp1));
1195 const double ymax1 = *std::max_element(std::begin(yp1), std::end(yp1));
1197 const double xmin2 = *std::min_element(std::begin(xp2), std::end(xp2));
1198 const double ymin2 = *std::min_element(std::begin(yp2), std::end(yp2));
1199 const double xmax2 = *std::max_element(std::begin(xp2), std::end(xp2));
1200 const double ymax2 = *std::max_element(std::begin(yp2), std::end(yp2));
1202 const double xmin = std::min(xmin1, xmin2);
1203 const double ymin = std::min(ymin1, ymin2);
1204 const double xmax = std::max(xmax1, xmax2);
1205 const double ymax = std::max(ymax1, ymax2);
1207 const double epsx = 1.e-6 * std::max(std::abs(xmax), std::abs(xmin));
1208 const double epsy = 1.e-6 * std::max(std::abs(ymax), std::abs(ymin));
1210 const double zsum1 = std::accumulate(std::begin(zp1), std::end(zp1), 0.);
1211 const double zsum2 = std::accumulate(std::begin(zp2), std::end(zp2), 0.);
1212 const double zmean = (zsum1 + zsum2) / (zp1.size() + zp2.size());
1214 std::array<std::vector<double>, 2> xl;
1215 std::array<std::vector<double>, 2> yl;
1216 std::array<std::vector<int>, 2> flags;
1217 std::array<std::vector<double>, 2> qs;
1219 AddPoints(xp1, yp1, xp2, yp2, xl[0], yl[0], flags[0], qs[0], epsx, epsy);
1221 AddPoints(xp2, yp2, xp1, yp1, xl[1], yl[1], flags[1], qs[1], epsx, epsy);
1225 std::array<std::vector<int>, 2> links;
1226 for (
unsigned int ic = 0; ic < 2; ++ic) {
1227 const unsigned int n1 = xl[ic].size();
1228 links[ic].assign(n1, -1);
1229 const unsigned int jc = ic == 0 ? 1 : 0;
1230 const unsigned int n2 = xl[jc].size();
1231 for (
unsigned int i = 0; i < n1; ++i) {
1232 unsigned int nFound = 0;
1233 for (
unsigned int j = 0; j < n2; ++j) {
1234 if (
fabs(xl[ic][i] - xl[jc][j]) < epsx &&
1235 fabs(yl[ic][i] - yl[jc][j]) < epsy) {
1240 if (nFound == 0 && (flags[ic][i] == 2 || flags[ic][i] == 3)) {
1241 std::cerr <<
m_className <<
"::EliminateOverlaps: "
1242 <<
"Warning. Expected match not found (" << ic <<
"-"
1246 }
else if (nFound > 1) {
1247 std::cerr <<
m_className <<
"::EliminateOverlaps: "
1248 <<
"Warning. More than 1 match found (" << ic <<
"-"
1258 for (
unsigned int j = 0; j < 2; ++j) {
1259 std::cout <<
" Polygon " << j <<
"\n "
1260 <<
" No Type x y Q links\n";
1261 const unsigned int n = xl[j].size();
1262 for (
unsigned int i = 0; i < n; ++i) {
1263 printf(
" %3d %5d %13.6f %13.6f %5.3f %3d\n", i, flags[j][i],
1264 xl[j][i], yl[j][i], qs[j][i], links[j][i]);
1268 if (!ok)
return false;
1270 for (
unsigned int ic = 0; ic < 2; ++ic) {
1272 bool allInside =
true;
1273 const unsigned int np = xl[ic].size();
1274 for (
unsigned int i = 0; i < np; ++i) {
1275 if (flags[ic][i] != 1) {
1279 bool inside =
false, edge =
false;
1285 if (!(inside || edge)) {
1293 if (
m_debug) std::cout <<
" Curve 0 fully inside 1.\n";
1295 panelsOut.push_back(panel1);
1297 if (
m_debug) std::cout <<
" Curve 1 fully inside 0.\n";
1299 panelsOut.push_back(panel2);
1301 panelsOut.back().zv.assign(panelsOut.back().xv.size(), zmean);
1303 std::vector<Panel> newPanels;
1305 if (!TraceEnclosed(xl[0], yl[0], xl[1], yl[1], panel2, newPanels)) {
1309 if (!TraceEnclosed(xl[1], yl[1], xl[0], yl[0], panel1, newPanels)) {
1313 for (
auto& panel : newPanels) {
1314 panel.zv.assign(panel.xv.size(), zmean);
1321 panelsOut.insert(panelsOut.end(), newPanels.begin(), newPanels.end());
1326 for (
unsigned int ic = 0; ic < 2; ++ic) {
1327 std::vector<Panel> newPanels;
1328 const unsigned int n = xl[ic].size();
1330 std::vector<bool> mark(n,
false);
1334 std::cout <<
" Searching for starting point on " << ic <<
".\n";
1338 for (
unsigned int i = 0; i < n; ++i) {
1339 const unsigned int ii = NextPoint(i, n);
1341 if (mark[i] || mark[ii])
continue;
1343 bool inside =
false, edge =
false;
1344 const double xm = 0.5 * (xl[ic][i] + xl[ic][ii]);
1345 const double ym = 0.5 * (yl[ic][i] + yl[ic][ii]);
1351 if (inside || edge)
continue;
1357 TraceNonOverlap(xp1, yp1, xl[0], yl[0], xl[1], yl[1], flags[0],
1358 flags[1], links[0], links[1], mark, i, panel1,
1362 TraceNonOverlap(xp2, yp2, xl[1], yl[1], xl[0], yl[0], flags[1],
1363 flags[0], links[1], links[0], mark, i, panel2,
1369 for (
auto& panel : newPanels) {
1370 panel.zv.assign(panel.xv.size(), zmean);
1371 itypo.push_back(ic + 1);
1373 panelsOut.insert(panelsOut.end(), newPanels.begin(), newPanels.end());
1375 std::cout <<
" No further non-overlapped areas of " << ic <<
".\n";
1380 std::vector<Panel> newPanels;
1381 const unsigned int n1 = xl[0].size();
1382 std::vector<bool> mark1(n1,
false);
1387 std::cout <<
" Searching for starting point on overlap.\n";
1389 for (
unsigned int i = 0; i < n1; ++i) {
1391 if (mark1[i])
continue;
1394 int ip2 = links[0][ip1];
1395 if (ip2 < 0 || flags[0][ip1] == 1) {
1396 bool inside =
false, edge =
false;
1398 if (!(inside || edge))
continue;
1399 }
else if (flags[1][ip2] == 1) {
1404 TraceOverlap(xp1, yp1, xp2, yp2, xl[0], yl[0], xl[1], yl[1], flags[0],
1405 links[0], links[1], mark1, ip1, ip2, panel1, newPanels);
1409 for (
auto& panel : newPanels) {
1410 panel.zv.assign(panel.xv.size(), zmean);
1413 panelsOut.insert(panelsOut.end(), newPanels.begin(), newPanels.end());
1415 if (
m_debug) std::cout <<
" No further overlapped areas.\n";
1419bool ComponentNeBem3d::TraceEnclosed(
const std::vector<double>& xl1,
1420 const std::vector<double>& yl1,
1421 const std::vector<double>& xl2,
1422 const std::vector<double>& yl2,
1423 const Panel& panel2,
1424 std::vector<Panel>& panelsOut)
const {
1425 const int n1 = xl1.size();
1426 const int n2 = xl2.size();
1428 unsigned int nFound = 0;
1429 int jp1 = 0, jp2 = 0;
1430 int kp1 = 0, kp2 = 0;
1431 for (
int ip1 = 0; ip1 < n1; ++ip1) {
1432 const double x1 = xl1[ip1];
1433 const double y1 = yl1[ip1];
1434 for (
int ip2 = 0; ip2 < n2; ++ip2) {
1435 if (nFound > 0 && ip2 == jp2)
continue;
1436 const double x2 = xl2[ip2];
1437 const double y2 = yl2[ip2];
1439 for (
int k = 0; k < n1; ++k) {
1440 const int kk = NextPoint(k, n1);
1441 if (k == ip1 || kk == ip1)
continue;
1442 double xc = 0., yc = 0.;
1444 Crossing(x1, y1, x2, y2, xl1[k], yl1[k], xl1[kk], yl1[kk], xc, yc);
1447 if (cross)
continue;
1448 if (
m_debug) std::cout <<
" No crossing with 1.\n";
1449 for (
int k = 0; k < n2; ++k) {
1450 const int kk = NextPoint(k, n2);
1451 if (k == ip2 || kk == ip2)
continue;
1452 double xc = 0., yc = 0.;
1454 Crossing(x1, y1, x2, y2, xl2[k], yl2[k], xl2[kk], yl2[kk], xc, yc);
1457 if (cross)
continue;
1462 std::cout <<
" 1st junction: " << jp1 <<
", " << jp2 <<
".\n";
1469 double xc = 0., yc = 0.;
1470 cross = Crossing(x1, y1, x2, y2, xl1[jp1], yl1[jp1], xl2[jp2], yl2[jp2],
1474 std::cout <<
" 2nd junction: " << kp1 <<
", " << kp2 <<
".\n";
1481 if (nFound > 1)
break;
1484 std::cerr <<
m_className <<
"::TraceEnclosed: Found no cut-out.\n";
1489 std::vector<double> xpl;
1490 std::vector<double> ypl;
1491 if (
m_debug) std::cout <<
" Creating part 1 of area 2.\n";
1492 for (
int ip1 = jp1; ip1 <= kp1; ++ip1) {
1493 if (
m_debug) std::cout <<
" Adding " << ip1 <<
" on 1.\n";
1494 xpl.push_back(xl1[ip1]);
1495 ypl.push_back(yl1[ip1]);
1498 int imax = jp2 < kp2 ? jp2 + n2 : jp2;
1500 for (
int i = kp2; i <= imax; ++i) {
1502 if (
m_debug) std::cout <<
" Adding " << ip2 <<
" on 2.\n";
1503 xpl.push_back(xl2[ip2]);
1504 ypl.push_back(yl2[ip2]);
1508 for (
int ip1 = 0; ip1 < n1; ++ip1) {
1509 if (ip1 == jp1 || ip1 == kp1)
continue;
1510 bool inside =
false, edge =
false;
1519 if (
m_debug) std::cout <<
" Trying the other direction.\n";
1520 xpl.resize(kp1 - jp1 + 1);
1521 ypl.resize(kp1 - jp1 + 1);
1522 imax = jp2 < kp2 ? kp2 : kp2 + n2;
1524 for (
int i = imax; i >= jp2; --i) {
1525 const int ip2 = i % n2;
1526 if (
m_debug) std::cout <<
" Adding " << ip2 <<
" on 2.\n";
1527 xpl.push_back(xl2[ip2]);
1528 ypl.push_back(yl2[ip2]);
1533 Panel newPanel1 = panel2;
1536 panelsOut.push_back(std::move(newPanel1));
1537 if (
m_debug) std::cout <<
" Part 1 has " << xpl.size() <<
" nodes.\n";
1542 if (
m_debug) std::cout <<
" Creating part 2 of area 2.\n";
1544 for (
int i = kp1; i <= imax; ++i) {
1545 const int ip1 = i % n1;
1546 if (
m_debug) std::cout <<
" Adding " << ip1 <<
" on 1.\n";
1547 xpl.push_back(xl1[ip1]);
1548 ypl.push_back(yl1[ip1]);
1552 imax = jp2 > kp2 ? jp2 : jp2 + n2;
1553 for (
int i = imax; i >= kp2; --i) {
1554 const int ip2 = i % n2;
1555 if (
m_debug) std::cout <<
" Adding " << ip2 <<
" on 2.\n";
1556 xpl.push_back(xl2[ip2]);
1557 ypl.push_back(yl2[ip2]);
1560 imax = jp2 > kp2 ? kp2 + n2 : kp2;
1561 for (
int i = jp2; i <= imax; ++i) {
1562 const int ip2 = i % n2;
1563 if (
m_debug) std::cout <<
" Adding " << ip2 <<
" on 2.\n";
1564 xpl.push_back(xl2[ip2]);
1565 ypl.push_back(yl2[ip2]);
1569 Panel newPanel2 = panel2;
1572 panelsOut.push_back(std::move(newPanel2));
1573 if (
m_debug) std::cout <<
" Part 1 has " << xpl.size() <<
" nodes.\n";
1577void ComponentNeBem3d::TraceNonOverlap(
1578 const std::vector<double>& xp1,
const std::vector<double>& yp1,
1579 const std::vector<double>& xl1,
const std::vector<double>& yl1,
1580 const std::vector<double>& xl2,
const std::vector<double>& yl2,
1581 const std::vector<int>& flags1,
const std::vector<int>& flags2,
1582 const std::vector<int>& links1,
const std::vector<int>& links2,
1583 std::vector<bool>& mark1,
int ip1,
const Panel& panel1,
1584 std::vector<Panel>& panelsOut)
const {
1585 const unsigned int n1 = xl1.size();
1586 const unsigned int n2 = xl2.size();
1589 const int is1 = ip1;
1590 std::vector<double> xpl;
1591 std::vector<double> ypl;
1593 xpl.push_back(xl1[ip1]);
1594 ypl.push_back(yl1[ip1]);
1597 std::cout <<
" Start from point " << ip1 <<
" on curve 1.\n";
1600 ip1 = NextPoint(ip1, n1);
1601 xpl.push_back(xl1[ip1]);
1602 ypl.push_back(yl1[ip1]);
1605 std::cout <<
" Next point is " << ip1 <<
" on curve 1.\n";
1609 unsigned int il = 1;
1616 if (il == 1 && flags1[std::max(ip1, 0)] == 1) {
1618 ip1 = NextPoint(ip1, n1);
1624 xpl.push_back(xl1[ip1]);
1625 ypl.push_back(yl1[ip1]);
1627 std::cout <<
" Went to point " << ip1 <<
" on curve 1.\n";
1629 }
else if (il == 1) {
1633 if (dir == +1 || dir == 0) {
1634 const double xm = 0.5 * (xl2[ip2] + xl2[NextPoint(ip2, n2)]);
1635 const double ym = 0.5 * (yl2[ip2] + yl2[NextPoint(ip2, n2)]);
1636 bool inside =
false, edge =
false;
1639 ip2 = NextPoint(ip2, n2);
1646 }
else if (ip1 >= 0) {
1649 xpl.push_back(xl2[ip2]);
1650 ypl.push_back(yl2[ip2]);
1653 std::cout <<
" Added point " << ip2 <<
" along 2 +.\n";
1657 if (dir == -1 || dir == 0) {
1658 const double xm = 0.5 * (xl2[ip2] + xl2[PrevPoint(ip2, n2)]);
1659 const double ym = 0.5 * (yl2[ip2] + yl2[PrevPoint(ip2, n2)]);
1660 bool inside =
false, edge =
false;
1663 ip2 = PrevPoint(ip2, n2);
1670 }
else if (ip1 >= 0) {
1673 xpl.push_back(xl2[ip2]);
1674 ypl.push_back(yl2[ip2]);
1677 std::cout <<
" Added point " << ip2 <<
" along 2 -\n";
1682 ip1 = NextPoint(ip1, n1);
1686 }
else if (ip1 >= 0) {
1689 xpl.push_back(xl1[ip1]);
1690 ypl.push_back(yl1[ip1]);
1691 if (
m_debug) std::cout <<
" Continued over 1.\n";
1693 }
else if (il == 2 && flags2[std::max(ip2, 0)] == 1) {
1695 ip2 = dir > 0 ? NextPoint(ip2, n2) : PrevPoint(ip2, n2);
1700 }
else if (ip1 >= 0) {
1703 xpl.push_back(xl2[ip2]);
1704 ypl.push_back(yl2[ip2]);
1706 std::cout <<
" Went to point " << ip2 <<
" on 2.\n";
1708 }
else if (il == 2) {
1711 ip1 = NextPoint(ip1, n1);
1717 xpl.push_back(xl1[ip1]);
1718 ypl.push_back(yl1[ip1]);
1719 if (
m_debug) std::cout <<
" Resumed 1 at point " << ip1 <<
".\n";
1722 std::cerr <<
m_className <<
"::TraceNonOverlap: Unexpected case.\n";
1727 Panel newPanel = panel1;
1730 panelsOut.push_back(std::move(newPanel));
1732 std::cout <<
" End of curve reached, " << xpl.size() <<
" points.\n";
1736void ComponentNeBem3d::TraceOverlap(
1737 const std::vector<double>& xp1,
const std::vector<double>& yp1,
1738 const std::vector<double>& xp2,
const std::vector<double>& yp2,
1739 const std::vector<double>& xl1,
const std::vector<double>& yl1,
1740 const std::vector<double>& xl2,
const std::vector<double>& yl2,
1741 const std::vector<int>& flags1,
const std::vector<int>& links1,
1742 const std::vector<int>& links2, std::vector<bool>& mark1,
int ip1,
int ip2,
1743 const Panel& panel1, std::vector<Panel>& panelsOut)
const {
1747 const unsigned int n1 = xl1.size();
1748 const unsigned int n2 = xl2.size();
1751 const int is1 = ip1;
1752 const int is2 = ip2;
1753 std::vector<double> xpl;
1754 std::vector<double> ypl;
1755 xpl.push_back(xl1[ip1]);
1756 ypl.push_back(yl1[ip1]);
1760 unsigned int il = 1;
1767 std::cout <<
" Start from point " << ip1 <<
" on curve " << il <<
"\n";
1774 const int ii = NextPoint(ip1, n1);
1781 bool inside =
false, edge =
false;
1782 if (links1[ii] >= 0) {
1784 }
else if (flags1[ii] == 1) {
1788 if (inside || edge) {
1789 const double xm = 0.5 * (xl1[ip1] + xl1[ii]);
1790 const double ym = 0.5 * (yl1[ip1] + yl1[ii]);
1794 if (inside || edge) {
1797 std::cout <<
" Continued to point " << ip1 <<
" on "
1800 xpl.push_back(xl1[ip1]);
1801 ypl.push_back(yl1[ip1]);
1809 <<
"No point 2 reference found; abandoned.\n";
1814 if (links2[NextPoint(ip2, n2)] == ip1LL &&
1815 links2[PrevPoint(ip2, n2)] == ip1LL) {
1817 <<
"Both 2+ and 2- return on 1; not stored.\n";
1819 }
else if (links2[NextPoint(ip2, n2)] == ip1LL) {
1821 std::cout <<
" 2+ is a return to previous point on 1.\n";
1824 }
else if (links2[PrevPoint(ip2, n2)] == ip1LL) {
1826 std::cout <<
" 2- is a return to previous point on 1.\n";
1830 if (
m_debug) std::cout <<
" Both ways are OK.\n";
1834 if (dir == +1 || dir == 0) {
1835 ip2 = NextPoint(ip2, n2);
1837 if (
m_debug) std::cout <<
" Return to start over 2+.\n";
1842 if (inside || edge) {
1844 std::cout <<
" Going to 2+ (point " << ip2 <<
" of 2).\n";
1846 xpl.push_back(xl2[ip2]);
1847 ypl.push_back(yl2[ip2]);
1849 if (links2[ip2] >= 0) {
1854 std::cout <<
" This point is also on curve 1: "
1863 ip2 = PrevPoint(ip2, n2);
1866 if (dir == -1 || dir == 0) {
1867 ip2 = PrevPoint(ip2, n2);
1869 if (
m_debug) std::cout <<
" Return to start over 2-\n";
1874 if (inside || edge) {
1876 std::cout <<
" Going to 2- (point " << ip2 <<
" of 2).\n";
1878 xpl.push_back(xl2[ip2]);
1879 ypl.push_back(yl2[ip2]);
1881 if (links2[ip2] >= 0) {
1886 std::cout <<
" This point is also on 1: " << ip1 <<
".\n";
1895 if (
m_debug) std::cout <<
" Dead end.\n";
1897 }
else if (il == 2) {
1901 <<
"Direction not set; abandoned.\n";
1905 ip2 = dir > 0 ? NextPoint(ip2, n2) : PrevPoint(ip2, n2);
1914 std::cout <<
" Stepped over 2 to point " << ip2 <<
" of 2.\n";
1916 xpl.push_back(xl2[ip2]);
1917 ypl.push_back(yl2[ip2]);
1918 if (links2[ip2] >= 0) {
1923 std::cout <<
" This point is also on curve 1: " << ip1 <<
".\n";
1931 if (xpl.size() <= 2) {
1932 if (
m_debug) std::cout <<
" Too few points.\n";
1934 Panel newPanel = panel1;
1937 panelsOut.push_back(std::move(newPanel));
1941 std::cout <<
" End of curve reached, " << xpl.size() <<
" points.\n";
1945bool ComponentNeBem3d::MakePrimitives(
const Panel& panelIn,
1946 std::vector<Panel>& panelsOut)
const {
1953 const double epsang = 1.e-6;
1955 if (panelIn.xv.empty() || panelIn.yv.empty() || panelIn.zv.empty()) {
1960 std::accumulate(std::begin(panelIn.zv), std::end(panelIn.zv), 0.);
1961 const double zmean = zsum / panelIn.zv.size();
1963 std::vector<Panel> stack;
1964 stack.push_back(panelIn);
1965 stack.back().zv.clear();
1966 for (
unsigned int k = 0; k < stack.size(); ++k) {
1968 const auto& xp1 = stack[k].xv;
1969 const auto& yp1 = stack[k].yv;
1970 const unsigned int np = xp1.size();
1972 std::cout <<
" Polygon " << k <<
" with " << np <<
" nodes.\n";
1976 if (
m_debug) std::cout <<
" Too few points.\n";
1982 const double x12 = xp1[0] - xp1[1];
1983 const double y12 = yp1[0] - yp1[1];
1984 const double x23 = xp1[1] - xp1[2];
1985 const double y23 = yp1[1] - yp1[2];
1986 const double x31 = xp1[2] - xp1[0];
1987 const double y31 = yp1[2] - yp1[0];
1988 const double x32 = xp1[2] - xp1[1];
1989 const double y32 = yp1[2] - yp1[1];
1990 const double x13 = xp1[0] - xp1[2];
1991 const double y13 = yp1[0] - yp1[2];
1992 const double x21 = xp1[1] - xp1[0];
1993 const double y21 = yp1[1] - yp1[0];
1994 const double s12 = x12 * x12 + y12 * y12;
1995 const double s32 = x32 * x32 + y32 * y32;
1996 const double s13 = x13 * x13 + y13 * y13;
1997 const double s23 = x23 * x23 + y23 * y23;
1998 const double s31 = x31 * x31 + y31 * y31;
1999 const double s21 = x21 * x21 + y21 * y21;
2000 if (
fabs(x12 * x32 + y12 * y32) < epsang *
sqrt(s12 * s32)) {
2002 std::cout <<
" Right-angled triangle node 2 - done.\n";
2004 panelsOut.push_back(stack[k]);
2006 }
else if (
fabs(x13 * x23 + y13 * y23) < epsang *
sqrt(s13 * s23)) {
2008 std::cout <<
" Right-angled triangle node 3 - rearrange.\n";
2010 Panel panel = stack[k];
2011 panel.xv = {xp1[1], xp1[2], xp1[0]};
2012 panel.yv = {yp1[1], yp1[2], yp1[0]};
2013 panelsOut.push_back(std::move(panel));
2015 }
else if (
fabs(x31 * x21 + y31 * y21) < epsang *
sqrt(s31 * s21)) {
2017 std::cout <<
" Right-angled triangle node 1 - rearrange.\n";
2019 Panel panel = stack[k];
2020 panel.xv = {xp1[2], xp1[0], xp1[1]};
2021 panel.yv = {yp1[2], yp1[0], yp1[1]};
2022 panelsOut.push_back(std::move(panel));
2028 const double x12 = xp1[0] - xp1[1];
2029 const double y12 = yp1[0] - yp1[1];
2030 const double x23 = xp1[1] - xp1[2];
2031 const double y23 = yp1[1] - yp1[2];
2032 const double x34 = xp1[2] - xp1[3];
2033 const double y34 = yp1[2] - yp1[3];
2034 const double x43 = xp1[3] - xp1[2];
2035 const double y43 = yp1[3] - yp1[2];
2036 const double x14 = xp1[0] - xp1[3];
2037 const double y14 = yp1[0] - yp1[3];
2038 const double x32 = xp1[2] - xp1[1];
2039 const double y32 = yp1[2] - yp1[1];
2041 const double s12 = x12 * x12 + y12 * y12;
2042 const double s23 = x23 * x23 + y23 * y23;
2043 const double s32 = x32 * x32 + y32 * y32;
2044 const double s34 = x34 * x34 + y34 * y34;
2045 const double s43 = x43 * x43 + y43 * y43;
2046 const double s14 = x14 * x14 + y14 * y14;
2047 if (
fabs(x12 * x32 + y12 * y32) < epsang *
sqrt(s12 * s32) &&
2048 fabs(x23 * x43 + y23 * y43) < epsang *
sqrt(s23 * s43) &&
2049 fabs(x14 * x34 + y14 * y34) < epsang *
sqrt(s14 * s34)) {
2050 if (
m_debug) std::cout <<
" Rectangle.\n";
2051 panelsOut.push_back(stack[k]);
2056 if (np >= 4 && SplitTrapezium(stack[k], stack, panelsOut, epsang))
continue;
2059 if (
m_debug) std::cout <<
" Trying to find a right-angle\n";
2060 bool corner =
false;
2061 for (
unsigned int ip = 0; ip < np; ++ip) {
2063 const unsigned int inext = NextPoint(ip, np);
2064 const unsigned int iprev = PrevPoint(ip, np);
2066 const double dxprev = xp1[iprev] - xp1[ip];
2067 const double dyprev = yp1[iprev] - yp1[ip];
2068 const double dxnext = xp1[inext] - xp1[ip];
2069 const double dynext = yp1[inext] - yp1[ip];
2070 if (
fabs(dxprev * dxnext + dyprev * dynext) >
2071 epsang *
sqrt((dxprev * dxprev + dyprev * dyprev) *
2072 (dxnext * dxnext + dynext * dynext))) {
2077 const double xm = 0.5 * (xp1[iprev] + xp1[inext]);
2078 const double ym = 0.5 * (yp1[iprev] + yp1[inext]);
2079 bool inside =
false, edge =
false;
2081 if (!inside)
continue;
2085 for (
unsigned int jp = 0; jp < np; ++jp) {
2087 const unsigned int jnext = NextPoint(jp, np);
2088 if (jp == iprev || jp == ip || jp == inext || jnext == iprev ||
2089 jnext == ip || jnext == inext)
2092 double xc = 0., yc = 0.;
2093 if (Crossing(xp1[iprev], yp1[iprev], xp1[inext], yp1[inext], xp1[jp],
2094 yp1[jp], xp1[jnext], yp1[jnext], xc, yc)) {
2099 if (cross)
continue;
2102 std::cout <<
" Cutting at right-angled corner " << ip <<
"\n";
2105 Panel panel = stack[k];
2106 panel.xv = {xp1[iprev], xp1[ip], xp1[inext]};
2107 panel.yv = {yp1[iprev], yp1[ip], yp1[inext]};
2108 stack.push_back(std::move(panel));
2110 stack[k].xv.erase(stack[k].xv.begin() + ip);
2111 stack[k].yv.erase(stack[k].yv.begin() + ip);
2112 stack.push_back(std::move(stack[k]));
2114 std::cout <<
" Going for another pass, NP = " << np <<
"\n";
2118 if (corner)
continue;
2121 if (
m_debug) std::cout <<
" Trying to find a corner\n";
2123 for (
unsigned int ip = 0; ip < np; ++ip) {
2124 const unsigned int iprev = PrevPoint(ip, np);
2125 const unsigned int inext = NextPoint(ip, np);
2128 const double xm = 0.5 * (xp1[iprev] + xp1[inext]);
2129 const double ym = 0.5 * (yp1[iprev] + yp1[inext]);
2130 bool inside =
false, edge =
false;
2132 if (!inside)
continue;
2136 for (
unsigned int jp = 0; jp < np; ++jp) {
2137 const unsigned int jj = NextPoint(jp, np);
2139 if (jp == iprev || jp == ip || jp == inext || jj == iprev || jj == ip ||
2143 double xc = 0., yc = 0.;
2144 if (Crossing(xp1[iprev], yp1[iprev], xp1[inext], yp1[inext], xp1[jp],
2145 yp1[jp], xp1[jj], yp1[jj], xc, yc)) {
2150 if (cross)
continue;
2152 if (
m_debug) std::cout <<
" Cutting at corner " << ip <<
"\n";
2154 const double x1 = xp1[iprev];
2155 const double x2 = xp1[ip];
2156 const double x3 = xp1[inext];
2157 const double y1 = yp1[iprev];
2158 const double y2 = yp1[ip];
2159 const double y3 = yp1[inext];
2160 const double s21 = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
2161 const double s31 = (x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1);
2162 const double s32 = (x3 - x2) * (x3 - x2) + (y3 - y2) * (y3 - y2);
2163 const double s12 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
2164 const double s13 = (x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3);
2165 const double s23 = (x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3);
2168 ((x2 - x1) * (x3 - x1) + (y2 - y1) * (y3 - y1)) /
sqrt(s21 * s31);
2170 ((x3 - x2) * (x1 - x2) + (y3 - y2) * (y1 - y2)) /
sqrt(s32 * s12);
2172 ((x1 - x3) * (x2 - x3) + (y1 - y3) * (y2 - y3)) /
sqrt(s13 * s23);
2174 const double phi1 =
acos(a1);
2175 const double phi2 =
acos(a2);
2176 const double phi3 =
acos(a3);
2177 std::cout <<
" Angles: " << RadToDegree * phi1 <<
", "
2178 << RadToDegree * phi2 <<
", " << RadToDegree * phi3 <<
"\n";
2179 const double sumphi = phi1 + phi2 + phi3;
2180 std::cout <<
" Sum = " << RadToDegree * sumphi <<
"\n";
2183 if (
fabs(a1) < epsang ||
fabs(a2) < epsang ||
fabs(a3) < epsang) {
2184 if (
m_debug) std::cout <<
" Right-angled corner cut off.\n";
2185 Panel panel = stack[k];
2186 if (
fabs(a1) < epsang) {
2187 panel.xv = {x3, x1, x2};
2188 panel.yv = {y3, y1, y2};
2189 }
else if (
fabs(a2) < epsang) {
2190 panel.xv = {x1, x2, x3};
2191 panel.yv = {y1, y2, y3};
2193 panel.xv = {x2, x3, x1};
2194 panel.yv = {y2, y3, y1};
2196 stack.push_back(std::move(panel));
2197 }
else if (a1 <= a2 && a1 <= a3) {
2198 if (
m_debug) std::cout <<
" A1 < A2, A3 - adding 2 triangles.\n";
2199 const double xc = x2 + a2 * (x3 - x2) *
sqrt(s12 / s32);
2200 const double yc = y2 + a2 * (y3 - y2) *
sqrt(s12 / s32);
2201 Panel panel1 = stack[k];
2202 panel1.xv = {x3, xc, x1};
2203 panel1.yv = {y3, yc, y1};
2204 stack.push_back(std::move(panel1));
2205 Panel panel2 = stack[k];
2206 panel2.xv = {x2, xc, x1};
2207 panel2.yv = {y2, yc, y1};
2208 stack.push_back(std::move(panel2));
2209 }
else if (a2 <= a1 && a2 <= a3) {
2210 if (
m_debug) std::cout <<
" A2 < A1, A3 - adding 2 triangles.\n";
2211 const double xc = x3 + a3 * (x1 - x3) *
sqrt(s23 / s13);
2212 const double yc = y3 + a3 * (y1 - y3) *
sqrt(s23 / s13);
2213 Panel panel1 = stack[k];
2214 panel1.xv = {x1, xc, x2};
2215 panel1.yv = {y1, yc, y2};
2216 stack.push_back(std::move(panel1));
2217 Panel panel2 = stack[k];
2218 panel2.xv = {x3, xc, x2};
2219 panel2.yv = {y3, yc, y2};
2220 stack.push_back(std::move(panel2));
2222 if (
m_debug) std::cout <<
" A3 < A1, A2 - adding 2 triangles.\n";
2223 const double xc = x1 + a1 * (x2 - x1) *
sqrt(s31 / s21);
2224 const double yc = y1 + a1 * (y2 - y1) *
sqrt(s31 / s21);
2225 Panel panel1 = stack[k];
2226 panel1.xv = {x1, xc, x3};
2227 panel1.yv = {y1, yc, y3};
2228 stack.push_back(std::move(panel1));
2229 Panel panel2 = stack[k];
2230 panel2.xv = {x2, xc, x3};
2231 panel2.yv = {y2, yc, y3};
2232 stack.push_back(std::move(panel2));
2235 stack[k].xv.erase(stack[k].xv.begin() + ip);
2236 stack[k].yv.erase(stack[k].yv.begin() + ip);
2237 stack.push_back(std::move(stack[k]));
2239 std::cout <<
" Going for another pass, NP = " << np <<
"\n";
2243 if (corner)
continue;
2244 std::cerr <<
m_className <<
"::MakePrimitives:\n "
2245 <<
"Unable to identify a corner to cut, probably a degenerate "
2249 for (
auto& panel : panelsOut) {
2250 panel.zv.assign(panel.xv.size(), zmean);
2255bool ComponentNeBem3d::SplitTrapezium(
const Panel panelIn,
2256 std::vector<Panel>& stack,
2257 std::vector<Panel>& panelsOut,
2258 const double epsang)
const {
2259 const auto xp1 = panelIn.xv;
2260 const auto yp1 = panelIn.yv;
2261 const unsigned int np = xp1.size();
2262 for (
unsigned int ip = 0; ip < np; ++ip) {
2263 const unsigned int inext = NextPoint(ip, np);
2264 const double xi0 = xp1[ip];
2265 const double yi0 = yp1[ip];
2266 const double xi1 = xp1[inext];
2267 const double yi1 = yp1[inext];
2268 const double dxi = xi0 - xi1;
2269 const double dyi = yi0 - yi1;
2270 const double si2 = dxi * dxi + dyi * dyi;
2271 for (
unsigned int jp = ip + 2; jp < np; ++jp) {
2272 const unsigned int jnext = NextPoint(jp, np);
2274 if (ip == jp || ip == jnext || inext == jp || inext == jnext) {
2277 const double xj0 = xp1[jp];
2278 const double yj0 = yp1[jp];
2279 const double xj1 = xp1[jnext];
2280 const double yj1 = yp1[jnext];
2281 const double dxj = xj0 - xj1;
2282 const double dyj = yj0 - yj1;
2283 const double sj2 = dxj * dxj + dyj * dyj;
2285 const double sij =
sqrt(si2 * sj2);
2286 if (
fabs(dxi * dxj + dyi * dyj + sij) > epsang * sij)
continue;
2288 std::cout <<
" Found parallel sections: "
2289 << ip <<
", " << jp <<
"\n";
2292 if (sj2 <= 0 || si2 <= 0) {
2293 std::cerr <<
m_className <<
"::SplitTrapezium:\n "
2294 <<
"Zero norm segment found; skipped.\n";
2299 ((xi0 - xj0) * (xj1 - xj0) + (yi0 - yj0) * (yj1 - yj0)) / sj2;
2301 ((xi1 - xj0) * (xj1 - xj0) + (yi1 - yj0) * (yj1 - yj0)) / sj2;
2303 ((xj0 - xi0) * (xi1 - xi0) + (yj0 - yi0) * (yi1 - yi0)) / si2;
2305 ((xj1 - xi0) * (xi1 - xi0) + (yj1 - yi0) * (yi1 - yi0)) / si2;
2307 std::cout <<
" xl1 = " << xl1 <<
", xl2 = " << xl2 <<
", "
2308 <<
"xl3 = " << xl3 <<
", xl4 = " << xl4 <<
"\n";
2311 const double r1 = (xl1 + epsang) * (1. + epsang - xl1);
2312 const double r2 = (xl2 + epsang) * (1. + epsang - xl2);
2313 const double r3 = (xl3 + epsang) * (1. + epsang - xl3);
2314 const double r4 = (xl4 + epsang) * (1. + epsang - xl4);
2315 if ((r1 < 0 && r4 < 0) || (r2 < 0 && r3 < 0)) {
2316 if (
m_debug) std::cout <<
" No rectangle.\n";
2320 std::vector<double> xpl(4, 0.);
2321 std::vector<double> ypl(4, 0.);
2325 xpl[1] = xj0 + xl1 * (xj1 - xj0);
2326 ypl[1] = yj0 + xl1 * (yj1 - yj0);
2327 }
else if (r4 >= 0) {
2328 xpl[0] = xi0 + xl4 * (xi1 - xi0);
2329 ypl[0] = yi0 + xl4 * (yi1 - yi0);
2334 xpl[2] = xj0 + xl2 * (xj1 - xj0);
2335 ypl[2] = yj0 + xl2 * (yj1 - yj0);
2338 }
else if (r3 >= 0) {
2341 xpl[3] = xi0 + xl3 * (xi1 - xi0);
2342 ypl[3] = yi0 + xl3 * (yi1 - yi0);
2345 double xm = 0.5 * (xpl[0] + xpl[1]);
2346 double ym = 0.5 * (ypl[0] + ypl[1]);
2347 bool inside =
false, edge =
false;
2349 if (!(inside || edge)) {
2350 if (
m_debug) std::cout <<
" Midpoint 1 not internal.\n";
2353 xm = 0.5 * (xpl[2] + xpl[3]);
2354 ym = 0.5 * (ypl[2] + ypl[3]);
2356 if (!(inside || edge)) {
2357 if (
m_debug) std::cout <<
" Midpoint 2 not internal.\n";
2361 const unsigned int iprev = PrevPoint(ip, np);
2362 const unsigned int jprev = PrevPoint(jp, np);
2365 for (
unsigned int i = 0; i < np; ++i) {
2366 if ((i == iprev && r1 >= 0) || i == ip || (i == inext && r2 >= 0) ||
2367 (i == jprev && r3 >= 0) || i == jp || (i == jnext && r4 >= 0))
2369 const unsigned int ii = NextPoint(i, np);
2370 double xc = 0., yc = 0.;
2371 if (Crossing(xp1[i], yp1[i], xp1[ii], yp1[ii], xpl[0], ypl[0], xpl[1],
2373 Crossing(xp1[i], yp1[i], xp1[ii], yp1[ii], xpl[2], ypl[2], xpl[3],
2376 std::cout <<
" Crossing (edge " << i <<
", " << ii
2377 <<
"), ip = " << ip <<
", jp = " << jp <<
"\n";
2383 if (cross)
continue;
2385 if ((
fabs(xl1) < epsang &&
fabs(xl3) < epsang) ||
2386 (
fabs(1. - xl2) < epsang &&
fabs(1. - xl4) < epsang)) {
2387 if (
m_debug) std::cout <<
" Not stored, degenerate.\n";
2389 if (
m_debug) std::cout <<
" Adding rectangle.\n";
2390 Panel panel = panelIn;
2393 panelsOut.push_back(std::move(panel));
2398 if (
m_debug) std::cout <<
" First non-rectangular section.\n";
2399 for (
unsigned int i = jp + 1; i <= ip + np; ++i) {
2400 const unsigned int ii = i % np;
2401 xpl.push_back(xp1[ii]);
2402 ypl.push_back(yp1[ii]);
2404 if (r1 >= 0 && r4 >= 0) {
2405 if (
m_debug) std::cout <<
" 1-4 degenerate\n";
2406 }
else if (r1 >= 0) {
2407 if (
m_debug) std::cout <<
" Using 1\n";
2408 xpl.push_back(xj0 + xl1 * (xj1 - xj0));
2409 ypl.push_back(yj0 + xl1 * (yj1 - yj0));
2410 }
else if (r4 >= 0) {
2411 if (
m_debug) std::cout <<
" Using 4\n";
2412 xpl.push_back(xi0 + xl4 * (xi1 - xi0));
2413 ypl.push_back(yi0 + xl4 * (yi1 - yi0));
2415 if (
m_debug) std::cout <<
" Neither 1 nor 4, should not happen\n";
2417 if (xpl.size() < 3) {
2419 std::cout <<
" Not stored, only " << xpl.size()
2424 std::cout <<
" Adding non-rectangular part with " << xpl.size()
2427 Panel panel = panelIn;
2430 stack.push_back(std::move(panel));
2435 if (
m_debug) std::cout <<
" Second non-rectangular section.\n";
2436 for (
unsigned int i = ip + 1; i <= jp; ++i) {
2437 const unsigned int ii = i % np;
2438 xpl.push_back(xp1[ii]);
2439 ypl.push_back(yp1[ii]);
2441 if (r2 >= 0 && r3 >= 0) {
2442 if (
m_debug) std::cout <<
" 2-3 degenerate\n";
2443 }
else if (r2 >= 0) {
2444 if (
m_debug) std::cout <<
" Using 2\n";
2445 xpl.push_back(xj0 + xl2 * (xj1 - xj0));
2446 ypl.push_back(yj0 + xl2 * (yj1 - yj0));
2447 }
else if (r3 >= 0) {
2448 if (
m_debug) std::cout <<
" Using 3\n";
2449 xpl.push_back(xi0 + xl3 * (xi1 - xi0));
2450 ypl.push_back(yi0 + xl3 * (yi1 - yi0));
2452 if (
m_debug) std::cout <<
" Neither 2 nor 3, should not happen\n";
2454 if (xpl.size() < 3) {
2456 std::cout <<
" Not stored, only " << xpl.size()
2461 std::cout <<
" Adding non-rectangular part with " << xpl.size()
2464 Panel panel = panelIn;
2467 stack.push_back(std::move(panel));
2476 double& c, std::vector<double>& xv,
2477 std::vector<double>& yv,
2478 std::vector<double>& zv,
int& interface,
2479 double& v,
double& q,
2480 double& lambda)
const {
2481 if (i >= m_primitives.size()) {
2482 std::cerr <<
m_className <<
"::GetPrimitive: Index out of range.\n";
2485 const auto& primitive = m_primitives[i];
2492 interface = primitive.interface;
2495 lambda = primitive.lambda;
2500 std::vector<double>& xv,
2501 std::vector<double>& yv,
2502 std::vector<double>& zv,
int& interface,
2503 double& bc,
double& lambda)
const {
2505 if (i >= m_elements.size()) {
2506 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
2509 const auto& element = m_elements[i];
2513 interface = element.interface;
2515 lambda = element.lambda;
2520 m_primitives.clear();
2526 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2527 <<
" Periodicities are not supported.\n";
Abstract base class for components.
GeometryBase * m_geometry
Pointer to the geometry.
bool m_ready
Ready for use?
std::string m_className
Class name.
bool m_debug
Switch on/off debugging messages.
virtual Medium * GetMedium(const double x, const double y, const double z)
Get the medium at a given location (x, y, z).
ComponentNeBem3d()
Constructor.
void Reset() override
Reset the component.
void UpdatePeriodicity() override
Verify periodicities.
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
bool GetElement(const unsigned int i, std::vector< double > &xv, std::vector< double > &yv, std::vector< double > &zv, int &interface, double &bc, double &lambda) const
void SetTargetElementSize(const double length)
bool GetPrimitive(const unsigned int i, double &a, double &b, double &c, std::vector< double > &xv, std::vector< double > &yv, std::vector< double > &zv, int &interface, double &v, double &q, double &lambda) const
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
virtual unsigned int GetNumberOfSolids() const
Return the number of solids in the geometry.
virtual Solid * GetSolid(const unsigned int) const
Get a solid from the list.
Abstract base class for media.
double GetDielectricConstant() const
Get the relative static dielectric constant.
virtual bool SolidPanels(std::vector< Panel > &panels)=0
Retrieve the surface panels of the solid.
void Inside(const std::vector< double > &xpl, const std::vector< double > &ypl, const double x, const double y, bool &inside, bool &edge)
DoubleAc acos(const DoubleAc &f)
DoubleAc fabs(const DoubleAc &f)
DoubleAc sqrt(const DoubleAc &f)
std::vector< double > zv
Z-coordinates of vertices.
int volume
Reference to solid to which the panel belongs.
std::vector< double > xv
X-coordinates of vertices.
std::vector< double > yv
Y-coordinates of vertices.