41#include <gsl/gsl_sys.h>
43#include <boost/filesystem.hpp>
47#define SQR(x) ((x)*(x))
48#define PointID(triangle_id, vertex_id) Triangles_m[triangle_id][vertex_id]
49#define Point(triangle_id, vertex_id) Points_m[Triangles_m[triangle_id][vertex_id]]
63#define FUNC_EQ(x, y) inline bool eq(double x, double y) { \
64 return almost_eq(x, y); \
67#define FUNC_EQ_ZERO(x) inline bool eq_zero(double x) { \
68 return almost_eq_zero(x); \
71#define FUNC_LE(x, y) inline bool le(double x, double y) { \
72 if (almost_eq(x, y)) { \
78#define FUNC_LE_ZERO(x) inline bool le_zero(double x) { \
79 if (almost_eq_zero(x)) { \
85#define FUNC_LT(x, y) inline bool lt(double x, double y) { \
86 if (almost_eq(x, y)) { \
92#define FUNC_LT_ZERO(x) inline bool lt_zero(double x) { \
93 if (almost_eq_zero(x)) { \
99#define FUNC_GE(x, y) inline bool ge(double x, double y) { \
100 if (almost_eq(x, y)) { \
106#define FUNC_GE_ZERO(x) inline bool ge_zero(double x) { \
107 if (almost_eq_zero(x)) { \
113#define FUNC_GT(x, y) inline bool gt(double x, double y) { \
114 if (almost_eq(x, y)) { \
120#define FUNC_GT_ZERO(x) inline bool gt_zero(double x) { \
121 if (almost_eq_zero(x)) { \
133 inline bool almost_eq(
double A,
double B,
double maxDiff = 1e-15,
double maxRelDiff = DBL_EPSILON) {
136 const double diff = std::abs(A - B);
142 const double largest = (B > A) ? B : A;
144 if (diff <= largest * maxRelDiff)
150 const double diff = std::abs(A);
151 return (diff <= maxDiff);
171 inline bool almost_eq(
double A,
double B,
double maxDiff = 1e-20,
int maxUlps = 1000) {
178 if (std::isnan(A) || std::isnan(B)) {
182 if (std::abs (A - B) <= maxDiff) {
186#pragma GCC diagnostic push
187#pragma GCC diagnostic ignored "-Wstrict-aliasing"
188 auto aInt = *(int64_t*)&A;
189#pragma GCC diagnostic pop
192 aInt = 0x8000000000000000 - aInt;
195#pragma GCC diagnostic push
196#pragma GCC diagnostic ignored "-Wstrict-aliasing"
197 auto bInt = *(int64_t*)&B;
198#pragma GCC diagnostic pop
201 bInt = 0x8000000000000000 - bInt;
204 if (std::abs (aInt - bInt) <= maxUlps) {
212 return (std::abs(A) <= maxDiff);
233 inline bool almost_eq (
double A,
double B,
double maxDiff = 1e-20,
int maxUlps = 1000) {
235 if (std::isnan (A) || std::isnan (B)) {
241 if (std::abs (A - B) <= maxDiff)
244#pragma GCC diagnostic push
245#pragma GCC diagnostic ignored "-Wstrict-aliasing"
246 auto aInt = *(int64_t*)&A;
247 auto bInt = *(int64_t*)&B;
248#pragma GCC diagnostic pop
252 if (std::signbit (aInt) != std::signbit (bInt))
256 return (std::abs (aInt - bInt) <= maxUlps);
260 return (std::abs (A) <= maxDiff);
309Vector_t get_max_extent (std::vector<Vector_t>& coords) {
311 coords.begin (), coords.end (), VectorLessX ());
313 coords.begin (), coords.end (), VectorLessY ());
315 coords.begin (), coords.end (), VectorLessZ ());
323Vector_t get_min_extent (std::vector<Vector_t>& coords) {
325 coords.begin (), coords.end (), VectorLessX ());
327 coords.begin (), coords.end (), VectorLessY ());
329 coords.begin (), coords.end (), VectorLessZ ());
336static void write_voxel_mesh (
338 const std::unordered_map<
int, std::unordered_set<int> >& ids,
340 const Vektor<int,3>&
nr,
344 const size_t numpoints = 8 * ids.size ();
347 *
gmsg <<
level2 <<
"* Writing VTK file of voxel mesh '" << fname <<
"'" <<
endl;
352 of <<
"# vtk DataFile Version 2.0" << std::endl;
353 of <<
"generated using BoundaryGeometry::computeMeshVoxelization"
355 of <<
"ASCII" << std::endl << std::endl;
356 of <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
357 of <<
"POINTS " << numpoints <<
" float" << std::endl;
359 const auto nr0_times_nr1 =
nr[0] *
nr[1];
360 for (
auto& elem: ids) {
361 auto id = elem.first;
362 int k = (
id - 1) / nr0_times_nr1;
363 int rest = (
id - 1) % nr0_times_nr1;
364 int j = rest /
nr[0];
365 int i = rest %
nr[0];
368 P[0] = i * hr_m[0] + origin[0];
369 P[1] = j * hr_m[1] + origin[1];
370 P[2] = k * hr_m[2] + origin[2];
372 of << P[0] <<
" " << P[1] <<
" " << P[2] << std::endl;
373 of << P[0] + hr_m[0] <<
" " << P[1] <<
" " << P[2] << std::endl;
374 of << P[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] << std::endl;
375 of << P[0] + hr_m[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] << std::endl;
376 of << P[0] <<
" " << P[1] <<
" " << P[2] + hr_m[2] << std::endl;
377 of << P[0] + hr_m[0] <<
" " << P[1] <<
" " << P[2] + hr_m[2] << std::endl;
378 of << P[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] + hr_m[2] << std::endl;
379 of << P[0] + hr_m[0] <<
" " << P[1] + hr_m[1] <<
" " << P[2] + hr_m[2] << std::endl;
382 const auto num_cells = ids.size ();
383 of <<
"CELLS " << num_cells <<
" " << 9 * num_cells << std::endl;
384 for (
size_t i = 0; i < num_cells; i++)
386 << 8 * i <<
" " << 8 * i + 1 <<
" " << 8 * i + 2 <<
" " << 8 * i + 3 <<
" "
387 << 8 * i + 4 <<
" " << 8 * i + 5 <<
" " << 8 * i + 6 <<
" " << 8 * i + 7 << std::endl;
388 of <<
"CELL_TYPES " << num_cells << std::endl;
389 for (
size_t i = 0; i < num_cells; i++)
390 of <<
"11" << std::endl;
391 of <<
"CELL_DATA " << num_cells << std::endl;
392 of <<
"SCALARS " <<
"cell_attribute_data" <<
" float " <<
"1" << std::endl;
393 of <<
"LOOKUP_TABLE " <<
"default" << std::endl;
394 for (
size_t i = 0; i < num_cells; i++)
395 of << (
float)(i) << std::endl;
397 of <<
"COLOR_SCALARS " <<
"BBoxColor " << 4 << std::endl;
398 for (
size_t i = 0; i < num_cells; i++) {
399 of <<
"1.0" <<
" 1.0 " <<
"0.0 " <<
"1.0" << std::endl;
430 inline double v1(
int i)
const {
436 inline double v2(
int i)
const {
442 inline double v3(
int i)
const {
451 pts[0][0] *= scaleby[0];
452 pts[0][1] *= scaleby[1];
453 pts[0][2] *= scaleby[2];
454 pts[1][0] *= scaleby[0];
455 pts[1][1] *= scaleby[1];
456 pts[1][2] *= scaleby[2];
457 pts[2][0] *= scaleby[0];
458 pts[2][1] *= scaleby[1];
459 pts[2][2] *= scaleby[2];
477 int outcode_fcmp = 0;
479 if (
cmp::gt(p[0], 0.5)) outcode_fcmp |= 0x01;
480 if (
cmp::lt(p[0], -0.5)) outcode_fcmp |= 0x02;
481 if (
cmp::gt(p[1], 0.5)) outcode_fcmp |= 0x04;
482 if (
cmp::lt(p[1], -0.5)) outcode_fcmp |= 0x08;
483 if (
cmp::gt(p[2], 0.5)) outcode_fcmp |= 0x10;
484 if (
cmp::lt(p[2], -0.5)) outcode_fcmp |= 0x20;
486 return(outcode_fcmp);
497 int outcode_fcmp = 0;
499 if (
cmp::gt( p[0] + p[1], 1.0)) outcode_fcmp |= 0x001;
500 if (
cmp::gt( p[0] - p[1], 1.0)) outcode_fcmp |= 0x002;
501 if (
cmp::gt(-p[0] + p[1], 1.0)) outcode_fcmp |= 0x004;
502 if (
cmp::gt(-p[0] - p[1], 1.0)) outcode_fcmp |= 0x008;
503 if (
cmp::gt( p[0] + p[2], 1.0)) outcode_fcmp |= 0x010;
504 if (
cmp::gt( p[0] - p[2], 1.0)) outcode_fcmp |= 0x020;
505 if (
cmp::gt(-p[0] + p[2], 1.0)) outcode_fcmp |= 0x040;
506 if (
cmp::gt(-p[0] - p[2], 1.0)) outcode_fcmp |= 0x080;
507 if (
cmp::gt( p[1] + p[2], 1.0)) outcode_fcmp |= 0x100;
508 if (
cmp::gt( p[1] - p[2], 1.0)) outcode_fcmp |= 0x200;
509 if (
cmp::gt(-p[1] + p[2], 1.0)) outcode_fcmp |= 0x400;
510 if (
cmp::gt(-p[1] - p[2], 1.0)) outcode_fcmp |= 0x800;
512 return(outcode_fcmp);
523 int outcode_fcmp = 0;
525 if (
cmp::gt( p[0] + p[1] + p[2], 1.5)) outcode_fcmp |= 0x01;
526 if (
cmp::gt( p[0] + p[1] - p[2], 1.5)) outcode_fcmp |= 0x02;
527 if (
cmp::gt( p[0] - p[1] + p[2], 1.5)) outcode_fcmp |= 0x04;
528 if (
cmp::gt( p[0] - p[1] - p[2], 1.5)) outcode_fcmp |= 0x08;
529 if (
cmp::gt(-p[0] + p[1] + p[2], 1.5)) outcode_fcmp |= 0x10;
530 if (
cmp::gt(-p[0] + p[1] - p[2], 1.5)) outcode_fcmp |= 0x20;
531 if (
cmp::gt(-p[0] - p[1] + p[2], 1.5)) outcode_fcmp |= 0x40;
532 if (
cmp::gt(-p[0] - p[1] - p[2], 1.5)) outcode_fcmp |= 0x80;
534 return(outcode_fcmp);
553#define LERP(a, b, t) (a + t * (b - a))
555 plane_point[0] =
LERP(p1[0], p2[0], alpha);
556 plane_point[1] =
LERP(p1[1], p2[1], alpha);
557 plane_point[2] =
LERP(p1[2], p2[2], alpha);
559 return(face_plane(plane_point) & mask);
573 const int outcode_diff
575 if ((0x01 & outcode_diff) != 0)
576 if (check_point(p1,p2,( .5-p1[0])/(p2[0]-p1[0]),0x3e) ==
INSIDE)
return(
INSIDE);
577 if ((0x02 & outcode_diff) != 0)
578 if (check_point(p1,p2,(-.5-p1[0])/(p2[0]-p1[0]),0x3d) ==
INSIDE)
return(
INSIDE);
579 if ((0x04 & outcode_diff) != 0)
580 if (check_point(p1,p2,( .5-p1[1])/(p2[1]-p1[1]),0x3b) ==
INSIDE)
return(
INSIDE);
581 if ((0x08 & outcode_diff) != 0)
582 if (check_point(p1,p2,(-.5-p1[1])/(p2[1]-p1[1]),0x37) ==
INSIDE)
return(
INSIDE);
583 if ((0x10 & outcode_diff) != 0)
584 if (check_point(p1,p2,( .5-p1[2])/(p2[2]-p1[2]),0x2f) ==
INSIDE)
return(
INSIDE);
585 if ((0x20 & outcode_diff) != 0)
586 if (check_point(p1,p2,(-.5-p1[2])/(p2[2]-p1[2]),0x1f) ==
INSIDE)
return(
INSIDE);
594constexpr double EPS = 10e-15;
599 return (((A[0] <
EPS) ? 4 : 0) | ((A[0] > -
EPS) ? 32 : 0) |
600 ((A[1] <
EPS) ? 2 : 0) | ((A[1] > -
EPS) ? 16 : 0) |
601 ((A[2] <
EPS) ? 1 : 0) | ((A[2] > -
EPS) ? 8 : 0));
605point_triangle_intersection (
630 const int sign12 = SIGN3(cross12_1p);
635 const int sign23 = SIGN3(cross23_2p);
640 const int sign31 = SIGN3(cross31_3p);
660triangle_intersects_cube (
679 if ((v1_test & v2_test & v3_test) != 0)
return(
OUTSIDE);
684 v1_test |= bevel_2d(t.
v1()) << 8;
685 v2_test |= bevel_2d(t.
v2()) << 8;
686 v3_test |= bevel_2d(t.
v3()) << 8;
687 if ((v1_test & v2_test & v3_test) != 0)
return(
OUTSIDE);
692 v1_test |= bevel_3d(t.
v1()) << 24;
693 v2_test |= bevel_3d(t.
v2()) << 24;
694 v3_test |= bevel_3d(t.
v3()) << 24;
695 if ((v1_test & v2_test & v3_test) != 0)
return(
OUTSIDE);
705 if ((v1_test & v2_test) == 0)
707 if ((v1_test & v3_test) == 0)
709 if ((v2_test & v3_test) == 0)
739 double d = norm[0] * t.
v1(0) + norm[1] * t.
v1(1) + norm[2] * t.
v1(2);
745 double denom = norm[0] + norm[1] + norm[2];
749 if (
cmp::le(std::abs(hitpp[0]), 0.5))
750 if (point_triangle_intersection(hitpp,t) ==
INSIDE)
753 denom = norm[0] + norm[1] - norm[2];
756 hitpn[2] = -(hitpn[0] = hitpn[1] = d / denom);
757 if (
cmp::le(std::abs(hitpn[0]), 0.5))
758 if (point_triangle_intersection(hitpn,t) ==
INSIDE)
761 denom = norm[0] - norm[1] + norm[2];
764 hitnp[1] = -(hitnp[0] = hitnp[2] = d / denom);
765 if (
cmp::le(std::abs(hitnp[0]), 0.5))
766 if (point_triangle_intersection(hitnp,t) ==
INSIDE)
769 denom = norm[0] - norm[1] - norm[2];
772 hitnn[1] = hitnn[2] = -(hitnn[0] = d / denom);
773 if (
cmp::le(std::abs(hitnn[0]), 0.5))
774 if (point_triangle_intersection(hitnn,t) ==
INSIDE)
893 t_.
scale (scaleby , v_.
pts[0] + 0.5);
894 return triangle_intersects_cube (t_);
916static inline Vector_t normalVector (
922 const double magnitude = std::sqrt (
SQR (N (0)) +
SQR (N (1)) +
SQR (N (2)));
924 return N / magnitude;
928static inline double computeArea (
935 return(0.5 * std::sqrt (
dot (AB, AB) *
dot (AC, AC) -
dot (AB, AC) *
dot (AB, AC)));
950 SIZE,
"GEOMETRY",
"The \"GEOMETRY\" statement defines the beam pipe geometry.") {
954 "Specifies the geometry file [H5hut]",
959 "If FGEOM is selected topo is over-written. ",
960 {
"RECTANGULAR",
"BOXCORNER",
"ELLIPTIC"},
965 "Specifies the length of a tube shaped elliptic beam pipe [m]",
970 "Specifies the start of a tube shaped elliptic beam pipe [m]",
975 "Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]",
980 "Specifies the major semi-axis of a tube shaped elliptic beam pipe [m]",
985 "In case of BOXCORNER Specifies first part with height == B [m]",
990 "In case of BOXCORNER Specifies first second with height == B-C [m]",
995 "In case of BOXCORNER Specifies height of corner C [m]",
1000 "Multiplicative scaling factor for coordinates ",
1005 "Multiplicative scaling factor for X coordinates ",
1010 "Multiplicative scaling factor for Y coordinates ",
1015 "Multiplicative scaling factor for Z coordinates ",
1020 "Shift in z direction",
1024 (
"INSIDEPOINT",
"A point inside the geometry");
1045 gsl_rng_env_setup();
1046 randGen_m = gsl_rng_alloc(gsl_rng_default);
1053 const std::string&
name,
1056 gsl_rng_env_setup();
1057 randGen_m = gsl_rng_alloc(gsl_rng_default);
1102 throw OpalException (
"BoundaryGeometry::find()",
"Geometry \""
1103 +
name +
"\" not found.");
1112 const int triangle_id,
1178 const int triangle_id,
1194 const double a = -
dot(n,w0);
1195 const double b =
dot(n,dir);
1205 const double r =
a / b;
1223 const double uu =
dot(u,u);
1224 const double uv =
dot(u,v);
1225 const double vv =
dot(v,v);
1227 const double wu =
dot(w,u);
1228 const double wv =
dot(w,v);
1229 const double D = uv * uv - uu * vv;
1232 const double s = (uv * wv - vv * wu) / D;
1236 const double t = (uv * wu - uu * wv) / D;
1250static inline double magnitude (
1253 return std::sqrt (
dot (v,v));
1266 double distance = P[0] - x;
1271 if (
cmp::lt(x - P[0], distance)) {
1272 distance = x - P[0];
1273 ref_pt = {x, P[1], P[2]};
1278 if (
cmp::lt(P[1] - y, distance)) {
1280 ref_pt = {P[0], y, P[1]};
1285 if (
cmp::lt(y - P[1], distance)) {
1286 distance = y - P[1];
1287 ref_pt = {P[0], y, P[2]};
1291 if (
cmp::lt(P[2] - z, distance)) {
1292 distance = P[2] - z;
1293 ref_pt = {P[0], P[1], z};
1297 if (
cmp::lt(z - P[2], distance)) {
1298 ref_pt = {P[0], P[1], z};
1307 return (k % 2) == 1;
1366 *
gmsg <<
level2 <<
"* Searching for a point inside the geometry..." <<
endl;
1371 std::vector<Vector_t> P_outs {
1381 for (
const auto& P: P_outs) {
1406 }
else if (n == n_i) {
1432 if (!
c.isInside (P))
return 1;
1437 *
gmsg <<
"* " << __func__ <<
": "
1438 <<
"reference_pt=" << reference_pt
1439 <<
", P=" << P <<
endl;
1443 const Vector_t v = reference_pt - P;
1444 const int N = std::ceil (magnitude (v) / std::min ({
voxelMesh_m.sizeOfVoxel [0],
1451 int triangle_id = -1;
1453 for (
int i = 0; i < N; i++) {
1460 *
gmsg <<
"* " << __func__ <<
": "
1461 <<
"result: " << result <<
endl;
1487 *
gmsg <<
"* " << __func__ <<
": "
1504 c.intersect (r, tmin, tmax);
1505 int triangle_id = -1;
1508 I, triangle_id) > 0) ? 1 : 0;
1511 *
gmsg <<
"* " << __func__ <<
": "
1512 <<
" result=" << result
1543#define mapPoint2VoxelIndices(pt, i, j, k) { \
1544 i = floor ((pt[0] - voxelMesh_m.minExtent [0]) / voxelMesh_m.sizeOfVoxel[0]); \
1545 j = floor ((pt[1] - voxelMesh_m.minExtent [1]) / voxelMesh_m.sizeOfVoxel[1]); \
1546 k = floor ((pt[2] - voxelMesh_m.minExtent [2]) / voxelMesh_m.sizeOfVoxel[2]); \
1547 if (!(0 <= i && i < voxelMesh_m.nr_m[0] && \
1548 0 <= j && j < voxelMesh_m.nr_m[1] && \
1549 0 <= k && k < voxelMesh_m.nr_m[2])) { \
1551 << "* " << __func__ << ":" \
1552 << " WARNING: pt=" << pt \
1553 << " is outside the bbox" \
1588 for (
unsigned int triangle_id = 0; triangle_id <
Triangles_m.size(); triangle_id++) {
1593 std::min({v1[0], v2[0], v3[0]}),
1594 std::min({v1[1], v2[1], v3[1]}),
1595 std::min({v1[2], v2[2], v3[2]}) };
1597 std::max({v1[0], v2[0], v3[0]}),
1598 std::max({v1[1], v2[1], v3[1]}),
1599 std::max({v1[2], v2[2], v3[2]}) };
1600 int i_min, j_min, k_min;
1601 int i_max, j_max, k_max;
1605 for (
int i = i_min; i <= i_max; i++) {
1606 for (
int j = j_min; j <= j_max; j++) {
1607 for (
int k = k_min; k <= k_max; k++) {
1625 bool writeVTK =
false;
1627 if (!std::filesystem::exists(vtkFileName)) {
1632 auto t_geom = boost::filesystem::last_write_time(
h5FileName_m);
1633 auto t_vtk = boost::filesystem::last_write_time(vtkFileName);
1634 if (std::difftime(t_geom, t_vtk) > 0) {
1640 write_voxel_mesh (vtkFileName,
1664 double longest_edge_max_m = 0.0;
1665 for (
unsigned int i = 0; i < bg->
Triangles_m.size(); i++) {
1670 const double length_edge1 = std::sqrt (
1671 SQR (x1[0] - x2[0]) +
SQR (x1[1] - x2[1]) +
SQR (x1[2] - x2[2]));
1672 const double length_edge2 = std::sqrt (
1673 SQR (x3[0] - x2[0]) +
SQR (x3[1] - x2[1]) +
SQR (x3[2] - x2[2]));
1674 const double length_edge3 = std::sqrt (
1675 SQR (x3[0] - x1[0]) +
SQR (x3[1] - x1[1]) +
SQR (x3[2] - x1[2]));
1677 double max = length_edge1;
1678 if (length_edge2 >
max)
max = length_edge2;
1679 if (length_edge3 >
max)
max = length_edge3;
1682 if (longest_edge_max_m <
max) longest_edge_max_m =
max;
1703 bg->
voxelMesh_m.nr_m (0) = 16 * (int)std::floor (extent [0] / longest_edge_max_m);
1704 bg->
voxelMesh_m.nr_m (1) = 16 * (int)std::floor (extent [1] / longest_edge_max_m);
1705 bg->
voxelMesh_m.nr_m (2) = 16 * (int)std::floor (extent [2] / longest_edge_max_m);
1839 static void computeTriangleNeighbors (
1841 std::vector<std::set<unsigned int>>& neighbors
1843 std::vector<std::set<unsigned int>> adjacencies_to_pt (bg->
Points_m.size());
1846 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size(); triangle_id++) {
1847 for (
unsigned int j = 1; j <= 3; j++) {
1848 auto pt_id = bg->PointID (triangle_id, j);
1850 adjacencies_to_pt [pt_id].insert (triangle_id);
1854 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size(); triangle_id++) {
1855 std::set<unsigned int> to_A = adjacencies_to_pt [bg->PointID (triangle_id, 1)];
1856 std::set<unsigned int> to_B = adjacencies_to_pt [bg->PointID (triangle_id, 2)];
1857 std::set<unsigned int> to_C = adjacencies_to_pt [bg->PointID (triangle_id, 3)];
1859 std::set<unsigned int> intersect;
1860 std::set_intersection (
1861 to_A.begin(), to_A.end(),
1862 to_B.begin(), to_B.end(),
1863 std::inserter(intersect,intersect.begin()));
1864 std::set_intersection(
1865 to_B.begin(), to_B.end(),
1866 to_C.begin(), to_C.end(),
1867 std::inserter(intersect,intersect.begin()));
1868 std::set_intersection(
1869 to_C.begin(), to_C.end(),
1870 to_A.begin(), to_A.end(),
1871 std::inserter(intersect, intersect.begin()));
1872 intersect.erase (triangle_id);
1874 neighbors [triangle_id] = intersect;
1876 *
gmsg <<
level2 <<
"* " << __func__ <<
": Computing neighbors done" <<
endl;
1906 std::vector<Vector_t> intersection_points;
1909 for (
unsigned int triangle_id = 0; triangle_id < bg->
Triangles_m.size(); triangle_id++) {
1912 intersection_points.push_back (result);
1917 return ((intersection_points.size () % 2) == 1);
1921 static bool hasInwardPointingNormal (
1923 const int triangle_id
1928 const Vector_t triNormal = normalVector (
A,
B,
C);
1932 double minvoxelmesh = bg->
voxelMesh_m.sizeOfVoxel[0];
1933 if (minvoxelmesh > bg->
voxelMesh_m.sizeOfVoxel[1])
1935 if (minvoxelmesh > bg->
voxelMesh_m.sizeOfVoxel[2])
1937 const Vector_t P = (
A+
B+
C)/3 + triNormal * minvoxelmesh;
1947 const bool is_inside =
isInside (bg, P);
1948 const double dotPA_N =
dot (P -
A, triNormal);
1949 return (is_inside && dotPA_N >= 0) || (!is_inside && dotPA_N < 0);
1953 static void orientTriangle (
BoundaryGeometry* bg,
int ref_id,
int triangle_id) {
1958 for (
int i = 1; i <= 3; i++) {
1959 for (
int j = 1; j <= 3; j++) {
1960 if (bg->PointID (triangle_id, j) == bg->PointID (ref_id, i)) {
1964 if (n == 2)
goto edge_found;
1970 int diff =
id[1] -
id[0];
1971 if ((((ic[1] - ic[0]) == 1) && ((diff == 1) || (diff == -2))) ||
1972 (((ic[1] - ic[0]) == 2) && ((diff == -1) || (diff == 2)))) {
1973 std::swap (bg->PointID (triangle_id,
id[0]), bg->PointID (triangle_id,
id[1]));
1978 std::vector<std::set<unsigned int>> neighbors (bg->
Triangles_m.size());
1980 computeTriangleNeighbors (bg, neighbors);
1983 int triangle_id = 0;
1985 std::vector<unsigned int> triangles (bg->
Triangles_m.size());
1986 std::vector<unsigned int>::size_type queue_cursor = 0;
1987 std::vector<unsigned int>::size_type queue_end = 0;
1988 std::vector <bool> isOriented (bg->
Triangles_m.size(),
false);
1995 while (isOriented[triangle_id])
1999 if (!hasInwardPointingNormal (bg, triangle_id)) {
2000 std::swap (bg->PointID (triangle_id, 2), bg->PointID (triangle_id, 3));
2002 isOriented[triangle_id] =
true;
2005 triangles[queue_end++] = triangle_id;
2007 for (
auto neighbor_id: neighbors[triangle_id]) {
2008 if (isOriented[neighbor_id])
continue;
2009 orientTriangle (bg, triangle_id, neighbor_id);
2010 isOriented[neighbor_id] =
true;
2011 triangles[queue_end++] = neighbor_id;
2014 }
while (queue_cursor < queue_end && (triangle_id = triangles[queue_cursor],
true));
2018 *
gmsg <<
level2 <<
"* " << __func__ <<
": mesh is contiguous" <<
endl;
2020 *
gmsg <<
level2 <<
"* " << __func__ <<
": mesh is discontiguous (" << parts <<
") parts" <<
endl;
2028 *
gmsg <<
level2 <<
"* Initializing Boundary Geometry..." <<
endl;
2034 "', please check if it exists");
2047 rc = H5SetErrorHandler (H5AbortErrorhandler);
2049 H5SetVerbosityLevel (1);
2051 h5_prop_t props = H5CreateFileProp ();
2053 H5SetPropFileMPIOCollective (props, &comm);
2054 h5_file_t f = H5OpenFile (
h5FileName_m.c_str(), H5_O_RDONLY, props);
2055 H5CloseProp (props);
2057 h5t_mesh_t* m =
nullptr;
2058 H5FedOpenTriangleMesh (f,
"0", &m);
2059 H5FedSetLevel (m, 0);
2061 auto numTriangles = H5FedGetNumElementsTotal (m);
2065 h5_loc_id_t local_id;
2067 h5t_iterator_t* iter = H5FedBeginTraverseEntities (m, 0);
2068 while ((local_id = H5FedTraverseEntities (iter)) >= 0) {
2069 h5_loc_id_t local_vids[4];
2070 H5FedGetVertexIndicesOfEntity (m, local_id, local_vids);
2072 PointID (i, 1) = local_vids[0];
2073 PointID (i, 2) = local_vids[1];
2074 PointID (i, 3) = local_vids[2];
2077 H5FedEndTraverseEntities (iter);
2080 int num_points = H5FedGetNumVerticesTotal (m);
2082 for (i = 0; i < num_points; i++) {
2084 H5FedGetVertexCoordsByIndex (m, i, P);
2086 P[0] * xyzscale * xscale,
2087 P[1] * xyzscale * yscale,
2088 P[2] * xyzscale * zscale + zshift));
2094 Local::computeGeometryInterval (
this);
2099 if (pt.size () != 3) {
2101 "BoundaryGeometry::initialize()",
2102 "Dimension of INSIDEPOINT must be 3");
2107 if (is_inside ==
false) {
2109 "BoundaryGeometry::initialize()",
2110 "INSIDEPOINT is not inside the geometry");
2117 *
gmsg <<
level2 <<
"* using as point inside the geometry: ("
2122 *
gmsg <<
level2 <<
"* no point inside the geometry found!" <<
endl;
2125 Local::makeTriangleNormalInwardPointing (
this);
2168 *
gmsg <<
"* " << __func__ <<
": "
2175 const Ray r =
Ray (P, v_);
2177 std::min(P[0], Q[0]),
2178 std::min(P[1], Q[1]),
2179 std::min(P[2], Q[2]) };
2181 std::max(P[0], Q[0]),
2182 std::max(P[1], Q[1]),
2183 std::max(P[2], Q[2]) };
2206 std::unordered_set<int> triangle_ids;
2207 for (
int i = i_min; i <= i_max; i++) {
2208 for (
int j = j_min; j <= j_max; j++) {
2209 for (
int k = k_min; k <= k_max; k++) {
2214 *
gmsg <<
"* " << __func__ <<
": "
2215 <<
" Test voxel: (" << i <<
", " << j <<
", " << k <<
"), "
2232 const auto triangles_intersecting_voxel =
2234 if (triangles_intersecting_voxel !=
voxelMesh_m.ids.end()) {
2235 triangle_ids.insert (
2236 triangles_intersecting_voxel->second.begin(),
2237 triangles_intersecting_voxel->second.end());
2246 int num_intersections = 0;
2247 int tmp_intersect_result = 0;
2249 for (
auto it = triangle_ids.begin ();
2250 it != triangle_ids.end ();
2260 *
gmsg <<
"* " << __func__ <<
": "
2261 <<
" Test triangle: " << *it
2262 <<
" intersect: " << tmp_intersect_result
2269 switch (tmp_intersect_result) {
2278 t = (tmp_intersect_pt[0] - P[0]) / (Q[0] - P[0]);
2280 t = (tmp_intersect_pt[1] - P[1]) / (Q[1] - P[1]);
2282 t = (tmp_intersect_pt[2] - P[2]) / (Q[2] - P[2]);
2284 num_intersections++;
2288 *
gmsg <<
"* " << __func__ <<
": "
2294 intersect_pt = tmp_intersect_pt;
2295 triangle_id = (*it);
2299 PAssert (tmp_intersect_result != -1);
2303 return num_intersections;
2321 *
gmsg <<
"* " << __func__ <<
": "
2331 int intersect_result = 0;
2333 int i_min, j_min, k_min;
2334 int i_max, j_max, k_max;
2339 std::min(P0[0], Q[0]),
2340 std::min(P0[1], Q[1]),
2341 std::min(P0[2], Q[2]) };
2343 std::max(P0[0], Q[0]),
2344 std::max(P0[1], Q[1]),
2345 std::max(P0[2], Q[2]) };
2348 }
while (( (i_max-i_min+1) * (j_max-j_min+1) * (k_max-k_min+1)) > 27);
2353 for (
int l = 1; l <= n; l++, P = Q) {
2356 P, Q, intersect_pt, triangle_id);
2357 if (triangle_id != -1) {
2363 *
gmsg <<
"* " << __func__ <<
": "
2364 <<
" result=" << intersect_result
2365 <<
" intersection pt: " << intersect_pt
2370 return intersect_result;
2392 *
gmsg <<
"* " << __func__ <<
": "
2413 int tmp_triangle_id = -1;
2415 if (tmp_triangle_id >= 0) {
2416 intersect_pt = tmp_intersect_pt;
2417 triangle_id = tmp_triangle_id;
2422 *
gmsg <<
"* " << __func__ <<
":"
2423 <<
" result=" << ret;
2425 *
gmsg <<
" intersetion=" << intersect_pt;
2438 of.open (fn.c_str ());
2441 of <<
"# vtk DataFile Version 2.0" << std::endl;
2442 of <<
"generated using DataSink::writeGeoToVtk" << std::endl;
2443 of <<
"ASCII" << std::endl << std::endl;
2444 of <<
"DATASET UNSTRUCTURED_GRID" << std::endl;
2445 of <<
"POINTS " <<
Points_m.size () <<
" float" << std::endl;
2446 for (
unsigned int i = 0; i <
Points_m.size (); i++)
2459 <<
PointID (i, 3) << std::endl;
2460 of <<
"CELL_TYPES " <<
Triangles_m.size() << std::endl;
2462 of <<
"5" << std::endl;
2463 of <<
"CELL_DATA " <<
Triangles_m.size() << std::endl;
2464 of <<
"SCALARS " <<
"cell_attribute_data" <<
" float " <<
"1" << std::endl;
2465 of <<
"LOOKUP_TABLE " <<
"default" << std::endl;
2467 of << (
float)(i) << std::endl;
2474 os <<
"* ************* B O U N D A R Y G E O M E T R Y *********************************** " <<
endl;
2491 os <<
"* Total triangle num " <<
Triangles_m.size() <<
'\n'
2492 <<
"* Total points num " <<
Points_m.size () <<
'\n'
2493 <<
"* Geometry bounds(m) Max = " <<
maxExtent_m <<
'\n'
2496 <<
"* Resolution of voxel mesh " <<
voxelMesh_m.nr_m <<
'\n'
2497 <<
"* Size of voxel " <<
voxelMesh_m.sizeOfVoxel <<
'\n'
2499 os <<
"* ********************************************************************************** " <<
endl;
Vector3D cross(const Vector3D &lhs, const Vector3D &rhs)
Vector cross product.
double dot(const Vector3D &lhs, const Vector3D &rhs)
Vector dot product.
constexpr double c
The velocity of light in m/s.
#define PointID(triangle_id, vertex_id)
#define mapPoint2VoxelIndices(pt, i, j, k)
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Inform & level2(Inform &inf)
Inform & endl(Inform &inf)
double getReal(const Attribute &attr)
Return real value.
Attribute makePredefinedString(const std::string &name, const std::string &help, const std::initializer_list< std::string > &predefinedStrings)
Make predefined string attribute.
Attribute makeReal(const std::string &name, const std::string &help)
Make real attribute.
Attribute makeRealArray(const std::string &name, const std::string &help)
Create real array attribute.
std::vector< double > getRealArray(const Attribute &attr)
Get array value.
std::string getString(const Attribute &attr)
Get string value.
Attribute makeString(const std::string &name, const std::string &help)
Make string attribute.
constexpr double c
The velocity of light in m/s.
bool enableVTK
If true VTK files are written.
std::string combineFilePath(std::initializer_list< std::string > ilist)
bool almost_eq(double A, double B, double maxDiff=1e-15, double maxRelDiff=DBL_EPSILON)
bool almost_eq_zero(double A, double maxDiff=1e-15)
bool almost_eq(double A, double B, double maxDiff=1e-20, int maxUlps=1000)
bool almost_eq_zero(double A, double maxDiff=1e-15)
bool almost_eq(double A, double B, double maxDiff=1e-20, int maxUlps=1000)
bool ge(double x, double y)
bool gt(double x, double y)
bool almost_eq_zero(double A, double maxDiff=1e-15)
bool lt(double x, double y)
bool le(double x, double y)
Definition(int size, const char *name, const char *help)
Constructor for exemplars.
void registerOwnership(const AttributeHandler::OwnerType &itsClass) const
const std::string & getOpalName() const
Return object name.
Object(int size, const char *name, const char *help)
Constructor for exemplars.
void setOpalName(const std::string &name)
Set object name.
std::vector< Attribute > itsAttr
The object attributes.
bool builtin
Built-in flag.
Object * find(const std::string &name)
Find entry.
static OpalData * getInstance()
void define(Object *newObject)
Define a new object.
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Abstract base class for accelerator geometry classes.
Triangle(const Vector_t &v1, const Vector_t &v2, const Vector_t &v3)
const Vector_t & v3() const
const Vector_t & v2() const
const Vector_t & v1() const
void scale(const Vector_t &scaleby, const Vector_t &shiftby)
const Ray & operator=(const Ray &a)=delete
Ray(Vector_t o, Vector_t d)
bool isInside(const Vector_t &P) const
bool intersect(const Ray &r, double &tmin, double &tmax) const
Voxel(const Vector_t &min, const Vector_t &max)
int intersect(const Triangle &t) const
bool intersect(const Ray &r) const
void scale(const Vector_t &scale)
std::vector< std::array< unsigned int, 4 > > Triangles_m
IpplTimings::TimerRef TisInside_m
std::vector< Vector_t > TriNormals_m
int fastIsInside(const Vector_t &reference_pt, const Vector_t &P)
int intersectRayBoundary(const Vector_t &P, const Vector_t &v, Vector_t &I)
std::vector< double > TriAreas_m
virtual void execute()
Execute the command.
const Vector_t & getPoint(const int triangle_id, const int vertex_id)
virtual void update()
Update this object.
IpplTimings::TimerRef TRayTrace_m
struct BoundaryGeometry::@117056140100230112133004050263065356254101277345 voxelMesh_m
virtual bool canReplaceBy(Object *object)
Test if replacement is allowed.
bool isInside(const Vector_t &P)
std::vector< Vector_t > Points_m
static BoundaryGeometry * find(const std::string &name)
int intersectLineSegmentBoundary(const Vector_t &P0, const Vector_t &P1, Vector_t &intersection_pt, int &triangle_id)
IpplTimings::TimerRef Tinitialize_m
int mapVoxelIndices2ID(const int i, const int j, const int k)
IpplTimings::TimerRef TPartInside_m
Vector_t mapPoint2Voxel(const Vector_t &)
IpplTimings::TimerRef TfastIsInside_m
int intersectTriangleVoxel(const int triangle_id, const int i, const int j, const int k)
void writeGeomToVtk(std::string fn)
@ debug_intersectRayBoundary
@ debug_intersectTinyLineSegmentBoundary
@ debug_intersectLineSegmentBoundary
bool findInsidePoint(void)
int partInside(const Vector_t &r, const Vector_t &v, const double dt, Vector_t &intecoords, int &triId)
int intersectTinyLineSegmentBoundary(const Vector_t &, const Vector_t &, Vector_t &, int &)
virtual BoundaryGeometry * clone(const std::string &name)
Return a clone.
Topology getTopology() const
virtual ~BoundaryGeometry()
Inform & printInfo(Inform &os) const
Vector_t mapIndices2Voxel(const int, const int, const int)
int intersectLineTriangle(const enum INTERSECTION_TESTS kind, const Vector_t &P0, const Vector_t &P1, const int triangle_id, Vector_t &I)
void computeMeshVoxelization(void)
void updateElement(ElementBase *element)
The base class for all OPAL exceptions.
static MPI_Comm getComm()
static Communicate * Comm
static TimerRef getTimer(const char *nm)
static void stopTimer(TimerRef t)
static void startTimer(TimerRef t)
Vektor< double, 3 > Vector_t