23 std::cerr <<
m_className <<
"::SetComponent: Null pointer.\n";
34 std::cerr <<
m_className <<
"::Plot: Component is not defined.\n";
38 double pmin = 0., pmax = 0.;
40 std::cerr <<
m_className <<
"::Plot: Component is not ready.\n";
44 if (!GetPlotLimits())
return false;
53 if (!m_xaxis && !m_yaxis) {
57 if (m_xaxisTitle.empty()) {
58 frame->GetXaxis()->SetTitle(
LabelX().c_str());
60 frame->GetXaxis()->SetTitle(m_xaxisTitle.c_str());
62 if (m_yaxisTitle.empty()) {
63 frame->GetYaxis()->SetTitle(
LabelY().c_str());
65 frame->GetYaxis()->SetTitle(m_yaxisTitle.c_str());
69 if (m_xaxis) m_xaxis->Draw();
70 if (m_yaxis) m_yaxis->Draw();
77 std::cout <<
m_className <<
"::Plot: CST component. Calling DrawCST.\n";
78 DrawCST(componentCST);
86 for (
const auto& dline : m_viewDrift->m_driftLines) {
88 if (dline.second == ViewDrift::Particle::Electron) {
89 gr.SetLineColor(kOrange - 3);
91 gr.SetLineColor(kRed + 1);
93 std::vector<float> xgr;
94 std::vector<float> ygr;
96 for (
const auto& point : dline.first) {
98 float xp = 0., yp = 0.;
99 ToPlane(point[0], point[1], point[2], xp, yp);
101 if (InView(xp, yp)) {
107 gr.DrawGraph(xgr.size(), xgr.data(), ygr.data(),
"lsame");
112 if (m_drawViewRegion && !m_viewRegionX.empty()) {
114 poly.SetLineColor(kSpring + 4);
115 poly.SetLineWidth(3);
116 std::vector<double> xv = m_viewRegionX;
117 std::vector<double> yv = m_viewRegionY;
119 xv.push_back(m_viewRegionX[0]);
120 yv.push_back(m_viewRegionY[0]);
121 poly.DrawPolyLine(xv.size(), xv.data(), yv.data(),
"same");
125 gPad->RedrawAxis(
"g");
129bool ViewFEMesh::GetPlotLimits() {
134 std::vector<double> xg(4, 0.);
135 std::vector<double> yg(4, 0.);
136 std::vector<double> zg(4, 0.);
137 for (
size_t i = 0; i < 4; ++i) {
142 m_xMinBox = *std::min_element(xg.begin(), xg.end());
143 m_xMaxBox = *std::max_element(xg.begin(), xg.end());
144 m_yMinBox = *std::min_element(yg.begin(), yg.end());
145 m_yMaxBox = *std::max_element(yg.begin(), yg.end());
146 m_zMinBox = *std::min_element(zg.begin(), zg.end());
147 m_zMaxBox = *std::max_element(zg.begin(), zg.end());
154 if (!m_component)
return false;
158 <<
" Bounding box of the component is not defined.\n"
159 <<
" Please set the limits explicitly (SetArea).\n";
165 double x0 = 0., y0 = 0., z0 = 0.;
166 double x1 = 0., y1 = 0., z1 = 0.;
169 <<
" Cell boundaries are not defined.\n"
170 <<
" Please set the limits explicitly (SetArea).\n";
187 double xmin = 0., xmax = 0., ymin = 0., ymax = 0.;
188 IntersectPlaneArea(xmin, ymin, xmax, ymax);
189 if (m_viewRegionX.empty()) {
190 std::cerr <<
m_className <<
"::GetPlotLimits: Empty view.\n"
191 <<
" Make sure the viewing plane (SetPlane)\n"
192 <<
" intersects with the bounding box.\n";
203 const double x0,
const double y0,
const double z0) {
204 if (fy * fy + fz * fz > 0) {
205 SetPlane(fx, fy, fz, x0, y0, z0, 1, 0, 0);
207 SetPlane(fx, fy, fz, x0, y0, z0, 0, 1, 0);
212 const double x0,
const double y0,
const double z0,
213 const double hx,
const double hy,
const double hz) {
226 if (!GetPlotLimits()) {
227 std::cerr <<
m_className <<
"::CreateDefaultAxes:\n"
228 <<
" Cannot determine the axis limits.\n";
237 m_xaxis =
new TGaxis(x0, y0, x1, y0, x0, x1, 2405,
"x");
238 m_yaxis =
new TGaxis(x0, y0, x0, y1, y0, y1, 2405,
"y");
241 m_xaxis->SetLabelSize(0.025);
242 m_yaxis->SetLabelSize(0.025);
245 m_xaxis->SetTitleSize(0.03);
246 m_xaxis->SetTitle(
LabelX().c_str());
247 m_yaxis->SetTitleSize(0.03);
248 m_yaxis->SetTitle(
LabelY().c_str());
253void ViewFEMesh::DrawElements() {
255 double mapxmax = m_component->
m_mapmax[0];
256 double mapxmin = m_component->
m_mapmin[0];
257 double mapymax = m_component->
m_mapmax[1];
258 double mapymin = m_component->
m_mapmin[1];
259 double mapzmax = m_component->
m_mapmax[2];
260 double mapzmin = m_component->
m_mapmin[2];
263 double sx = mapxmax - mapxmin;
264 double sy = mapymax - mapymin;
265 double sz = mapzmax - mapzmin;
277 const double dist =
m_plane[3];
283 const int nMinX = perX ? int(
m_xMinBox / sx) - 1 : 0;
284 const int nMaxX = perX ? int(
m_xMaxBox / sx) + 1 : 0;
285 const int nMinY = perY ? int(
m_yMinBox / sy) - 1 : 0;
286 const int nMaxY = perY ? int(
m_yMaxBox / sy) + 1 : 0;
287 const int nMinZ = perZ ? int(
m_zMinBox / sz) - 1 : 0;
288 const int nMaxZ = perZ ? int(
m_zMaxBox / sz) + 1 : 0;
291 if (
dynamic_cast<ComponentCST*
>(m_component)) cst =
true;
295 for (
size_t i = 0; i < nElements; ++i) {
297 bool driftmedium =
false;
298 std::vector<size_t> nodes;
299 if (!m_component->
GetElement(i, mat, driftmedium, nodes))
continue;
301 if (driftmedium && !m_plotMeshBorders)
continue;
303 if (m_disabledMaterial[mat])
continue;
306 const short col = m_colorMap.count(mat) != 0 ? m_colorMap[mat] : 1;
307 gr.SetLineColor(col);
308 if (m_colorMap_fill.count(mat) != 0) {
309 gr.SetFillColor(m_colorMap_fill[mat]);
311 gr.SetFillColor(col);
314 std::string opt =
"";
315 if (m_plotMeshBorders || !m_fillMesh) opt +=
"l";
316 if (m_fillMesh) opt +=
"f";
320 std::vector<double> vx0;
321 std::vector<double> vy0;
322 std::vector<double> vz0;
323 const size_t nNodes = nodes.size();
324 for (
size_t j = 0; j < nNodes; ++j) {
325 double xn = 0., yn = 0., zn = 0.;
326 if (!m_component->
GetNode(nodes[j], xn, yn, zn))
continue;
331 if (vx0.size() != nNodes) {
333 <<
" Error retrieving nodes of element " << i <<
".\n";
337 std::vector<double> vx(nNodes, 0.);
338 std::vector<double> vy(nNodes, 0.);
339 std::vector<double> vz(nNodes, 0.);
341 for (
int nx = nMinX; nx <= nMaxX; nx++) {
342 const double dx = sx * nx;
345 for (
size_t j = 0; j < nNodes; ++j) {
346 vx[j] = mapxmin + (mapxmax - vx0[j]) + dx;
349 for (
size_t j = 0; j < nNodes; ++j) {
355 for (
int ny = nMinY; ny <= nMaxY; ny++) {
356 const double dy = sy * ny;
359 for (
size_t j = 0; j < nNodes; ++j) {
360 vy[j] = mapymin + (mapymax - vy0[j]) + dy;
363 for (
size_t j = 0; j < nNodes; ++j) {
369 for (
int nz = nMinZ; nz <= nMaxZ; nz++) {
370 const double dz = sz * nz;
373 for (
size_t j = 0; j < nNodes; ++j) {
374 vz[j] = mapzmin + (mapzmax - vz0[j]) + dz;
377 for (
size_t j = 0; j < nNodes; ++j) {
383 std::vector<double> vX;
384 std::vector<double> vY;
387 const double pcf = std::max(
388 {std::abs(vx[0]), std::abs(vy[0]), std::abs(vz[0]),
389 std::abs(fx), std::abs(fy), std::abs(fz), std::abs(dist)});
390 const double tol = 1.e-4 * pcf;
392 std::vector<bool> in(nNodes,
false);
394 for (
size_t j = 0; j < nNodes; ++j) {
395 const double d = fx * vx[j] + fy * vy[j] + fz * vz[j] - dist;
396 if (std::abs(d) < tol) {
400 double xp = 0., yp = 0.;
401 ToPlane(vx[j], vy[j], vz[j], xp, yp);
413 if (std::abs(cnt) == (
int)nNodes)
continue;
416 const std::array<std::array<unsigned int, 3>, 8> neighbours = {{
417 {1, 2, 4}, {0, 3, 5}, {0, 3, 6}, {1, 2, 7},
418 {0, 5, 6}, {1, 4, 7}, {2, 4, 7}, {3, 5, 6}
420 for (
size_t j = 0; j < nNodes; ++j) {
421 for (
unsigned int k : neighbours[j]) {
422 if (in[j] || in[k])
continue;
423 if (PlaneCut(vx[j], vy[j], vz[j],
424 vx[k], vy[k], vz[k], xMat)) {
425 vX.push_back(xMat(0, 0));
426 vY.push_back(xMat(1, 0));
432 for (
size_t j = 0; j < nNodes; ++j) {
433 for (
size_t k = j + 1; k < nNodes; ++k) {
434 if (in[j] || in[k])
continue;
435 if (PlaneCut(vx[j], vy[j], vz[j],
436 vx[k], vy[k], vz[k], xMat)) {
437 vX.push_back(xMat(0, 0));
438 vY.push_back(xMat(1, 0));
443 if (vX.size() < 3)
continue;
447 RemoveCrossings(vX, vY);
450 std::vector<double> cX;
451 std::vector<double> cY;
454 ClipToView(vX, vY, cX, cY);
457 if (cX.size() <= 2)
continue;
459 RemoveCrossings(cX, cY);
462 std::vector<float> xgr(cX.begin(), cX.end());
463 std::vector<float> ygr(cY.begin(), cY.end());
464 gr.DrawGraph(xgr.size(), xgr.data(), ygr.data(), opt.c_str());
472void ViewFEMesh::DrawCST(ComponentCST* cst) {
492 double mapxmax = m_component->
m_mapmax[0];
493 double mapxmin = m_component->
m_mapmin[0];
494 double mapymax = m_component->
m_mapmax[1];
495 double mapymin = m_component->
m_mapmin[1];
496 double mapzmax = m_component->
m_mapmax[2];
497 double mapzmin = m_component->
m_mapmin[2];
500 double sx = mapxmax - mapxmin;
501 double sy = mapymax - mapymin;
502 double sz = mapzmax - mapzmin;
511 const int nMinX = perX ? int(
m_xMinBox / sx) - 1 : 0;
512 const int nMaxX = perX ? int(
m_xMaxBox / sx) + 1 : 0;
513 const int nMinY = perY ? int(
m_yMinBox / sy) - 1 : 0;
514 const int nMaxY = perY ? int(
m_yMaxBox / sy) + 1 : 0;
515 const int nMinZ = perZ ? int(
m_zMinBox / sz) - 1 : 0;
516 const int nMaxZ = perZ ? int(
m_zMaxBox / sz) + 1 : 0;
518 std::vector<PolygonInfo> elements;
519 int nMinU = 0, nMaxU = 0, nMinV = 0, nMaxV = 0;
520 double mapumin = 0., mapumax = 0., mapvmin = 0., mapvmax = 0.;
521 double su = 0., sv = 0.;
522 bool mirroru =
false, mirrorv =
false;
523 double uMin, vMin, uMax, vMax;
524 unsigned int n_x, n_y, n_z;
525 cst->GetNumberOfMeshLines(n_x, n_y, n_z);
530 if (fx == 0 && fy == 0 && fz == 1) {
532 std::cout <<
m_className <<
"::DrawCST: Creating x-y mesh view.\n";
534 unsigned int i, j,
z;
535 const double z0 =
m_plane[3] * fz;
536 if (!cst->Coordinate2Index(0, 0, z0, i, j, z)) {
537 std::cerr <<
" Could not determine the z-index of the plane.\n";
540 std::cout <<
" The z-index of the plane is " <<
z <<
".\n";
558 for (
unsigned int y = 0;
y < (n_y - 1);
y++) {
559 for (
unsigned int x = 0;
x < (n_x - 1);
x++) {
560 auto elem = cst->Index2Element(x, y, z);
561 double e_xmin, e_xmax, e_ymin, e_ymax, e_zmin, e_zmax;
562 cst->GetElementBoundaries(elem, e_xmin, e_xmax, e_ymin, e_ymax,
564 PolygonInfo tmp_info;
565 tmp_info.element = elem;
566 tmp_info.p1[0] = e_xmin;
567 tmp_info.p2[0] = e_xmax;
568 tmp_info.p3[0] = e_xmax;
569 tmp_info.p4[0] = e_xmin;
570 tmp_info.p1[1] = e_ymin;
571 tmp_info.p2[1] = e_ymin;
572 tmp_info.p3[1] = e_ymax;
573 tmp_info.p4[1] = e_ymax;
574 elements.push_back(std::move(tmp_info));
577 }
else if (fx == 0 && fy == -1 && fz == 0) {
579 std::cout <<
m_className <<
"::DrawCST: Creating x-z mesh view.\n";
581 unsigned int i = 0, j = 0,
y = 0;
582 const double y0 =
m_plane[3] * fy;
583 if (!cst->Coordinate2Index(0, y0, 0, i, y, j)) {
584 std::cerr <<
" Could not determine the y-index of the plane.\n";
587 std::cout <<
" The y-index of the plane is " <<
y <<
".\n";
606 for (
unsigned int z = 0;
z < (n_z - 1);
z++) {
607 for (
unsigned int x = 0;
x < (n_x - 1);
x++) {
608 auto elem = cst->Index2Element(x, y, z);
609 double e_xmin, e_xmax, e_ymin, e_ymax, e_zmin, e_zmax;
610 cst->GetElementBoundaries(elem, e_xmin, e_xmax, e_ymin, e_ymax,
612 PolygonInfo tmp_info;
613 tmp_info.element = elem;
614 tmp_info.p1[0] = e_xmin;
615 tmp_info.p2[0] = e_xmax;
616 tmp_info.p3[0] = e_xmax;
617 tmp_info.p4[0] = e_xmin;
618 tmp_info.p1[1] = e_zmin;
619 tmp_info.p2[1] = e_zmin;
620 tmp_info.p3[1] = e_zmax;
621 tmp_info.p4[1] = e_zmax;
622 elements.push_back(std::move(tmp_info));
625 }
else if (fx == -1 && fy == 0 && fz == 0) {
627 std::cout <<
m_className <<
"::DrawCST: Creating z-y mesh view.\n";
629 unsigned int i, j,
x;
630 const double x0 =
m_plane[3] * fx;
631 if (!cst->Coordinate2Index(x0, 0, 0, x, i, j)) {
632 std::cerr <<
" Could not determine the x-index of the plane.\n";
635 std::cout <<
" The x-index of the plane is " <<
x <<
".\n";
653 for (
unsigned int z = 0;
z < (n_z - 1);
z++) {
654 for (
unsigned int y = 0;
y < (n_y - 1);
y++) {
655 auto elem = cst->Index2Element(x, y, z);
656 double e_xmin, e_xmax, e_ymin, e_ymax, e_zmin, e_zmax;
657 cst->GetElementBoundaries(elem, e_xmin, e_xmax, e_ymin, e_ymax,
659 PolygonInfo tmp_info;
660 tmp_info.element = elem;
661 tmp_info.p1[0] = e_zmin;
662 tmp_info.p2[0] = e_zmax;
663 tmp_info.p3[0] = e_zmax;
664 tmp_info.p4[0] = e_zmin;
665 tmp_info.p1[1] = e_ymin;
666 tmp_info.p2[1] = e_ymin;
667 tmp_info.p3[1] = e_ymax;
668 tmp_info.p4[1] = e_ymax;
670 elements.push_back(std::move(tmp_info));
675 std::cerr <<
" The given plane name is not known.\n";
676 std::cerr <<
" Please choose one of the following: xy, xz, yz.\n";
680 std::cout <<
m_className <<
"::DrawCST:\n " << elements.size()
681 <<
" elements in the projection of the unit cell.\n";
682 for (
const auto& element : elements) {
684 bool driftmedium =
false;
685 std::vector<size_t> nodes;
686 cst->GetElement(element.element, mat, driftmedium, nodes);
688 if (driftmedium && !m_plotMeshBorders)
continue;
690 if (m_disabledMaterial[mat])
continue;
692 const short col = m_colorMap.count(mat) > 0 ? m_colorMap[mat] : 1;
693 gr.SetLineColor(col);
694 if (m_colorMap_fill.count(mat) > 0) {
695 gr.SetFillColor(m_colorMap_fill[mat]);
697 gr.SetFillColor(col);
699 if (m_plotMeshBorders)
704 for (
int nu = nMinU; nu <= nMaxU; nu++) {
705 for (
int nv = nMinV; nv <= nMaxV; nv++) {
707 float tmp_u[4], tmp_v[4];
708 if (mirroru && nu != 2 * (nu / 2)) {
710 tmp_u[0] = mapumin + (mapumax - element.p1[0]) + su * nu;
711 tmp_u[1] = mapumin + (mapumax - element.p2[0]) + su * nu;
712 tmp_u[2] = mapumin + (mapumax - element.p3[0]) + su * nu;
713 tmp_u[3] = mapumin + (mapumax - element.p4[0]) + su * nu;
716 tmp_u[0] = element.p1[0] + su * nu;
717 tmp_u[1] = element.p2[0] + su * nu;
718 tmp_u[2] = element.p3[0] + su * nu;
719 tmp_u[3] = element.p4[0] + su * nu;
721 if (mirrorv && nv != 2 * (nv / 2)) {
722 tmp_v[0] = mapvmin + (mapvmax - element.p1[1]) + sv * nv;
723 tmp_v[1] = mapvmin + (mapvmax - element.p2[1]) + sv * nv;
724 tmp_v[2] = mapvmin + (mapvmax - element.p3[1]) + sv * nv;
725 tmp_v[3] = mapvmin + (mapvmax - element.p4[1]) + sv * nv;
727 tmp_v[0] = element.p1[1] + sv * nv;
728 tmp_v[1] = element.p2[1] + sv * nv;
729 tmp_v[2] = element.p3[1] + sv * nv;
730 tmp_v[3] = element.p4[1] + sv * nv;
732 if (tmp_u[0] < uMin || tmp_u[1] > uMax || tmp_v[0] < vMin ||
736 std::string opt =
"";
737 if (m_plotMeshBorders || !m_fillMesh) opt +=
"l";
738 if (m_fillMesh) opt +=
"f";
740 gr.DrawGraph(4, tmp_u, tmp_v, opt.c_str());
755void ViewFEMesh::RemoveCrossings(std::vector<double>& x,
756 std::vector<double>& y) {
758 double xmin =
x[0], xmax =
x[0];
759 double ymin =
y[0], ymax =
y[0];
760 for (
int i = 1; i < (int)
x.size(); i++) {
761 if (x[i] < xmin) xmin =
x[i];
762 if (x[i] > xmax) xmax =
x[i];
763 if (y[i] < ymin) ymin =
y[i];
764 if (y[i] > ymax) ymax =
y[i];
768 double xtol = 1e-10 * std::abs(xmax - xmin);
769 double ytol = 1e-10 * std::abs(ymax - ymin);
770 for (
int i = 0; i < (int)
x.size(); i++) {
771 for (
int j = i + 1; j < (int)
x.size(); j++) {
772 if (std::abs(x[i] - x[j]) < xtol && std::abs(y[i] - y[j]) < ytol) {
773 x.erase(
x.begin() + j);
774 y.erase(
y.begin() + j);
781 if (
x.size() <= 3)
return;
791 bool crossings =
true;
792 while (crossings && (attempts < NN)) {
796 for (
int i = 1; i <= NN; i++) {
797 for (
int j = i + 2; j <= NN; j++) {
799 if ((j + 1) > NN && 1 + (j % NN) >= i)
break;
802 double xc = 0., yc = 0.;
803 if (!LinesCrossed(x[(i - 1) % NN],
y[(i - 1) % NN], x[i % NN],
804 y[i % NN], x[(j - 1) % NN],
y[(j - 1) % NN],
805 x[j % NN], y[j % NN], xc, yc)) {
810 for (
int k = 1; k <= (j - i) / 2; k++) {
811 double xs =
x[(i + k - 1) % NN];
812 double ys =
y[(i + k - 1) % NN];
813 x[(i + k - 1) % NN] = x[(j - k) % NN];
814 y[(i + k - 1) % NN] = y[(j - k) % NN];
815 x[(j - k) % NN] = xs;
816 y[(j - k) % NN] = ys;
830 std::cerr <<
m_className <<
"::RemoveCrossings:\n Warning: "
831 <<
"Maximum attempts reached. Crossings not removed.\n";
836bool ViewFEMesh::InView(
const double x,
const double y)
const {
843 return IsInPolygon(x, y, m_viewRegionX, m_viewRegionY, edge);
853bool ViewFEMesh::LinesCrossed(
double x1,
double y1,
double x2,
double y2,
854 double u1,
double v1,
double u2,
double v2,
855 double& xc,
double& yc)
const {
857 double xtol = 1.0e-10 * std::max({std::abs(x1), std::abs(x2), std::abs(u1),
859 double ytol = 1.0e-10 * std::max({std::abs(y1), std::abs(y2), std::abs(v1),
861 if (xtol <= 0) xtol = 1.0e-10;
862 if (ytol <= 0) ytol = 1.0e-10;
869 double det = dy * du - dx * dv;
872 if (OnLine(x1, y1, x2, y2, u1, v1)) {
876 }
else if (OnLine(x1, y1, x2, y2, u2, v2)) {
880 }
else if (OnLine(u1, v1, u2, v2, x1, y1)) {
884 }
else if (OnLine(u1, v1, u2, v2, x2, y2)) {
890 if (std::abs(det) < xtol * ytol)
return false;
894 xc = (du * (x1 * y2 - x2 * y1) - dx * (u1 * v2 - u2 * v1)) / det;
895 yc = ((-1 * dv) * (x1 * y2 - x2 * y1) + dy * (u1 * v2 - u2 * v1)) / det;
898 if (OnLine(x1, y1, x2, y2, xc, yc) && OnLine(u1, v1, u2, v2, xc, yc))
910bool ViewFEMesh::OnLine(
double x1,
double y1,
double x2,
double y2,
double u,
913 double xtol = 1.e-10 * std::max({std::abs(x1), std::abs(x2), std::abs(u)});
914 double ytol = 1.e-10 * std::max({std::abs(y1), std::abs(y2), std::abs(v)});
915 if (xtol <= 0) xtol = 1.0e-10;
916 if (ytol <= 0) ytol = 1.0e-10;
919 double xc = 0, yc = 0;
922 if ((std::abs(x1 - u) <= xtol && std::abs(y1 - v) <= ytol) ||
923 (std::abs(x2 - u) <= xtol && std::abs(y2 - v) <= ytol)) {
927 if (std::abs(x1 - x2) <= xtol && std::abs(y1 - y2) <= ytol) {
931 if (std::abs(u - x1) + std::abs(v - y1) <
932 std::abs(u - x2) + std::abs(v - y2)) {
935 double dpar = ((u - x1) * (x2 - x1) + (v - y1) * (y2 - y1)) /
936 ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
942 }
else if (dpar > 1.0) {
946 xc = x1 + dpar * (x2 - x1);
947 yc = y1 + dpar * (y2 - y1);
953 double dpar = ((u - x2) * (x1 - x2) + (v - y2) * (y1 - y2)) /
954 ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
960 }
else if (dpar > 1.0) {
964 xc = x2 + dpar * (x1 - x2);
965 yc = y2 + dpar * (y1 - y2);
970 if (std::abs(u - xc) < xtol && std::abs(v - yc) < ytol)
return true;
980bool ViewFEMesh::PlaneCut(
double x1,
double y1,
double z1,
double x2,
double y2,
981 double z2, TMatrixD& xMat) {
984 TMatrixD cutMat(3, 3);
985 dataCut[0] =
m_proj[0][0];
986 dataCut[1] =
m_proj[1][0];
987 dataCut[2] = x1 - x2;
988 dataCut[3] =
m_proj[0][1];
989 dataCut[4] =
m_proj[1][1];
990 dataCut[5] = y1 - y2;
991 dataCut[6] =
m_proj[0][2];
992 dataCut[7] =
m_proj[1][2];
993 dataCut[8] = z1 - z2;
994 cutMat.SetMatrixArray(dataCut.GetArray());
999 (cutMat(1, 1) * cutMat(2, 2) - cutMat(1, 2) * cutMat(2, 1)) -
1001 (cutMat(1, 0) * cutMat(2, 2) - cutMat(1, 2) * cutMat(2, 0)) +
1003 (cutMat(1, 0) * cutMat(2, 1) - cutMat(1, 1) * cutMat(2, 0));
1006 if (std::abs(cutDet) < 1e-20)
return false;
1009 TArrayD dataCoords(3);
1010 TMatrixD coordMat(3, 1);
1011 dataCoords[0] = x1 -
m_proj[2][0];
1012 dataCoords[1] = y1 -
m_proj[2][1];
1013 dataCoords[2] = z1 -
m_proj[2][2];
1014 coordMat.SetMatrixArray(dataCoords.GetArray());
1017 cutMat.SetTol(1e-20);
1020 if (!cutMat.IsValid())
return false;
1021 xMat = cutMat * coordMat;
1024 if (xMat(2, 0) < 0 || xMat(2, 0) > 1)
return false;
1030bool ViewFEMesh::IntersectPlaneArea(
double& xmin,
double& ymin,
1031 double& xmax,
double& ymax) {
1032 std::vector<TMatrixD> intersect_points;
1033 m_viewRegionX.clear();
1034 m_viewRegionY.clear();
1036 for (
int i0 = 0; i0 < 2; ++i0) {
1037 for (
int j0 = 0; j0 < 2; ++j0) {
1038 for (
int k0 = 0; k0 < 2; ++k0) {
1039 for (
int i1 = i0; i1 < 2; ++i1) {
1040 for (
int j1 = j0; j1 < 2; ++j1) {
1041 for (
int k1 = k0; k1 < 2; ++k1) {
1042 if (i1 - i0 + j1 - j0 + k1 - k0 != 1)
continue;
1049 TMatrixD xMat(3, 1);
1050 if (!PlaneCut(x0, y0, z0, x1, y1, z1, xMat))
continue;
1052 std::cout <<
m_className <<
"::IntersectPlaneArea:\n"
1053 <<
" Intersection of plane at (" << xMat(0, 0)
1054 <<
", " << xMat(1, 0) <<
", " << xMat(2, 0)
1055 <<
") with edge\n ("
1056 << x0 <<
", " << y0 <<
", " << z0 <<
")-("
1057 << x1 <<
", " << y1 <<
", " << z1 <<
")\n";
1061 for (
auto& p : intersect_points) {
1062 const double dx = xMat(0, 0) - p(0, 0);
1063 const double dy = xMat(1, 0) - p(1, 0);
1064 if (std::hypot(dx, dy) < 1e-10) {
1069 if (!skip) intersect_points.push_back(xMat);
1076 if (intersect_points.size() < 3) {
1077 std::cerr <<
m_className <<
"::IntersectPlaneArea:\n"
1078 <<
" WARNING: Empty intersection of view plane with area.\n";
1081 TMatrixD offset = intersect_points[0];
1082 xmin = xmax = intersect_points[0](0, 0);
1083 ymin = ymax = intersect_points[0](1, 0);
1085 for (
auto& p : intersect_points) p -= offset;
1086 std::sort(intersect_points.begin(), intersect_points.end(),
1087 [](
const TMatrixD& a,
const TMatrixD& b) ->
bool {
1088 double cross_z = a(0, 0) * b(1, 0) - a(1, 0) * b(0, 0);
1091 for (
auto& p : intersect_points) {
1093 m_viewRegionX.push_back(p(0, 0));
1094 m_viewRegionY.push_back(p(1, 0));
1095 xmin = std::min(p(0, 0), xmin);
1096 ymin = std::min(p(1, 0), ymin);
1097 xmax = std::max(p(0, 0), xmax);
1098 ymax = std::max(p(1, 0), ymax);
1110bool ViewFEMesh::IsInPolygon(
double x,
double y,
1111 const std::vector<double>& px,
1112 const std::vector<double>& py,
bool& edge)
const {
1114 const size_t pN = px.size();
1117 if (pN < 2)
return false;
1119 if (pN == 2)
return OnLine(px[0], py[0], px[1], py[1], x, y);
1122 double px_min = px[0], py_min = py[0];
1123 double px_max = px[0], py_max = py[0];
1124 for (
size_t i = 0; i < pN; i++) {
1125 px_min = std::min(px_min, px[i]);
1126 py_min = std::min(py_min, py[i]);
1127 px_max = std::max(px_max, px[i]);
1128 py_max = std::max(py_max, py[i]);
1132 double xtol = 1.0e-10 * std::max(std::abs(px_min), std::abs(px_max));
1133 double ytol = 1.0e-10 * std::max(std::abs(py_min), std::abs(py_max));
1134 if (xtol <= 0) xtol = 1.0e-10;
1135 if (ytol <= 0) ytol = 1.0e-10;
1138 if (std::abs(px_max - px_min) < xtol) {
1139 edge = (
y > (py_min - ytol) && y < (py_max + ytol) &&
1140 std::abs(px_max + px_min - 2 * x) < xtol);
1144 if (std::abs(py_max - py_min) < ytol) {
1145 edge = (
x > (px_min - xtol) && x < (px_max + xtol) &&
1146 std::abs(py_max + py_min - 2 * y) < ytol);
1151 double xinf = px_min - std::abs(px_max - px_min);
1152 double yinf = py_min - std::abs(py_max - py_min);
1159 while (!done && niter < 100) {
1166 for (
size_t i = 0; (done && i < pN); i++) {
1168 if (OnLine(px[i % pN], py[i % pN], px[(i + 1) % pN], py[(i + 1) % pN], x,
1175 double xc = 0., yc = 0.;
1176 if (LinesCrossed(x, y, xinf, yinf, px[i % pN], py[i % pN],
1177 px[(i + 1) % pN], py[(i + 1) % pN], xc, yc))
1182 if (OnLine(x, y, xinf, yinf, px[i], py[i])) {
1184 xinf = px_min -
RndmUniform() * std::abs(px_max - xinf);
1185 yinf = py_min -
RndmUniform() * std::abs(py_max - yinf);
1196 std::cerr <<
m_className <<
"::IsInPolygon: Unable to determine whether ("
1197 <<
x <<
", " <<
y <<
") is inside a polygon. Returning false.\n";
1202 return (ncross != 2 * (ncross / 2));
1211void ViewFEMesh::ClipToView(std::vector<double>& px, std::vector<double>& py,
1212 std::vector<double>& cx, std::vector<double>& cy) {
1214 int pN = (int)px.size();
1221 const auto& vx = m_viewRegionX;
1222 const auto& vy = m_viewRegionY;
1223 const int vN = m_viewRegionX.size();
1229 for (
int i = 0; i < pN; i++) {
1234 for (
int j = 0; j < vN; j++) {
1237 if (OnLine(vx[j % vN], vy[j % vN], vx[(j + 1) % vN], vy[(j + 1) % vN],
1240 cx.push_back(px[i]);
1241 cy.push_back(py[i]);
1249 if (OnLine(px[i % pN], py[i % pN], px[(i + 1) % pN], py[(i + 1) % pN],
1252 cx.push_back(vx[j]);
1253 cy.push_back(vy[j]);
1264 for (
int j = 0; j < vN; j++) {
1267 double xc = 0., yc = 0.;
1268 if (LinesCrossed(vx[j % vN], vy[j % vN], vx[(j + 1) % vN],
1269 vy[(j + 1) % vN], px[i % pN], py[i % pN],
1270 px[(i + 1) % pN], py[(i + 1) % pN], xc, yc)) {
1279 for (
int j = 0; j < vN; j++) {
1283 if (IsInPolygon(vx[j], vy[j], px, py, edge)) {
1285 cx.push_back(vx[j]);
1286 cy.push_back(vy[j]);
1291 for (
int i = 0; i < pN; i++) {
1295 if (IsInPolygon(px[i], py[i], vx, vy, edge)) {
1297 cx.push_back(px[i]);
1298 cy.push_back(py[i]);
Base class for components based on finite-element field maps.
virtual bool GetNode(const size_t i, double &x, double &y, double &z) const
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
std::array< double, 3 > m_mapmin
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
virtual size_t GetNumberOfElements() const
Return the number of mesh elements.
bool GetElementaryCell(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the coordinates of the elementary cell.
bool GetElement(const size_t i, double &vol, double &dmin, double &dmax)
Return the volume and aspect ratio of a mesh element.
std::array< double, 3 > m_mapmax
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
Base class for visualization classes.
std::array< double, 4 > m_plane
std::array< std::array< double, 3 >, 3 > m_proj
TPad * GetCanvas()
Retrieve the canvas.
void SetRange(TPad *pad, const double x0, const double y0, const double x1, const double y1)
void ToPlane(const T x, const T y, const T z, T &xp, T &yp) const
virtual void SetPlane(const double fx, const double fy, const double fz, const double x0, const double y0, const double z0)
void CreateDefaultAxes()
Create a default set of custom-made axes.
void SetPlane(const double fx, const double fy, const double fz, const double x0, const double y0, const double z0) override
bool Plot()
Plot method to be called by user.
void SetComponent(ComponentFieldMap *cmp)
Set the component from which to retrieve the mesh and field.
void SetXaxis(TGaxis *ax)
void SetYaxis(TGaxis *ay)
double RndmUniform()
Draw a random number uniformly distributed in the range [0, 1).