geometry_utils.inl 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2006-2017 by
  4. * The Salk Institute for Biological Studies and
  5. * Pittsburgh Supercomputing Center, Carnegie Mellon University
  6. *
  7. * Use of this source code is governed by an MIT-style
  8. * license that can be found in the LICENSE file or at
  9. * https://opensource.org/licenses/MIT.
  10. *
  11. ******************************************************************************/
  12. #ifndef SRC4_GEOMETRY_UTILS_INC_
  13. #define SRC4_GEOMETRY_UTILS_INC_
  14. /**
  15. * This file is directly included into diffuse_react_event.cpp.
  16. * The reason why this is not a standard .cpp + .h file is to gove the compiler
  17. * the opportunity to inline these functions into methods of diffuse&react event.
  18. */
  19. #include <vector>
  20. #include "logging.h"
  21. #include "diffuse_react_event.h"
  22. #include "defines.h"
  23. #include "world.h"
  24. #include "partition.h"
  25. #include "geometry.h"
  26. #include "debug_config.h"
  27. #include "wall_utils.inl"
  28. namespace MCell {
  29. namespace GeometryUtils {
  30. static Vec2 xyz2uv(const Partition& p, const Vec3& a, const Wall& w) {
  31. Vec2 res;
  32. if (w.has_initialized_grid()) {
  33. const Grid& g = w.grid;
  34. res.u = a.x * w.unit_u.x + a.y * w.unit_u.y + a.z * w.unit_u.z -
  35. g.vert0.u;
  36. res.v = a.x * w.unit_v.x + a.y * w.unit_v.y + a.z * w.unit_v.z -
  37. g.vert0.v;
  38. }
  39. else {
  40. Vec3 pos = a - p.get_wall_vertex(w, 0);
  41. res.u = dot(pos, w.unit_u);
  42. res.v = dot(pos, w.unit_v);
  43. }
  44. return res;
  45. }
  46. /***************************************************************************
  47. wall_bounding_box:
  48. In: a wall
  49. vector to store one corner of the bounding box for that wall
  50. vector to store the opposite corner
  51. Out: No return value. The vectors are set to define the smallest box
  52. that contains the wall.
  53. ***************************************************************************/
  54. static inline void get_wall_bounding_box(
  55. const Vec3 w_vert[VERTICES_IN_TRIANGLE],
  56. Vec3& llf, Vec3& urb
  57. ) {
  58. llf.x = urb.x = w_vert[0].x;
  59. llf.y = urb.y = w_vert[0].y;
  60. llf.z = urb.z = w_vert[0].z;
  61. if (w_vert[1].x < llf.x)
  62. llf.x = w_vert[1].x;
  63. else if (w_vert[1].x > urb.x)
  64. urb.x = w_vert[1].x;
  65. if (w_vert[2].x < llf.x)
  66. llf.x = w_vert[2].x;
  67. else if (w_vert[2].x > urb.x)
  68. urb.x = w_vert[2].x;
  69. if (w_vert[1].y < llf.y)
  70. llf.y = w_vert[1].y;
  71. else if (w_vert[1].y > urb.y)
  72. urb.y = w_vert[1].y;
  73. if (w_vert[2].y < llf.y)
  74. llf.y = w_vert[2].y;
  75. else if (w_vert[2].y > urb.y)
  76. urb.y = w_vert[2].y;
  77. if (w_vert[1].z < llf.z)
  78. llf.z = w_vert[1].z;
  79. else if (w_vert[1].z > urb.z)
  80. urb.z = w_vert[1].z;
  81. if (w_vert[2].z < llf.z)
  82. llf.z = w_vert[2].z;
  83. else if (w_vert[2].z > urb.z)
  84. urb.z = w_vert[2].z;
  85. }
  86. /***************************************************************************
  87. distribute_wall:
  88. In: a wall 'w' that fully fits into partition 'p'
  89. Out: colliding_subparts - indices of all the subpartitions in a given partition
  90. where the wall is located
  91. ***************************************************************************/
  92. // original name: distribute_wall
  93. static void wall_subparts_collision_test(
  94. const Partition& p, const Wall& w,
  95. SubpartIndicesVector& colliding_subparts
  96. ) {
  97. Vec3 llf, urb; /* Bounding box for wall */
  98. pos_t leeway = 1; /* Margin of error */
  99. Vec3 w_vert[VERTICES_IN_TRIANGLE];
  100. w_vert[0] = p.get_geometry_vertex(w.vertex_indices[0]);
  101. w_vert[1] = p.get_geometry_vertex(w.vertex_indices[1]);
  102. w_vert[2] = p.get_geometry_vertex(w.vertex_indices[2]);
  103. get_wall_bounding_box(w_vert, llf, urb);
  104. // min
  105. if (llf.x < -leeway)
  106. leeway = -llf.x;
  107. if (llf.y < -leeway)
  108. leeway = -llf.y;
  109. if (llf.z < -leeway)
  110. leeway = -llf.z;
  111. // max
  112. if (urb.x > leeway)
  113. leeway = urb.x;
  114. if (urb.y > leeway)
  115. leeway = urb.y;
  116. if (urb.z > leeway)
  117. leeway = urb.z;
  118. leeway = POS_EPS + leeway * POS_EPS;
  119. if (p.config.use_expanded_list) {
  120. leeway += p.config.rxn_radius_3d;
  121. }
  122. Vec3 leeway3 = Vec3(leeway);
  123. llf = llf - leeway3;
  124. urb = urb + leeway3;
  125. // let's assume for now that we are placing a cube with corners llf and urb,
  126. // fing what are the min and max parition indices
  127. IVec3 min_subpart_indices, max_subpart_indices;
  128. p.get_subpart_3d_indices(llf, min_subpart_indices);
  129. p.get_subpart_3d_indices(urb, max_subpart_indices);
  130. #if 0
  131. // don't know yet what is this doing, somehow it is trying to find some subvolume
  132. // but don't know which one
  133. // probably just an optimization
  134. // this is needed for the following code (if enabled, fix loop afterwards)
  135. max_subpart_indices += IVec3(1); // max is incremented by 1 in each dimension
  136. cent.x = 0.33333333333 * (w_vert[0].x + w_vert[1].x + w_vert[2].x);
  137. cent.y = 0.33333333333 * (w_vert[0].y + w_vert[1].y + w_vert[2].y);
  138. cent.z = 0.33333333333 * (w_vert[0].z + w_vert[1].z + w_vert[2].z);
  139. for (i = x_min; i < x_max; i++) {
  140. if (cent.x < world->x_partitions[i])
  141. break;
  142. }
  143. for (j = y_min; j < y_max; j++) {
  144. if (cent.y < world->y_partitions[j])
  145. break;
  146. }
  147. for (k = z_min; k < z_max; k++) {
  148. if (cent.z < world->z_partitions[k])
  149. break;
  150. }
  151. h = (k - 1) +
  152. (world->nz_parts - 1) * ((j - 1) + (world->ny_parts - 1) * (i - 1));
  153. where_am_i = localize_wall(w, world->subvol[h].local_storage);
  154. if (where_am_i == NULL)
  155. return NULL;
  156. #endif
  157. // go through all subparts in llf-urb box and select only those that cross our wall
  158. for (int x = min_subpart_indices.x; x <= max_subpart_indices.x; x++) {
  159. for (int y = min_subpart_indices.y; y <= max_subpart_indices.y; y++) {
  160. for (int z = min_subpart_indices.z; z <= max_subpart_indices.z; z++) {
  161. Vec3 subpart_llf, subpart_urb;
  162. subpart_index_t subpart_index = p.get_subpart_index_from_3d_indices(x, y, z);
  163. p.get_subpart_llf_point(subpart_index, subpart_llf);
  164. p.get_subpart_urb_point_from_llf(subpart_llf, subpart_urb);
  165. subpart_llf = subpart_llf - leeway3;
  166. subpart_urb = subpart_urb + leeway3;
  167. if (WallUtils::wall_in_box(p, w, subpart_llf, subpart_urb) != 0) {
  168. colliding_subparts.push_back(subpart_index);
  169. }
  170. }
  171. }
  172. }
  173. }
  174. /***************************************************************************
  175. find_edge_point:
  176. In: here: a wall
  177. loc: a point in the coordinate system of that wall where we are now
  178. (assumed to be on or inside triangle)
  179. disp: a 2D displacement vector to move
  180. edgept: a place to store the coordinate on the edge, if we hit it
  181. Out: index of the edge we hit (0, 1, or 2), or 3 if the new location
  182. is within the wall, or 4 if we can't tell. If the result is
  183. 0, 1, or 2, edgept is set to the new location.
  184. ***************************************************************************/
  185. static edge_index_t find_edge_point(
  186. const Wall& here,
  187. const Vec2& loc,
  188. const Vec2& disp,
  189. Vec2& edgept
  190. ) {
  191. pos_t lxd = determinant2(loc, disp);
  192. pos_t lxc1 = -loc.v * here.uv_vert1_u;
  193. pos_t dxc1 = -disp.v * here.uv_vert1_u;
  194. // Make sure that the displacement vector isn't on v0v1
  195. pos_t f, s, t;
  196. if (dxc1 < -POS_EPS || dxc1 > POS_EPS) {
  197. f = 1 / dxc1; /* f>0 is passing outwards */
  198. s = -lxd * f;
  199. if (0 < s && s < 1 && f > 0) {
  200. t = -lxc1 * f;
  201. if (POS_EPS < t && t < 1) {
  202. edgept = loc + Vec2(t) * disp;
  203. return EDGE_INDEX_0;
  204. }
  205. else if (t > 1 + POS_EPS) {
  206. return EDGE_INDEX_WITHIN_WALL;
  207. }
  208. /* else can't tell if we hit this edge, assume not */
  209. }
  210. }
  211. pos_t lxc2 = determinant2(loc, here.uv_vert2);
  212. pos_t dxc2 = determinant2(disp, here.uv_vert2);
  213. // Make sure that the displacement vector isn't on v1v2
  214. if (dxc2 < -POS_EPS || dxc2 > POS_EPS) {
  215. f = 1 / dxc2; /* f<0 is passing outwards */
  216. s = 1 + lxd * f;
  217. if (0 < s && s < 1 && f < 0) {
  218. t = -lxc2 * f;
  219. if (POS_EPS < t && t < 1) {
  220. edgept = loc + Vec2(t) * disp;
  221. return EDGE_INDEX_2;
  222. }
  223. else if (t > 1 + POS_EPS) {
  224. return EDGE_INDEX_WITHIN_WALL;
  225. }
  226. /* else can't tell */
  227. }
  228. }
  229. f = dxc2 - dxc1;
  230. if (f < -POS_EPS || f > POS_EPS) {
  231. f = 1 / f; /* f>0 is passing outwards */
  232. s = -(lxd + dxc1) * f;
  233. if (0 < s && s < 1 && f > 0) {
  234. t = (here.uv_vert1_u * here.uv_vert2.v + lxc1 - lxc2) * f;
  235. if (POS_EPS < t && t < 1) {
  236. edgept = loc + Vec2(t) * disp;
  237. return EDGE_INDEX_1;
  238. }
  239. else if (t > 1 + POS_EPS) {
  240. return EDGE_INDEX_WITHIN_WALL;
  241. }
  242. /* else can't tell */
  243. }
  244. }
  245. return EDGE_INDEX_CANNOT_TELL; /* Couldn't tell whether we hit or not--calling function should
  246. pick another displacement */
  247. }
  248. /***************************************************************************
  249. traverse_surface:
  250. In: here: a wall
  251. loc: a point in the coordinate system of that wall
  252. which: which edge to travel off of
  253. newloc: a vector to set for the new wall
  254. Out: NULL if the edge is not shared, or a pointer to the wall in that
  255. direction if it is shared. newloc is set to loc in the coordinate system
  256. of the new wall (after flattening the walls along their shared edge)
  257. ***************************************************************************/
  258. static wall_index_t traverse_surface(const Wall& here, const Vec2& loc, edge_index_t which_edge,
  259. Vec2& newloc) {
  260. wall_index_t there;
  261. const Edge& e = here.edges[which_edge];
  262. if (e.forward_index == here.index) {
  263. /* Apply forward transform to loc */
  264. there = e.backward_index;
  265. /* rotation */
  266. Vec2 tmp;
  267. tmp.u = e.get_cos_theta() * loc.u + e.get_sin_theta() * loc.v;
  268. tmp.v = -e.get_sin_theta() * loc.u + e.get_cos_theta() * loc.v;
  269. /* translation */
  270. newloc = tmp + e.get_translate();
  271. return there;
  272. }
  273. else {
  274. /* Apply inverse transform to loc */
  275. there = e.forward_index;
  276. /* inverse translation */
  277. Vec2 tmp;
  278. tmp = loc - e.get_translate();
  279. /* inverse rotation */
  280. newloc.u = e.get_cos_theta() * tmp.u - e.get_sin_theta() * tmp.v;
  281. newloc.v = e.get_sin_theta() * tmp.u + e.get_cos_theta() * tmp.v;
  282. return there;
  283. }
  284. return WALL_INDEX_INVALID;
  285. }
  286. /**************************************************************************
  287. same_side:
  288. In: two points p1 and p2
  289. line defined by the points a and b
  290. Out: returns 1 if points p1 and p2 are on the same side of the line
  291. defined by the points a and b
  292. **************************************************************************/
  293. static int same_side(const Vec3& p1, const Vec3& p2, const Vec3& a, const Vec3& b) {
  294. Vec3 cp1, cp2, b_a, p1_a, p2_a;
  295. b_a = b - a;
  296. p1_a = p1 - a;
  297. p2_a = p2 - a;
  298. cp1 = cross(b_a, p1_a);
  299. cp2 = cross(b_a, p2_a);
  300. if (dot(cp1, cp2) >= 0) {
  301. return 1;
  302. }
  303. else {
  304. return 0;
  305. }
  306. }
  307. /************************************************************************
  308. point_in_triangle:
  309. In: point p
  310. triangle defined by points a,b,c
  311. Out: returns 1 if point p is in the triangle defined by
  312. points (a,b,c) or lies on edges (a,b), (b,c) or (a,c).
  313. Note: If point p coincides with vertices (a,b,c) we consider that p
  314. is in the triangle.
  315. ************************************************************************/
  316. static bool point_in_triangle(const Vec3& p, const Vec3& a, const Vec3& b, const Vec3& c) {
  317. if (same_side(p, a, b, c) && same_side(p, b, a, c) && same_side(p, c, a, b)) {
  318. return 1;
  319. }
  320. if (((!distinguishable_p(p.x, a.x, POS_EPS)) &&
  321. (!distinguishable_p(p.y, a.y, POS_EPS)) &&
  322. (!distinguishable_p(p.z, a.z, POS_EPS))) ||
  323. ((!distinguishable_p(p.x, b.x, POS_EPS)) &&
  324. (!distinguishable_p(p.y, b.y, POS_EPS)) &&
  325. (!distinguishable_p(p.z, b.z, POS_EPS))) ||
  326. ((!distinguishable_p(p.x, c.x, POS_EPS)) &&
  327. (!distinguishable_p(p.y, c.y, POS_EPS)) &&
  328. (!distinguishable_p(p.z, c.z, POS_EPS)))) {
  329. return 1;
  330. }
  331. return 0;
  332. }
  333. /*******************************************************************
  334. cross2D:
  335. In: 2D vectors a and b
  336. Out: 2D pseudo cross product Dot(Perp(a0,b)
  337. Note: The code adapted from "Real-Time Collision Detection" by
  338. Christer Ericson, p.205
  339. *******************************************************************/
  340. static pos_t cross2D(const Vec2& a, const Vec2& b) {
  341. return ((a.v) * (b.u) - (a.u) * (b.v));
  342. }
  343. /*********************************************************************
  344. point_in_triangle_2D:
  345. In: point p
  346. triangle defined by vertices a, b, c
  347. Out: Returns 1 if point p is inside the above defined triangle,
  348. and 0 otherwise.
  349. Note: The code adapted from "Real-Time Collision Detection" by
  350. Christer Ericson, p.206
  351. ***********************************************************************/
  352. static bool point_in_triangle_2D(const Vec2& p, const Vec2& a,
  353. const Vec2& b, const Vec2& c) {
  354. pos_t pab, pbc, pca;
  355. pab = cross2D(p - a, b - a);
  356. pbc = cross2D(p - b, c - b);
  357. /* if P left of one of AB and BC and right of the other, not inside triangle
  358. - (pab and pbc have different signs */
  359. if (((pab > 0) && (pbc < 0)) || ((pab < 0) && (pbc > 0))) {
  360. return false;
  361. }
  362. pca = cross2D(p - c, a - c);
  363. /* if P left of one of AB and CA and right of the other, not inside triangle
  364. * - pab and pca have different signs */
  365. if (((pab > 0) && (pca < 0)) || ((pab < 0) && (pca > 0))) {
  366. return false;
  367. }
  368. /* if P left or right of all edges, so must be in (or on) the triangle */
  369. return true;
  370. }
  371. /***************************************************************************
  372. closest_pt_point_triangle:
  373. In: p - point
  374. a,b,c - vectors defining the vertices of the triangle.
  375. Out: final_result - closest point on triangle ABC to a point p.
  376. The code is adapted from "Real-time Collision Detection" by Christer
  377. Ericson, ISBN 1-55860-732-3, p.141.
  378. ***************************************************************************/
  379. static void closest_pt_point_triangle(
  380. const Vec3& p, const Vec3& a,
  381. const Vec3& b, const Vec3& c,
  382. Vec3& final_result
  383. ) {
  384. /* Check if P in vertex region outside A */
  385. Vec3 ab, ac, ap;
  386. ab = b - a;
  387. ac = c - a;
  388. ap = p - a;
  389. pos_t d1, d2;
  390. d1 = dot(ab, ap);
  391. d2 = dot(ac, ap);
  392. if (d1 <= 0 && d2 <= 0) {
  393. final_result = a;
  394. return;
  395. }
  396. /* Check if P in vertex region outside B */
  397. Vec3 bp = p - b;
  398. pos_t d3, d4;
  399. d3 = dot(ab, bp);
  400. d4 = dot(ac, bp);
  401. if (d3 >= 0 && d4 <= d3) {
  402. final_result = b;
  403. return;
  404. }
  405. /* Check if P in edge region of AB, if so return projection of P onto AB */
  406. pos_t v, w;
  407. Vec3 result1;
  408. pos_t vc = d1 * d4 - d3 * d2;
  409. if (vc <= 0 && d1 >= 0 && d3 <= 0) {
  410. v = d1 / (d1 - d3);
  411. result1 = ab * Vec3(v);
  412. final_result = a + result1;
  413. return; /* barycentric coordinates (1-v,v,0) */
  414. }
  415. /* Check if P in vertex region outside C */
  416. Vec3 cp = p - c;
  417. pos_t d5, d6;
  418. d5 = dot(ab, cp);
  419. d6 = dot(ac, cp);
  420. if (d6 >= 0 && d5 <= d6) {
  421. final_result = c;
  422. return;
  423. }
  424. /* Check if P in edge region of AC, if so return projection of P onto AC */
  425. pos_t vb = d5 * d2 - d1 * d6;
  426. if (vb <= 0 && d2 >= 0 && d6 <= 0) {
  427. w = d2 / (d2 - d6);
  428. result1 = ac * Vec3(w);
  429. final_result = a + result1;
  430. return; /* barycentric coordinates (0, 1-w,w) */
  431. }
  432. /* Check if P in edge region of BC, if so return projection of P onto BC */
  433. pos_t va = d3 * d6 - d5 * d4;
  434. if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) {
  435. w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
  436. result1 = (c - b) * Vec3(w);
  437. final_result = b + result1;
  438. return; /*barycentric coordinates (0,1-w, w) */
  439. }
  440. /* P inside face region. Compute Q through its barycentric
  441. coordinates (u,v,w) */
  442. pos_t denom = 1 / (va + vb + vc);
  443. v = vb * denom;
  444. w = vc * denom;
  445. ab = ab * Vec3(v);
  446. ac = ac * Vec3(w);
  447. result1 = ab + ac;
  448. final_result = a + result1;
  449. return; /* = u*a + v*b + w*c, u = va * denom = 1 - v -w */
  450. }
  451. /***************************************************************************
  452. closest_interior_point:
  453. In: a point in 3D
  454. a wall
  455. the surface coordinates of the closest interior point on the wall
  456. how far away the point can be before we give up
  457. Out: return the distance^2 between the input point and closest point.
  458. Sets closest interior point.
  459. Note: the search distance currently isn't used. This function is just
  460. a wrapper for closest_pt_point_triangle. If the closest point is
  461. on an edge or corner, we scoot the point towards the centroid of
  462. the triangle so we're contained fully within the triangle.
  463. ***************************************************************************/
  464. static pos_t closest_interior_point(
  465. const Partition& p,
  466. const Vec3& pt,
  467. const Wall& w,
  468. Vec2& ip) {
  469. #ifdef DEBUG_CLOSEST_INTERIOR_POINT
  470. std::cout << "closest_interior_point: " << pt << "\n";;
  471. w.dump(p, "", true);
  472. #endif
  473. Vec3 v;
  474. const Vec3& w_vert0 = p.get_wall_vertex(w, 0);
  475. const Vec3& w_vert1 = p.get_wall_vertex(w, 1);
  476. const Vec3& w_vert2 = p.get_wall_vertex(w, 2);
  477. closest_pt_point_triangle(pt, w_vert0, w_vert1, w_vert2, v);
  478. ip = xyz2uv(p, v, w);
  479. /* Check to see if we're lying on an edge; if so, scoot towards centroid. */
  480. /* ip lies on edge of wall if cross products are zero */
  481. int give_up_ctr = 0;
  482. int give_up = 10;
  483. pos_t a1 = ip.u * w.uv_vert2.v - ip.v * w.uv_vert2.u;
  484. pos_t a2 = w.uv_vert1_u * ip.v;
  485. Vec2 vert_0(0);
  486. Vec2 vert_1(w.uv_vert1_u, 0);
  487. while (
  488. give_up_ctr < give_up
  489. && (!distinguishable_p(ip.v, 0, POS_EPS) ||
  490. !distinguishable_p(a1, 0, POS_EPS) ||
  491. !distinguishable_p(a1 + a2, 2 * w.area, POS_EPS) ||
  492. !point_in_triangle_2D(ip, vert_0, vert_1, w.uv_vert2))
  493. ) {
  494. /* Move toward centroid. It's possible for this movement to be so small
  495. * that we are essentially stuck in this loop, so bail out after a set
  496. * number of tries. The number chosen is somewhat arbitrary. In most cases,
  497. * one try is sufficent. */
  498. ip.u = (1 - 5 * POS_EPS) * ip.u +
  499. 5 * POS_EPS * 0.333333333333333 * (w.uv_vert1_u + w.uv_vert2.u);
  500. ip.v = (1 - 5 * POS_EPS) * ip.v +
  501. 5 * POS_EPS * 0.333333333333333 * w.uv_vert2.v;
  502. a1 = ip.u * w.uv_vert2.v - ip.v * w.uv_vert2.u;
  503. a2 = w.uv_vert1_u * ip.v;
  504. give_up_ctr++;
  505. }
  506. pos_t res = len3_squared(v - pt);
  507. #ifdef DEBUG_CLOSEST_INTERIOR_POINT
  508. std::cout << "res: " << res << ", ip: " << ip << "\n";
  509. #endif
  510. return res;
  511. }
  512. static bool is_point_above_plane_defined_by_wall(const Partition& p, const Wall& w, const Vec3& pos) {
  513. // make vector pointing from any point to our position
  514. Vec3 w0_pos = pos - p.get_wall_vertex(w, 0);
  515. // dot product with normal gives ||a|| * ||b|| * cos(phi)
  516. pos_t dot_prod = dot(w0_pos, w.normal);
  517. assert(!cmp_eq(dot_prod, (pos_t)0.0, POS_EPS) && "Checked point is on the plane");
  518. return dot_prod > 0;
  519. }
  520. } // namespace GeometryUtil
  521. } // namespace MCell
  522. #endif // SRC4_GEOMETRY_UTILS_INC_