19 m_axes.reset(
new TH2D());
20 m_axes->SetStats(
false);
21 m_axes->GetXaxis()->SetTitle(
"x");
22 m_axes->GetYaxis()->SetTitle(
"y");
42 std::cerr <<
m_className <<
"::SetComponent: Null pointer.\n";
50 double ymax,
double zmax) {
52 if (xmin == xmax || ymin == ymax || zmin == zmax) {
53 std::cerr <<
m_className <<
"::SetArea: Null area range not permitted.\n";
56 m_xMin = std::min(xmin, xmax);
57 m_yMin = std::min(ymin, ymax);
58 m_zMin = std::min(zmin, zmax);
59 m_xMax = std::max(xmin, xmax);
60 m_yMax = std::max(ymin, ymax);
61 m_zMax = std::max(zmin, zmax);
73 std::cerr <<
m_className <<
"::Plot: Component is not defined.\n";
77 double pmin = 0., pmax = 0.;
79 std::cerr <<
m_className <<
"::Plot: Component is not ready.\n";
86 <<
" Bounding box cannot be determined. Call SetArea first.\n";
90 if (m_viewRegionLines.empty()) {
92 <<
" Empty view. Make sure the viewing plane (SetPlane)\n"
93 <<
" intersects with the bounding box.\n";
100 m_canvas->SetTitle(m_label.c_str());
103 m_canvas->Range(m_xPlaneMin, m_yPlaneMin, m_xPlaneMax, m_yPlaneMax);
108 std::cout <<
m_className <<
"::Plot: CST component. Calling DrawCST.\n";
109 DrawCST(componentCST);
121 const double x0,
const double y0,
const double z0) {
122 if (fy * fy + fz * fz > 0) {
123 SetPlane(fx, fy, fz, x0, y0, z0, 1, 0, 0);
125 SetPlane(fx, fy, fz, x0, y0, z0, 0, 1, 0);
131 const double x0,
const double y0,
const double z0,
132 const double hx,
const double hy,
const double hz) {
134 double fnorm = sqrt(fx * fx + fy * fy + fz * fz);
137 <<
" Normal vector has zero norm. No new projection set.\n";
140 double dist = (fx * x0 + fy * y0 + fz * z0) / fnorm;
142 m_proj[2][0] = fx / fnorm;
143 m_proj[2][1] = fy / fnorm;
144 m_proj[2][2] = fz / fnorm;
147 double xx = hx, xy = hy, xz = hz;
148 PlaneVector(xx, xy, xz);
149 double vecx_norm = std::sqrt(xx * xx + xy * xy + xz * xz);
150 if (vecx_norm < 1.0e-10) {
152 if (fy * fy + fz * fz > 0) {
163 PlaneVector(xx, xy, xz);
164 vecx_norm = std::sqrt(xx * xx + xy * xy + xz * xz);
166 m_proj[0][0] = xx / vecx_norm;
167 m_proj[0][1] = xy / vecx_norm;
168 m_proj[0][2] = xz / vecx_norm;
170 m_proj[1][0] = m_proj[2][1] * m_proj[0][2] - m_proj[2][2] * m_proj[0][1];
171 m_proj[1][1] = m_proj[2][2] * m_proj[0][0] - m_proj[2][0] * m_proj[0][2];
172 m_proj[1][2] = m_proj[2][0] * m_proj[0][1] - m_proj[2][1] * m_proj[0][0];
174 IntersectPlaneArea();
185 if (m_axes) m_axes->GetXaxis()->SetTitle(xtitle);
190 if (m_axes) m_axes->GetYaxis()->SetTitle(ytitle);
196 const double dx = std::abs(m_xPlaneMax - m_xPlaneMin) * 0.1;
197 const double dy = std::abs(m_yPlaneMax - m_yPlaneMin) * 0.1;
198 const double x0 = m_xPlaneMin + dx;
199 const double y0 = m_yPlaneMin + dy;
200 const double x1 = m_xPlaneMax - dx;
201 const double y1 = m_yPlaneMax - dy;
202 m_xaxis =
new TGaxis(x0, y0, x1, y0, x0, x1, 2405,
"x");
203 m_yaxis =
new TGaxis(x0, y0, x0, y1, y0, y1, 2405,
"y");
206 m_xaxis->SetLabelSize(0.025);
207 m_yaxis->SetLabelSize(0.025);
210 m_xaxis->SetTitleSize(0.03);
211 std::string name = CreateAxisTitle(m_proj[0]);
212 m_xaxis->SetTitle(name.c_str());
213 m_yaxis->SetTitleSize(0.03);
214 name = CreateAxisTitle(m_proj[1]);
215 m_yaxis->SetTitle(name.c_str());
218std::string ViewFEMesh::CreateAxisTitle(
const double* norm)
const {
220 for (
int i = 0; i < 3; ++i) {
221 std::stringstream num;
222 num << std::setprecision(6);
223 double value = std::abs(norm[i]);
224 if (value > 1.0e-10) num << value;
225 std::string temp = num.str();
226 if (temp.empty())
continue;
228 name += (name.empty() ?
"" :
" + ");
230 name += (name.empty() ?
"#minus" :
" #minus ");
233 name += (temp ==
"1" ?
"" : temp +
" ");
252void ViewFEMesh::DrawElements() {
254 double mapxmax = m_component->
m_mapmax[0];
255 double mapxmin = m_component->
m_mapmin[0];
256 double mapymax = m_component->
m_mapmax[1];
257 double mapymin = m_component->
m_mapmin[1];
258 double mapzmax = m_component->
m_mapmax[2];
259 double mapzmin = m_component->
m_mapmin[2];
262 double sx = mapxmax - mapxmin;
263 double sy = mapymax - mapymin;
264 double sz = mapzmax - mapzmin;
274 m_driftLines.clear();
279 dataProj[0] = m_proj[0][0];
280 dataProj[1] = m_proj[1][0];
281 dataProj[2] = m_proj[2][0];
282 dataProj[3] = m_proj[0][1];
283 dataProj[4] = m_proj[1][1];
284 dataProj[5] = m_proj[2][1];
285 dataProj[6] = m_proj[0][2];
286 dataProj[7] = m_proj[1][2];
287 dataProj[8] = m_proj[2][2];
288 TMatrixD projMat(3, 3, dataProj.GetArray());
293 (projMat(1, 1) * projMat(2, 2) - projMat(1, 2) * projMat(2, 1)) -
295 (projMat(1, 0) * projMat(2, 2) - projMat(1, 2) * projMat(2, 0)) +
297 (projMat(1, 0) * projMat(2, 1) - projMat(1, 1) * projMat(2, 0));
305 std::cerr <<
" Projection matrix is not invertible.\n";
306 std::cerr <<
" Finite element mesh will not be drawn.\n";
310 double fx = m_proj[2][0];
311 double fy = m_proj[2][1];
312 double fz = m_proj[2][2];
313 double dist = m_dist;
319 const int nMinX = perX ? int(m_xMin / sx) - 1 : 0;
320 const int nMaxX = perX ? int(m_xMax / sx) + 1 : 0;
321 const int nMinY = perY ? int(m_yMin / sy) - 1 : 0;
322 const int nMaxY = perY ? int(m_yMax / sy) + 1 : 0;
323 const int nMinZ = perZ ? int(m_zMin / sz) - 1 : 0;
324 const int nMaxZ = perZ ? int(m_zMax / sz) + 1 : 0;
327 for (
const auto& element : m_component->
elements) {
328 const auto mat = element.matmap;
330 if (m_component->
materials[mat].driftmedium && !(m_plotMeshBorders)) {
334 if (m_disabledMaterial[mat])
continue;
338 double vx1, vy1, vz1;
339 double vx2, vy2, vz2;
340 double vx3, vy3, vz3;
341 double vx4, vy4, vz4;
344 int colorID = m_colorMap.count(mat);
346 colorID = m_colorMap[mat];
351 int colorID_fill = m_colorMap_fill.count(mat);
352 if (colorID_fill != 0)
353 colorID_fill = m_colorMap_fill[mat];
355 colorID_fill = colorID;
357 const auto& n0 = m_component->
nodes[element.emap[0]];
358 const auto& n1 = m_component->
nodes[element.emap[1]];
359 const auto& n2 = m_component->
nodes[element.emap[2]];
360 const auto& n3 = m_component->
nodes[element.emap[3]];
362 for (
int nx = nMinX; nx <= nMaxX; nx++) {
365 vx1 = mapxmin + (mapxmax - n0.x) + sx * nx;
366 vx2 = mapxmin + (mapxmax - n1.x) + sx * nx;
367 vx3 = mapxmin + (mapxmax - n2.x) + sx * nx;
368 vx4 = mapxmin + (mapxmax - n3.x) + sx * nx;
370 vx1 = n0.x + sx * nx;
371 vx2 = n1.x + sx * nx;
372 vx3 = n2.x + sx * nx;
373 vx4 = n3.x + sx * nx;
377 for (
int ny = nMinY; ny <= nMaxY; ny++) {
380 vy1 = mapymin + (mapymax - n0.y) + sy * ny;
381 vy2 = mapymin + (mapymax - n1.y) + sy * ny;
382 vy3 = mapymin + (mapymax - n2.y) + sy * ny;
383 vy4 = mapymin + (mapymax - n3.y) + sy * ny;
385 vy1 = n0.y + sy * ny;
386 vy2 = n1.y + sy * ny;
387 vy3 = n2.y + sy * ny;
388 vy4 = n3.y + sy * ny;
392 for (
int nz = nMinZ; nz <= nMaxZ; nz++) {
395 vz1 = mapzmin + (mapzmax - n0.z) + sz * nz;
396 vz2 = mapzmin + (mapzmax - n1.z) + sz * nz;
397 vz3 = mapzmin + (mapzmax - n2.z) + sz * nz;
398 vz4 = mapzmin + (mapzmax - n3.z) + sz * nz;
400 vz1 = n0.z + sz * nz;
401 vz2 = n1.z + sz * nz;
402 vz3 = n2.z + sz * nz;
403 vz4 = n3.z + sz * nz;
407 std::vector<double> vX;
408 std::vector<double> vY;
411 const double pcf = std::max(
412 {std::abs(vx1), std::abs(vy1), std::abs(vz1), std::abs(fx),
413 std::abs(fy), std::abs(fz), std::abs(dist)});
414 const double tol = 1.e-4 * pcf;
416 bool in1 = (std::abs(fx * vx1 + fy * vy1 + fz * vz1 - dist) < tol);
417 bool in2 = (std::abs(fx * vx2 + fy * vy2 + fz * vz2 - dist) < tol);
418 bool in3 = (std::abs(fx * vx3 + fy * vy3 + fz * vz3 - dist) < tol);
419 bool in4 = (std::abs(fx * vx4 + fy * vy4 + fz * vz4 - dist) < tol);
424 PlaneCoords(vx1, vy1, vz1, projMat, xMat);
425 vX.push_back(xMat(0, 0));
426 vY.push_back(xMat(1, 0));
429 PlaneCoords(vx2, vy2, vz2, projMat, xMat);
430 vX.push_back(xMat(0, 0));
431 vY.push_back(xMat(1, 0));
434 PlaneCoords(vx3, vy3, vz3, projMat, xMat);
435 vX.push_back(xMat(0, 0));
436 vY.push_back(xMat(1, 0));
439 PlaneCoords(vx4, vy4, vz4, projMat, xMat);
440 vX.push_back(xMat(0, 0));
441 vY.push_back(xMat(1, 0));
446 if (PlaneCut(vx1, vy1, vz1, vx2, vy2, vz2, xMat)) {
447 vX.push_back(xMat(0, 0));
448 vY.push_back(xMat(1, 0));
452 if (PlaneCut(vx1, vy1, vz1, vx3, vy3, vz3, xMat)) {
453 vX.push_back(xMat(0, 0));
454 vY.push_back(xMat(1, 0));
458 if (PlaneCut(vx1, vy1, vz1, vx4, vy4, vz4, xMat)) {
459 vX.push_back(xMat(0, 0));
460 vY.push_back(xMat(1, 0));
464 if (PlaneCut(vx2, vy2, vz2, vx3, vy3, vz3, xMat)) {
465 vX.push_back(xMat(0, 0));
466 vY.push_back(xMat(1, 0));
470 if (PlaneCut(vx2, vy2, vz2, vx4, vy4, vz4, xMat)) {
471 vX.push_back(xMat(0, 0));
472 vY.push_back(xMat(1, 0));
476 if (PlaneCut(vx3, vy3, vz3, vx4, vy4, vz4, xMat)) {
477 vX.push_back(xMat(0, 0));
478 vY.push_back(xMat(1, 0));
481 if (vX.size() < 3)
continue;
486 RemoveCrossings(vX, vY);
489 std::vector<double> cX;
490 std::vector<double> cY;
493 ClipToView(vX, vY, cX, cY);
496 if (cX.size() <= 2)
continue;
499 RemoveCrossings(cX, cY);
503 poly.SetLineColor(colorID);
504 poly.SetFillColor(colorID_fill);
505 poly.SetLineWidth(3);
507 const auto nPoints = cX.size();
508 for (
size_t pt = 0; pt < nPoints; ++pt) {
509 poly.SetPoint(pt, cX[pt], cY[pt]);
513 m_mesh.push_back(std::move(poly));
521 for (
const auto& dline : m_viewDrift->m_driftLines) {
524 poly.SetLineColor(dline.n);
526 for (
const auto& point : dline.points) {
528 PlaneCoords(point.x, point.y, point.z, projMat, xMat);
530 if (InView(xMat(0, 0), xMat(1, 0))) {
531 poly.SetPoint(polyPts, xMat(0, 0), xMat(1, 0));
537 m_driftLines.push_back(std::move(poly));
546 if (!m_xaxis && !m_yaxis && m_drawAxes) {
547 std::string name = CreateAxisTitle(m_proj[0]);
548 m_axes->GetXaxis()->SetTitle(name.c_str());
549 m_axes->GetXaxis()->SetLimits(m_xPlaneMin, m_xPlaneMax);
550 name = CreateAxisTitle(m_proj[1]);
551 m_axes->GetYaxis()->SetTitle(name.c_str());
552 m_axes->GetYaxis()->SetTitleOffset(1.6);
553 m_axes->GetYaxis()->SetLimits(m_yPlaneMin, m_yPlaneMax);
558 if (m_xaxis && m_drawAxes) m_xaxis->Draw();
559 if (m_yaxis && m_drawAxes) m_yaxis->Draw();
562 for (
auto& m : m_mesh) {
563 if (m_plotMeshBorders || !m_fillMesh) m.Draw(
"same");
564 if (m_fillMesh) m.Draw(
"f:same");
567 for (
auto& dline : m_driftLines) dline.Draw(
"same");
569 if (m_drawViewRegion)
570 for (
auto& m : m_viewRegionLines) m.Draw(
"same");
573 gPad->RedrawAxis(
"g");
576void ViewFEMesh::DrawCST(ComponentCST* componentCST) {
586 double mapxmax = m_component->
m_mapmax[0];
587 double mapxmin = m_component->
m_mapmin[0];
588 double mapymax = m_component->
m_mapmax[1];
589 double mapymin = m_component->
m_mapmin[1];
590 double mapzmax = m_component->
m_mapmax[2];
591 double mapzmin = m_component->
m_mapmin[2];
594 double sx = mapxmax - mapxmin;
595 double sy = mapymax - mapymin;
596 double sz = mapzmax - mapzmin;
606 m_driftLines.clear();
611 dataProj[0] = m_proj[0][0];
612 dataProj[1] = m_proj[1][0];
613 dataProj[2] = m_proj[2][0];
614 dataProj[3] = m_proj[0][1];
615 dataProj[4] = m_proj[1][1];
616 dataProj[5] = m_proj[2][1];
617 dataProj[6] = m_proj[0][2];
618 dataProj[7] = m_proj[1][2];
619 dataProj[8] = m_proj[2][2];
620 TMatrixD projMat(3, 3, dataProj.GetArray());
625 (projMat(1, 1) * projMat(2, 2) - projMat(1, 2) * projMat(2, 1)) -
627 (projMat(1, 0) * projMat(2, 2) - projMat(1, 2) * projMat(2, 0)) +
629 (projMat(1, 0) * projMat(2, 1) - projMat(1, 1) * projMat(2, 0));
637 std::cerr <<
" Projection matrix is not invertible.\n";
638 std::cerr <<
" Finite element mesh will not be drawn.\n";
645 const int nMinX = perX ? int(m_xMin / sx) - 1 : 0;
646 const int nMaxX = perX ? int(m_xMax / sx) + 1 : 0;
647 const int nMinY = perY ? int(m_yMin / sy) - 1 : 0;
648 const int nMaxY = perY ? int(m_yMax / sy) + 1 : 0;
649 const int nMinZ = perZ ? int(m_zMin / sz) - 1 : 0;
650 const int nMaxZ = perZ ? int(m_zMax / sz) + 1 : 0;
653 std::vector<PolygonInfo> elements;
654 int nMinU = 0, nMaxU = 0, nMinV = 0, nMaxV = 0;
655 double mapumin = 0., mapumax = 0., mapvmin = 0., mapvmax = 0.;
656 double su = 0., sv = 0.;
657 bool mirroru =
false, mirrorv =
false;
658 double uMin, vMin, uMax, vMax;
659 unsigned int n_x, n_y, n_z;
660 componentCST->GetNumberOfMeshLines(n_x, n_y, n_z);
661 double e_xmin, e_xmax, e_ymin, e_ymax, e_zmin, e_zmax;
663 if (m_proj[2][0] == 0 && m_proj[2][1] == 0 && m_proj[2][2] == 1) {
664 std::cout <<
m_className <<
"::DrawCST: Creating x-y mesh view.\n";
668 unsigned int i, j,
z;
669 if (!componentCST->Coordinate2Index(0, 0, m_dist * m_proj[2][2], i, j, z)) {
670 std::cerr <<
" Could not determine the position of the plane in "
674 std::cout <<
" The plane position in z direction is: "
675 << m_dist * m_proj[2][2] <<
"\n";
693 for (
unsigned int y = 0;
y < (n_y - 1);
y++) {
694 for (
unsigned int x = 0;
x < (n_x - 1);
x++) {
695 elem = componentCST->Index2Element(x, y, z);
696 componentCST->GetElementBoundaries(elem, e_xmin, e_xmax, e_ymin, e_ymax,
698 PolygonInfo tmp_info;
699 tmp_info.element = elem;
700 tmp_info.p1[0] = e_xmin;
701 tmp_info.p2[0] = e_xmax;
702 tmp_info.p3[0] = e_xmax;
703 tmp_info.p4[0] = e_xmin;
704 tmp_info.p1[1] = e_ymin;
705 tmp_info.p2[1] = e_ymin;
706 tmp_info.p3[1] = e_ymax;
707 tmp_info.p4[1] = e_ymax;
708 tmp_info.material = componentCST->GetElementMaterial(elem);
709 elements.push_back(std::move(tmp_info));
713 }
else if (m_proj[2][0] == 0 && m_proj[2][1] == -1 && m_proj[2][2] == 0) {
714 std::cout <<
m_className <<
"::DrawCST: Creating x-z mesh view.\n";
718 unsigned int i = 0, j = 0,
y = 0;
719 if (!componentCST->Coordinate2Index(0, m_dist * m_proj[2][1], 0, i, y, j)) {
720 std::cerr <<
" Could not determine the position of the plane in "
724 std::cout <<
" The plane position in y direction is: "
725 << m_dist * m_proj[2][1] <<
"\n";
744 for (
unsigned int z = 0;
z < (n_z - 1);
z++) {
745 for (
unsigned int x = 0;
x < (n_x - 1);
x++) {
746 elem = componentCST->Index2Element(x, y, z);
747 componentCST->GetElementBoundaries(elem, e_xmin, e_xmax, e_ymin, e_ymax,
749 PolygonInfo tmp_info;
750 tmp_info.element = elem;
751 tmp_info.p1[0] = e_xmin;
752 tmp_info.p2[0] = e_xmax;
753 tmp_info.p3[0] = e_xmax;
754 tmp_info.p4[0] = e_xmin;
755 tmp_info.p1[1] = e_zmin;
756 tmp_info.p2[1] = e_zmin;
757 tmp_info.p3[1] = e_zmax;
758 tmp_info.p4[1] = e_zmax;
759 tmp_info.material = componentCST->GetElementMaterial(elem);
760 elements.push_back(std::move(tmp_info));
765 }
else if (m_proj[2][0] == -1 && m_proj[2][1] == 0 && m_proj[2][2] == 0) {
766 std::cout <<
m_className <<
"::DrawCST: Creating z-y mesh view.\n";
770 unsigned int i, j,
x;
771 if (!componentCST->Coordinate2Index(m_dist * m_proj[2][0], 0, 0, x, i,
773 std::cerr <<
" Could not determine the position of the plane in "
777 std::cout <<
" The plane position in x direction is: "
778 << m_dist * m_proj[2][0] <<
"\n";
796 for (
unsigned int z = 0;
z < (n_z - 1);
z++) {
797 for (
unsigned int y = 0;
y < (n_y - 1);
y++) {
798 elem = componentCST->Index2Element(x, y, z);
799 componentCST->GetElementBoundaries(elem, e_xmin, e_xmax, e_ymin, e_ymax,
801 PolygonInfo tmp_info;
802 tmp_info.element = elem;
803 tmp_info.p1[0] = e_zmin;
804 tmp_info.p2[0] = e_zmax;
805 tmp_info.p3[0] = e_zmax;
806 tmp_info.p4[0] = e_zmin;
807 tmp_info.p1[1] = e_ymin;
808 tmp_info.p2[1] = e_ymin;
809 tmp_info.p3[1] = e_ymax;
810 tmp_info.p4[1] = e_ymax;
811 tmp_info.material = componentCST->GetElementMaterial(elem);
813 elements.push_back(std::move(tmp_info));
818 std::cerr <<
" The given plane name is not known.\n";
819 std::cerr <<
" Please choose one of the following: xy, xz, yz.\n";
823 std::cout <<
" Number of elements in the projection of the unit cell:"
824 << elements.size() << std::endl;
825 std::vector<PolygonInfo>::iterator it;
826 std::vector<PolygonInfo>::iterator itend = elements.end();
828 for (
int nu = nMinU; nu <= nMaxU; nu++) {
829 for (
int nv = nMinV; nv <= nMaxV; nv++) {
830 it = elements.begin();
831 while (it != itend) {
832 if (m_disabledMaterial[(*it).material]) {
837 int colorID = m_colorMap.count((*it).material);
839 colorID = m_colorMap[(*it).material];
844 int colorID_fill = m_colorMap_fill.count((*it).material);
845 if (colorID_fill != 0)
846 colorID_fill = m_colorMap_fill[(*it).material];
848 colorID_fill = colorID;
851 poly.SetLineColor(colorID);
852 poly.SetFillColor(colorID_fill);
853 if (m_plotMeshBorders)
854 poly.SetLineWidth(3);
856 poly.SetLineWidth(1);
858 Double_t tmp_u[4], tmp_v[4];
859 if (mirroru && nu != 2 * (nu / 2)) {
861 tmp_u[0] = mapumin + (mapumax - (*it).p1[0]) + su * nu;
862 tmp_u[1] = mapumin + (mapumax - (*it).p2[0]) + su * nu;
863 tmp_u[2] = mapumin + (mapumax - (*it).p3[0]) + su * nu;
864 tmp_u[3] = mapumin + (mapumax - (*it).p4[0]) + su * nu;
867 tmp_u[0] = (*it).p1[0] + su * nu;
868 tmp_u[1] = (*it).p2[0] + su * nu;
869 tmp_u[2] = (*it).p3[0] + su * nu;
870 tmp_u[3] = (*it).p4[0] + su * nu;
872 if (mirrorv && nv != 2 * (nv / 2)) {
873 tmp_v[0] = mapvmin + (mapvmax - (*it).p1[1]) + sv * nv;
874 tmp_v[1] = mapvmin + (mapvmax - (*it).p2[1]) + sv * nv;
875 tmp_v[2] = mapvmin + (mapvmax - (*it).p3[1]) + sv * nv;
876 tmp_v[3] = mapvmin + (mapvmax - (*it).p4[1]) + sv * nv;
878 tmp_v[0] = (*it).p1[1] + sv * nv;
879 tmp_v[1] = (*it).p2[1] + sv * nv;
880 tmp_v[2] = (*it).p3[1] + sv * nv;
881 tmp_v[3] = (*it).p4[1] + sv * nv;
883 if (tmp_u[0] < uMin || tmp_u[1] > uMax || tmp_v[0] < vMin ||
888 poly.SetPoint(0, tmp_u[0], tmp_v[0]);
889 poly.SetPoint(1, tmp_u[1], tmp_v[1]);
890 poly.SetPoint(2, tmp_u[2], tmp_v[2]);
891 poly.SetPoint(3, tmp_u[3], tmp_v[3]);
893 m_mesh.push_back(std::move(poly));
899 <<
" Number of polygons to be drawn:" << m_mesh.size() <<
"\n";
902 for (
const auto& dline : m_viewDrift->m_driftLines) {
905 poly.SetLineColor(dline.n);
907 for (
const auto& point : dline.points) {
909 PlaneCoords(point.x, point.y, point.z, projMat, xMat);
911 if (xMat(0, 0) >= uMin && xMat(0, 0) <= uMax && xMat(1, 0) >= vMin &&
912 xMat(1, 0) <= vMax) {
913 poly.SetPoint(polyPts, xMat(0, 0), xMat(1, 0));
918 m_driftLines.push_back(std::move(poly));
925 if (!m_xaxis && !m_yaxis && m_drawAxes) {
926 m_axes->GetXaxis()->SetLimits(uMin, uMax);
927 m_axes->GetYaxis()->SetLimits(vMin, vMax);
931 if (m_xaxis && m_drawAxes) m_xaxis->Draw(
"");
932 if (m_yaxis && m_drawAxes) m_yaxis->Draw(
"");
934 for (
auto& m : m_mesh) {
935 if (m_plotMeshBorders || !m_fillMesh) m.Draw(
"same");
936 if (m_fillMesh) m.Draw(
"f:sames");
940 for (
auto& dline : m_driftLines) {
944 gPad->RedrawAxis(
"g");
955void ViewFEMesh::RemoveCrossings(std::vector<double>& x,
956 std::vector<double>& y) {
958 double xmin =
x[0], xmax =
x[0];
959 double ymin =
y[0], ymax =
y[0];
960 for (
int i = 1; i < (int)
x.size(); i++) {
961 if (x[i] < xmin) xmin =
x[i];
962 if (x[i] > xmax) xmax =
x[i];
963 if (y[i] < ymin) ymin =
y[i];
964 if (y[i] > ymax) ymax =
y[i];
968 double xtol = 1e-10 * std::abs(xmax - xmin);
969 double ytol = 1e-10 * std::abs(ymax - ymin);
970 for (
int i = 0; i < (int)
x.size(); i++) {
971 for (
int j = i + 1; j < (int)
x.size(); j++) {
972 if (std::abs(x[i] - x[j]) < xtol && std::abs(y[i] - y[j]) < ytol) {
973 x.erase(
x.begin() + j);
974 y.erase(
y.begin() + j);
981 if (
x.size() <= 3)
return;
991 bool crossings =
true;
992 while (crossings && (attempts < NN)) {
996 for (
int i = 1; i <= NN; i++) {
997 for (
int j = i + 2; j <= NN; j++) {
999 if ((j + 1) > NN && 1 + (j % NN) >= i)
break;
1002 double xc = 0., yc = 0.;
1003 if (!LinesCrossed(x[(i - 1) % NN],
y[(i - 1) % NN], x[i % NN],
1004 y[i % NN], x[(j - 1) % NN],
y[(j - 1) % NN],
1005 x[j % NN], y[j % NN], xc, yc)) {
1010 for (
int k = 1; k <= (j - i) / 2; k++) {
1011 double xs =
x[(i + k - 1) % NN];
1012 double ys =
y[(i + k - 1) % NN];
1013 x[(i + k - 1) % NN] = x[(j - k) % NN];
1014 y[(i + k - 1) % NN] = y[(j - k) % NN];
1015 x[(j - k) % NN] = xs;
1016 y[(j - k) % NN] = ys;
1029 if (attempts > NN) {
1030 std::cerr <<
m_className <<
"::RemoveCrossings:\n Warning: "
1031 <<
"Maximum attempts reached. Crossings not removed.\n";
1036bool ViewFEMesh::InView(
const double x,
const double y)
const {
1038 int vN = m_viewRegionLines[0].GetN() - 1;
1039 std::vector<double> vx(vN), vy(vN);
1040 vx.assign(m_viewRegionLines[0].GetX(), m_viewRegionLines[0].GetX() + vN);
1041 vy.assign(m_viewRegionLines[0].GetY(), m_viewRegionLines[0].GetY() + vN);
1044 return IsInPolygon(x, y, vx, vy, edge);
1054bool ViewFEMesh::LinesCrossed(
double x1,
double y1,
double x2,
double y2,
1055 double u1,
double v1,
double u2,
double v2,
1056 double& xc,
double& yc)
const {
1058 double xtol = 1.0e-10 * std::max({std::abs(x1), std::abs(x2), std::abs(u1),
1060 double ytol = 1.0e-10 * std::max({std::abs(y1), std::abs(y2), std::abs(v1),
1062 if (xtol <= 0) xtol = 1.0e-10;
1063 if (ytol <= 0) ytol = 1.0e-10;
1066 double dy = y2 - y1;
1067 double dv = v2 - v1;
1068 double dx = x1 - x2;
1069 double du = u1 - u2;
1070 double det = dy * du - dx * dv;
1073 if (OnLine(x1, y1, x2, y2, u1, v1)) {
1077 }
else if (OnLine(x1, y1, x2, y2, u2, v2)) {
1081 }
else if (OnLine(u1, v1, u2, v2, x1, y1)) {
1085 }
else if (OnLine(u1, v1, u2, v2, x2, y2)) {
1091 if (std::abs(det) < xtol * ytol)
return false;
1095 xc = (du * (x1 * y2 - x2 * y1) - dx * (u1 * v2 - u2 * v1)) / det;
1096 yc = ((-1 * dv) * (x1 * y2 - x2 * y1) + dy * (u1 * v2 - u2 * v1)) / det;
1099 if (OnLine(x1, y1, x2, y2, xc, yc) && OnLine(u1, v1, u2, v2, xc, yc))
1111bool ViewFEMesh::OnLine(
double x1,
double y1,
double x2,
double y2,
double u,
1114 double xtol = 1.e-10 * std::max({std::abs(x1), std::abs(x2), std::abs(u)});
1115 double ytol = 1.e-10 * std::max({std::abs(y1), std::abs(y2), std::abs(v)});
1116 if (xtol <= 0) xtol = 1.0e-10;
1117 if (ytol <= 0) ytol = 1.0e-10;
1120 double xc = 0, yc = 0;
1123 if ((std::abs(x1 - u) <= xtol && std::abs(y1 - v) <= ytol) ||
1124 (std::abs(x2 - u) <= xtol && std::abs(y2 - v) <= ytol)) {
1128 if (std::abs(x1 - x2) <= xtol && std::abs(y1 - y2) <= ytol) {
1132 if (std::abs(u - x1) + std::abs(v - y1) <
1133 std::abs(u - x2) + std::abs(v - y2)) {
1136 double dpar = ((u - x1) * (x2 - x1) + (v - y1) * (y2 - y1)) /
1137 ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
1143 }
else if (dpar > 1.0) {
1147 xc = x1 + dpar * (x2 - x1);
1148 yc = y1 + dpar * (y2 - y1);
1154 double dpar = ((u - x2) * (x1 - x2) + (v - y2) * (y1 - y2)) /
1155 ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
1161 }
else if (dpar > 1.0) {
1165 xc = x2 + dpar * (x1 - x2);
1166 yc = y2 + dpar * (y1 - y2);
1171 if (std::abs(u - xc) < xtol && std::abs(v - yc) < ytol)
return true;
1181bool ViewFEMesh::PlaneCut(
double x1,
double y1,
double z1,
double x2,
double y2,
1182 double z2, TMatrixD& xMat) {
1185 TMatrixD cutMat(3, 3);
1186 dataCut[0] = m_proj[0][0];
1187 dataCut[1] = m_proj[1][0];
1188 dataCut[2] = x1 - x2;
1189 dataCut[3] = m_proj[0][1];
1190 dataCut[4] = m_proj[1][1];
1191 dataCut[5] = y1 - y2;
1192 dataCut[6] = m_proj[0][2];
1193 dataCut[7] = m_proj[1][2];
1194 dataCut[8] = z1 - z2;
1195 cutMat.SetMatrixArray(dataCut.GetArray());
1200 (cutMat(1, 1) * cutMat(2, 2) - cutMat(1, 2) * cutMat(2, 1)) -
1202 (cutMat(1, 0) * cutMat(2, 2) - cutMat(1, 2) * cutMat(2, 0)) +
1204 (cutMat(1, 0) * cutMat(2, 1) - cutMat(1, 1) * cutMat(2, 0));
1207 if (std::abs(cutDet) < 1e-20)
return false;
1210 TArrayD dataCoords(3);
1211 TMatrixD coordMat(3, 1);
1212 dataCoords[0] = x1 - m_dist * m_proj[2][0];
1213 dataCoords[1] = y1 - m_dist * m_proj[2][1];
1214 dataCoords[2] = z1 - m_dist * m_proj[2][2];
1215 coordMat.SetMatrixArray(dataCoords.GetArray());
1218 cutMat.SetTol(1e-20);
1221 if (!cutMat.IsValid())
return false;
1222 xMat = cutMat * coordMat;
1225 if (xMat(2, 0) < 0 || xMat(2, 0) > 1)
return false;
1231bool ViewFEMesh::IntersectPlaneArea(
void) {
1232 std::vector<TMatrixD> intersect_points;
1233 m_viewRegionLines.clear();
1235 for (
int x0 = 0; x0 < 2; ++x0) {
1236 for (
int y0 = 0; y0 < 2; ++y0) {
1237 for (
int z0 = 0; z0 < 2; ++z0) {
1238 for (
int x1 = x0; x1 < 2; ++x1) {
1239 for (
int y1 = y0; y1 < 2; ++y1) {
1240 for (
int z1 = z0; z1 < 2; ++z1) {
1241 if (x1 - x0 + y1 - y0 + z1 - z0 != 1)
continue;
1242 double X0 = (x0 ? m_xMin : m_xMax);
1243 double Y0 = (y0 ? m_yMin : m_yMax);
1244 double Z0 = (z0 ? m_zMin : m_zMax);
1245 double X1 = (x1 ? m_xMin : m_xMax);
1246 double Y1 = (y1 ? m_yMin : m_yMax);
1247 double Z1 = (z1 ? m_zMin : m_zMax);
1248 TMatrixD xMat(3, 1);
1249 if (!PlaneCut(X0, Y0, Z0, X1, Y1, Z1, xMat))
continue;
1251 std::cout <<
m_className <<
"::IntersectPlaneArea:\n"
1252 <<
" Intersection of plane at (" << xMat(0, 0)
1253 <<
", " << xMat(1, 0) <<
", " << xMat(2, 0)
1254 <<
") with edge\n ("
1255 << X0 <<
", " << Y0 <<
", " << Z0 <<
")-("
1256 << X1 <<
", " << Y1 <<
", " << Z1 <<
")\n";
1260 for (
auto& p : intersect_points) {
1261 const double dx = xMat(0, 0) - p(0, 0);
1262 const double dy = xMat(1, 0) - p(1, 0);
1263 if (std::sqrt(dx * dx + dy * dy) < 1e-10) {
1268 if (!skip) intersect_points.push_back(xMat);
1275 if (intersect_points.size() < 3) {
1276 std::cerr <<
m_className <<
"::IntersectPlaneArea:\n";
1277 std::cerr <<
" WARNING: Empty intersection of view plane with area.\n";
1280 TMatrixD offset = intersect_points[0];
1281 m_xPlaneMin = m_xPlaneMax = intersect_points[0](0, 0);
1282 m_yPlaneMin = m_yPlaneMax = intersect_points[0](1, 0);
1284 for (
auto& p : intersect_points) p -= offset;
1285 std::sort(intersect_points.begin(), intersect_points.end(),
1286 [](
const TMatrixD& a,
const TMatrixD& b) ->
bool {
1287 double cross_z = a(0, 0) * b(1, 0) - a(1, 0) * b(0, 0);
1292 poly.SetLineWidth(3);
1294 for (
auto& p : intersect_points) {
1296 poly.SetPoint(pn, p(0, 0), p(1, 0));
1297 m_xPlaneMin = std::min(p(0, 0), m_xPlaneMin);
1298 m_yPlaneMin = std::min(p(1, 0), m_yPlaneMin);
1299 m_xPlaneMax = std::max(p(0, 0), m_xPlaneMax);
1300 m_yPlaneMax = std::max(p(1, 0), m_yPlaneMax);
1303 poly.SetPoint(pn, offset(0, 0), offset(1, 0));
1304 m_viewRegionLines.push_back(poly);
1310bool ViewFEMesh::PlaneVector(
double& x,
double& y,
double& z)
const {
1311 double dist =
x * m_proj[2][0] +
y * m_proj[2][1] +
z * m_proj[2][2];
1312 x =
x - dist * m_proj[2][0];
1313 y =
y - dist * m_proj[2][1];
1314 z =
z - dist * m_proj[2][2];
1322bool ViewFEMesh::PlaneCoords(
double x,
double y,
double z,
1323 const TMatrixD& projMat, TMatrixD& xMat) {
1325 TArrayD dataCoords(3);
1326 TMatrixD coordMat(3, 1);
1330 coordMat.SetMatrixArray(dataCoords.GetArray());
1331 xMat = projMat * coordMat;
1343bool ViewFEMesh::IsInPolygon(
double x,
double y, std::vector<double>& px,
1344 std::vector<double>& py,
bool& edge)
const {
1346 int pN = (int)px.size();
1349 if (pN < 2)
return false;
1351 if (pN == 2)
return OnLine(px[0], py[0], px[1], py[1], x, y);
1354 double px_min = px[0], py_min = py[0];
1355 double px_max = px[0], py_max = py[0];
1356 for (
int i = 0; i < pN; i++) {
1357 px_min = std::min(px_min, px[i]);
1358 py_min = std::min(py_min, py[i]);
1359 px_max = std::max(px_max, px[i]);
1360 py_max = std::max(py_max, py[i]);
1364 double xtol = 1.0e-10 * std::max(std::abs(px_min), std::abs(px_max));
1365 double ytol = 1.0e-10 * std::max(std::abs(py_min), std::abs(py_max));
1366 if (xtol <= 0) xtol = 1.0e-10;
1367 if (ytol <= 0) ytol = 1.0e-10;
1370 if (std::abs(px_max - px_min) < xtol) {
1371 edge = (
y > (py_min - ytol) && y < (py_max + ytol) &&
1372 std::abs(px_max + px_min - 2 * x) < xtol);
1376 if (std::abs(py_max - py_min) < ytol) {
1377 edge = (
x > (px_min - xtol) && x < (px_max + xtol) &&
1378 std::abs(py_max + py_min - 2 * y) < ytol);
1383 double xinf = px_min - std::abs(px_max - px_min);
1384 double yinf = py_min - std::abs(py_max - py_min);
1391 while (!done && niter < 100) {
1398 for (
int i = 0; (done && i < pN); i++) {
1400 if (OnLine(px[i % pN], py[i % pN], px[(i + 1) % pN], py[(i + 1) % pN], x,
1407 double xc = 0., yc = 0.;
1408 if (LinesCrossed(x, y, xinf, yinf, px[i % pN], py[i % pN],
1409 px[(i + 1) % pN], py[(i + 1) % pN], xc, yc))
1414 if (OnLine(x, y, xinf, yinf, px[i], py[i])) {
1416 xinf = px_min -
RndmUniform() * std::abs(px_max - xinf);
1417 yinf = py_min -
RndmUniform() * std::abs(py_max - yinf);
1428 std::cerr <<
m_className <<
"::IsInPolygon: Unable to determine whether ("
1429 <<
x <<
", " <<
y <<
") is inside a polygon. Returning false.\n";
1434 return (ncross != 2 * (ncross / 2));
1443void ViewFEMesh::ClipToView(std::vector<double>& px, std::vector<double>& py,
1444 std::vector<double>& cx, std::vector<double>& cy) {
1446 int pN = (int)px.size();
1453 int vN = m_viewRegionLines[0].GetN() - 1;
1454 std::vector<double> vx(vN), vy(vN);
1455 vx.assign(m_viewRegionLines[0].GetX(), m_viewRegionLines[0].GetX() + vN);
1456 vy.assign(m_viewRegionLines[0].GetY(), m_viewRegionLines[0].GetY() + vN);
1462 for (
int i = 0; i < pN; i++) {
1467 for (
int j = 0; j < vN; j++) {
1470 if (OnLine(vx[j % vN], vy[j % vN], vx[(j + 1) % vN], vy[(j + 1) % vN],
1473 cx.push_back(px[i]);
1474 cy.push_back(py[i]);
1482 if (OnLine(px[i % pN], py[i % pN], px[(i + 1) % pN], py[(i + 1) % pN],
1485 cx.push_back(vx[j]);
1486 cy.push_back(vy[j]);
1497 for (
int j = 0; j < vN; j++) {
1500 double xc = 0., yc = 0.;
1501 if (LinesCrossed(vx[j % vN], vy[j % vN], vx[(j + 1) % vN],
1502 vy[(j + 1) % vN], px[i % pN], py[i % pN],
1503 px[(i + 1) % pN], py[(i + 1) % pN], xc, yc)) {
1512 for (
int j = 0; j < vN; j++) {
1516 if (IsInPolygon(vx[j], vy[j], px, py, edge)) {
1518 cx.push_back(vx[j]);
1519 cy.push_back(vy[j]);
1524 for (
int i = 0; i < pN; i++) {
1528 if (IsInPolygon(px[i], py[i], vx, vy, edge)) {
1530 cx.push_back(px[i]);
1531 cy.push_back(py[i]);
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
Base class for components based on finite-element field maps.
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
std::array< double, 3 > m_mapmin
std::vector< Material > materials
std::vector< Node > nodes
std::vector< Element > elements
std::array< double, 3 > m_mapmax
Base class for visualization classes.
void SetXaxisTitle(const char *xtitle)
void CreateDefaultAxes()
Create a default set of custom-made axes.
void SetComponent(ComponentFieldMap *comp)
Set the component from which to retrieve the mesh and field.
void SetYaxisTitle(const char *ytitle)
bool Plot()
Plot method to be called by user.
void SetPlane(double fx, double fy, double fz, double x0, double y0, double z0)
Set the projection plane.
void SetArea()
Set area to be plotted to the default.
void SetXaxis(TGaxis *ax)
void SetYaxis(TGaxis *ay)
void SetDefaultProjection()
Reset the projection plane.
double RndmUniform()
Draw a random number uniformly distributed in the range [0, 1).
PlottingEngineRoot plottingEngine