Flow123d  release_2.2.0-914-gf1a3a4f
compute_intersection.cc
Go to the documentation of this file.
1 /*
2  * Author: viktor
3  */
4 
6 #include "mesh/ref_element.hh"
7 #include "mesh/mesh.h"
8 #include "system/system.hh"
9 
10 #include "plucker.hh"
12 #include "intersection_aux.hh"
13 
14 using namespace std;
15 
16 
17 /*************************************************************************************************************
18  * COMPUTE INTERSECTION FOR: 1D AND 2D
19  ************************************************************************************************************/
21 : computed_(false), abscissa_(nullptr), triangle_(nullptr)
22 {
23  plucker_coordinates_abscissa_ = nullptr;
24  plucker_coordinates_triangle_.resize(3, nullptr);
25  plucker_products_.resize(3, nullptr);
26 };
27 
29  Simplex< 2 >& triangle, Mesh *mesh)
30 : computed_(false), abscissa_(&abscissa), triangle_(&triangle)
31 {
32  // in this constructor, we suppose this is the final object -> we create all data members
33  plucker_coordinates_abscissa_ = new Plucker((*abscissa_)[0].point_coordinates(),
34  (*abscissa_)[1].point_coordinates());
35 
36  plucker_coordinates_triangle_.resize(3);
37  plucker_products_.resize(3);
38  for(unsigned int side = 0; side < 3; side++){
39  plucker_coordinates_triangle_[side] = new Plucker((*triangle_)[side][0].point_coordinates(),
40  (*triangle_)[side][1].point_coordinates());
41  // allocate and compute new Plucker products
42  plucker_products_[side] = new double((*plucker_coordinates_abscissa_)*(*plucker_coordinates_triangle_[side]));
43  }
44 };
45 
47 {
48  if(plucker_coordinates_abscissa_ != nullptr)
49  delete plucker_coordinates_abscissa_;
50 
51  for(unsigned int side = 0; side < RefElement<2>::n_sides; side++){
52  if(plucker_products_[side] != nullptr)
53  delete plucker_products_[side];
54  if(plucker_coordinates_triangle_[side] != nullptr)
55  delete plucker_coordinates_triangle_[side];
56  }
57 }
58 
59 
61  // unset all pointers
62  for(unsigned int side = 0; side < RefElement<2>::n_sides; side++)
63  {
64  plucker_products_[side] = nullptr;
65  plucker_coordinates_triangle_[side] = nullptr;
66  }
67  plucker_coordinates_abscissa_ = nullptr;
68 };
69 
70 void ComputeIntersection<Simplex<1>, Simplex<2>>::compute_plucker_products(){
71 
72  // if not already computed, compute plucker coordinates of abscissa
73  if(!plucker_coordinates_abscissa_->is_computed()){
74  plucker_coordinates_abscissa_->compute((*abscissa_)[0].point_coordinates(),
75  (*abscissa_)[1].point_coordinates());
76  }
77  scale_line_=plucker_coordinates_abscissa_->scale();
78 
79 // DBGMSG("Abscissa:\n");
80 // (*abscissa_)[0].point_coordinates().print();
81 // (*abscissa_)[1].point_coordinates().print();
82  scale_triangle_=std::numeric_limits<double>::max();
83  // if not already computed, compute plucker coordinates of triangle sides
84  for(unsigned int side = 0; side < RefElement<2>::n_sides; side++){
85  if(!plucker_coordinates_triangle_[side]->is_computed()){
86  plucker_coordinates_triangle_[side]->compute((*triangle_)[side][0].point_coordinates(),
87  (*triangle_)[side][1].point_coordinates());
88  }
89  scale_triangle_ = std::min( scale_triangle_, plucker_coordinates_triangle_[side]->scale());
90 
91  ASSERT_DBG(plucker_products_[side]).error("Undefined plucker product.");
92  if(*plucker_products_[side] == plucker_empty){
93  *plucker_products_[side] = (*plucker_coordinates_abscissa_)*(*plucker_coordinates_triangle_[side]);
94  }
95 // DBGMSG("Plucker product = %e\n", *(plucker_products_[side]));
96  }
97 };
98 
100  Simplex< 2 >& triangle){
101  computed_ = false;
102  abscissa_ = &abscissa;
103  triangle_ = &triangle;
104  clear_all();
105 };
106 
108 {
109  // compute local barycentric coordinates of IP: see formula (3) on pg. 12 in BP VF
110  // local alfa = w2/sum; local beta = w1/sum; => local barycentric coordinates in the triangle
111  // where sum = w0+w1+w2
112 
113  // plucker products with correct signs according to ref_element, ordered by sides
114 // double w[3] = {signed_plucker_product(0),
115 // signed_plucker_product(1),
116 // signed_plucker_product(2)};
117 
118  // local barycentric coordinates of IP, depends on barycentric coordinates order !!!
119 // arma::vec3 local_triangle({w[2],w[1],w[0]});
120 // DBGMSG("Plucker product sum = %f\n",w[0]+w[1]+w[2]);
121 // local_triangle = local_triangle / (w[0]+w[1]+w[2]);
122 // double w_sum = local[0] + local[1] + local[2];
123 // DBGMSG("Plucker product sum = %e %e %e\n",w_sum, 1-rounding_epsilonX, 1+rounding_epsilonX);
124 
125  //assert inaccurate barycentric coordinates
126  ASSERT_DBG(fabs(1.0 - local[0] - local[1] - local[2]) < rounding_epsilon)(local[0]+local[1]+local[2])
127  (local[0])(local[1])(local[2]);
128 
129 
130 
131  arma::vec3 local_triangle({local[2],local[1],local[0]});
132 
133  // local coordinate T on the line
134  // for i-th coordinate it holds: (from formula (4) on pg. 12 in BP VF)
135  // T = localAbscissa= (- A(i) + ( 1 - alfa - beta ) * V0(i) + alfa * V1(i) + beta * V2 (i)) / U(i)
136  // let's choose [max,i] = max {U(i)}
137  arma::vec3 u = (*abscissa_)[1].point_coordinates() - (*abscissa_)[0].point_coordinates();
138 
139  //find max in u in abs value:
140  unsigned int i = 0; // index of maximum in u
141  double max = u[0]; // maximum in u
142  if(fabs((double)u[1]) > fabs(max)){ max = u[1]; i = 1;}
143  if(fabs((double)u[2]) > fabs(max)){ max = u[2]; i = 2;}
144 
145  // global coordinates in triangle
146  double isect_coord_i =
147  local_triangle[0]*(*triangle_)[0][0].point_coordinates()[i] +
148  local_triangle[1]*(*triangle_)[0][1].point_coordinates()[i] +
149  local_triangle[2]*(*triangle_)[1][1].point_coordinates()[i];
150 
151  //theta on abscissa
152  //DebugOut() << "lineA: " << (*abscissa_)[0].point_coordinates();
153  //DebugOut() << "lineB: " << (*abscissa_)[1].point_coordinates();
154  double t = (-(*abscissa_)[0].point_coordinates()[i] + isect_coord_i)/max;
155  //DebugOut() << print_var(t) << print_var(isect_coord_i) << print_var(max);
156 
157  /*
158  DBGMSG("Coordinates: line; local and global triangle\n");
159  theta.print();
160  local_triangle.print();
161  global_triangle.print();
162  */
163  IP.set_topology_B(0, 2);
164 
165 
166  // possibly set abscissa vertex {0,1}
167  if( fabs(t) <= rounding_epsilon) { t = 0; IP.set_topology_A(0,0);}
168  else if(fabs(1-t) <= rounding_epsilon) { t = 1; IP.set_topology_A(1,0);}
169  else { IP.set_topology_A(0,1);} // no vertex, line 0, dim = 1
170 // // possibly set abscissa vertex {0,1}
171 // if( fabs(t) <= geometry_epsilon) { t = 0; IP.set_topology_A(0,0);}
172 // else if(fabs(1-t) <= geometry_epsilon) { t = 1; IP.set_topology_A(1,0);}
173 // else { IP.set_topology_A(0,1);} // no vertex, line 0, dim = 1
174 
175  arma::vec2 local_abscissa = {1-t, t};
176 
177  IP.set_coordinates(local_abscissa,local_triangle);
178  return true;
179 }
180 
181 bool ComputeIntersection<Simplex<1>,Simplex<2>>::compute_degenerate(unsigned int side,
183 {
184 // DBGMSG("PluckerProduct[%d]: %f\n",side, *plucker_products_[side]);
185 
186  // We solve following equation for parameters s,t:
187  /* A + sU = C + tV = intersection point
188  * sU - tV = C - A
189  *
190  * which is by components:
191  * (u1 -v1) (s) = (c1-a1)
192  * (u2 -v2) (t) = (c2-a2)
193  * (u3 -v3) = (c3-a3)
194  *
195  * these are 3 equations for variables s,t
196  * see (4.3) on pg. 19 in DP VF
197  *
198  * We will solve this using Crammer's rule for the maximal subdeterminant det_ij of the matrix.
199  * s = detX_ij / det_ij
200  * t = detY_ij / det_ij
201  */
202 
203  // starting point of abscissa
204  arma::vec3 A = (*abscissa_)[0].point_coordinates();
205  // direction vector of abscissa
206  arma::vec3 U = plucker_coordinates_abscissa_->get_u_vector();
207  // vertex of triangle side
208  arma::vec3 C = (*triangle_)[side][side%2].point_coordinates();
209  // direction vector of triangle side
210  arma::vec3 V = plucker_coordinates_triangle_[side]->get_u_vector();
211  // right hand side
212  arma::vec3 K = C - A;
213  // subdeterminants det_ij of the system equal minus normal vector to common plane of U and V
214  // det_12 = (-UxV)[1]
215  // det_13 = -(-UxV)[2]
216  // det_23 = (-UxV)[3]
217  arma::vec3 Det = -arma::cross(U,V);
218 
219 
220 // A.print("A");
221 // U.print("U");
222 // C.print("C");
223 // V.print("V");
224 // K.print("K");
225 // Det.print();
226 // cout <<endl;
227 
228  unsigned int max_index = 0;
229  double maximum = fabs(Det[0]);
230  if(fabs((double)Det[1]) > maximum){
231  maximum = fabs(Det[1]);
232  max_index = 1;
233  }
234  if(fabs((double)Det[2]) > maximum){
235  maximum = fabs(Det[2]);
236  max_index = 2;
237  }
238 // DBGVAR(maximum);
239  //abscissa is parallel to triangle side
240  if(std::abs(maximum) <= std::sqrt(rounding_epsilon)) return false;
241 
242  // map maximum index in {-UxV} to i,j of subdeterminants
243  // i j
244  // max_index 0: 1 2
245  // 1: 2 0 (switch due to sign change)
246  // 2: 0 1
247  unsigned int i = (max_index+1)%3,
248  j = (max_index+2)%3;
249 
250  double DetX = -K[i]*V[j] + K[j]*V[i];
251  double DetY = -K[i]*U[j] + K[j]*U[i];
252 
253  double s = DetX/Det[max_index]; //parameter on abscissa
254  double t = DetY/Det[max_index]; //parameter on triangle side
255 
256  // change sign according to side orientation
257  if(RefElement<2>::normal_orientation(side)) t=-t;
258 
259 // DBGVAR(s);
260 // DBGVAR(t);
261 
262  // if IP is inside of triangle side
263  if(t >= -geometry_epsilon && t <= 1+geometry_epsilon){
264 
265  IP.set_orientation(IntersectionResult::degenerate); // set orientation as a pathologic case ( > 1)
266  // possibly set abscissa vertex {0,1}
267  if( fabs(s) <= geometry_epsilon) { s = 0; IP.set_topology_A(0,0);}
268  else if(fabs(1-s) <= geometry_epsilon) { s = 1; IP.set_topology_A(1,0);}
269  else { IP.set_topology_A(0,1);} // no vertex, line 0, dim = 1
270 
271  // possibly set triangle vertex {0,1,2}
274  else { IP.set_topology_B(side,1);} // no vertex, side side, dim = 1
275 
276  arma::vec2 local_abscissa({1-s, s});
277  arma::vec3 local_triangle({0,0,0});
278 
279  // set local triangle barycentric coordinates according to nodes of the triangle side:
280  local_triangle[RefElement<2>::interact(Interaction<0,1>(side))[RefElement<2>::normal_orientation(side)]] = 1 - t;
282 // local_abscissa.print();
283 // local_triangle.print();
284 
285  IP.set_coordinates(local_abscissa,local_triangle);
286  return true; // IP found
287  }
288 
289  return false; // IP NOT found
290 }
291 
292 
294 {
295  ASSERT_EQ_DBG(0, IP12s.size());
296  compute_plucker_products();
297  computed_ = true;
298 
299  //DebugOut() << "LINE: \n" << (*abscissa_)[0].point_coordinates()
300  // << (*abscissa_)[1].point_coordinates();
301 
302 
303  // convert plucker products to local coords
304  arma::vec3 w = {signed_plucker_product(0),
305  signed_plucker_product(1),
306  signed_plucker_product(2)};
307  double w_sum = w[0] + w[1] + w[2];
308 
309  unsigned int n_positive = 0;
310  unsigned int n_negative = 0;
311  unsigned int zero_idx_sum =0;
312  //DebugOut() << print_var(std::fabs(w_sum));
313  //DebugOut() << print_var(scale_line_);
314  //DebugOut() << print_var(scale_triangle_);
315 
316  double scaled_epsilon = rounding_epsilon*scale_line_*scale_triangle_*scale_triangle_;
317  if(std::fabs(w_sum) > scaled_epsilon) {
318  w = w / w_sum;
319  for (unsigned int i=0; i < 3; i++) {
320  //DebugOut() << print_var(i) << print_var(w[i]);
321  if (w[i] > rounding_epsilon) n_positive++;
322  else if ( w[i] > -rounding_epsilon) zero_idx_sum+=i;
323  else n_negative++;
324  }
325 
326  } else {
327  /* case 'w_sum == 0':
328  * 1] all products are zero => n_negative=0 and n_positive=0 => it is degenerate case (coplanar case)
329  * 2] at least two products are nonzero AND some of them must be negative => no intersection
330  * (it happens when line is parallel with the triangle but not coplanar; unit test line_triangle09.msh)
331  * See the IF conditions below.
332  */
333 
334  for (unsigned int i=0; i < 3; i++) {
335  //DebugOut().fmt("i: {} w[i]: {:g}", i, w[i]);
336  if (w[i] > scaled_epsilon || w[i] < -scaled_epsilon) n_negative++;
337  }
338  // n_positive == 0
339  //DebugOut() << print_var(n_negative);
340  }
341 
342 // w.print("w");
343 
344  // any negative barycentric coordinate means, no intersection
345  if (n_negative>0) return IntersectionResult::none;
346 
347  // test whether any plucker products is non-zero
348  if (n_positive > 0) {
350 
351  compute_plucker(IP, w);
352  // edge of triangle
353  unsigned int non_zero_idx=0;
354  if (n_positive == 2) {
355  // one zero product, intersection on the zero edge
356  // the zero edge index is equal to zero_idx_sum
357  IP.set_topology_B(zero_idx_sum, 1);
358  non_zero_idx = (zero_idx_sum + 1) % 3;
359  }
360  else if (n_positive == 1) {
361  // two zero products, intersection in vertex oposite to single non-zero edge
362  // index of the non-zero edge is 3-zero_idx_sum
363  IP.set_topology_B(RefElement<2>::oposite_node(3-zero_idx_sum), 0);
364  non_zero_idx = 3-zero_idx_sum;
365  }
366  //DebugOut() << print_var(non_zero_idx) << print_var(signed_plucker_product(non_zero_idx));
367 
368  IntersectionResult result = signed_plucker_product(non_zero_idx) > 0 ?
370  IP.set_orientation(result);
371 
372  IP12s.push_back(IP);
373  return result;
374 
375  } else {
377  }
378 };
379 
381 {
382  IntersectionResult result = compute(IP12s);
383 // DBGVAR((int)result);
384  // skip empty cases
385  if(result == IntersectionResult::none) return 0;
386 
387  // standard case with a single intersection corner
388  if(result < IntersectionResult::degenerate){
389 // DBGCOUT(<< "12d plucker case\n");
390  ASSERT_EQ_DBG(1, IP12s.size());
391  IntersectionPointAux<1,2> &IP = IP12s.back();
392 
393  // check the IP whether it is on abscissa
394  arma::vec2 theta;
395  double t = IP.local_bcoords_A()[1];
396  // t is already checked for vertex position with tolerance in compute_plucker
397  if(t < 0 || t > 1) {
398 // DBGCOUT(<< "remove IP\n");
399  IP12s.pop_back(); // IP outside => remove
400  }
401  return IP12s.size();
402  }
403  else{
405 
406 // DBGCOUT(<< "12d degenerate case, all products are zero\n");
407 
408  // 3 zero products: abscissa and triangle are coplanar
409  for(unsigned int i = 0; i < 3;i++){
410 // DBGCOUT( << "side [" << i << "]\n");
412  if (compute_degenerate(i,IP))
413  {
414  double t = IP.local_bcoords_A()[1];
415  double tol = rounding_epsilon*scale_line_;
416  if(t >= -tol && t <= 1+tol)
417  {
418  if(IP12s.size() > 0)
419  {
420  // if the IP has been found already
421  if(IP12s.back().local_bcoords_A()[1] == t)
422  continue;
423 
424  // sort the IPs in the direction of the abscissa
425  if(IP12s.back().local_bcoords_A()[1] > t)
426  std::swap(IP12s.back(),IP);
427  }
428  IP12s.push_back(IP);
429  }
430  }
431  }
432  return IP12s.size();
433  }
434 }
435 
436 
437 void ComputeIntersection<Simplex<1>, Simplex<2>>::print_plucker_coordinates(std::ostream &os){
438  os << "\tPluckerCoordinates Abscissa[0]";
439  if(plucker_coordinates_abscissa_ == nullptr){
440  os << "NULL" << endl;
441  }else{
442  os << plucker_coordinates_abscissa_;
443  }
444  for(unsigned int i = 0; i < 3;i++){
445  os << "\tPluckerCoordinates Triangle[" << i << "]";
446  if(plucker_coordinates_triangle_[i] == nullptr){
447  os << "NULL" << endl;
448  }else{
449  os << plucker_coordinates_triangle_[i];
450  }
451  }
452 };
453 
454 
455 
456 
457 /*************************************************************************************************************
458  * COMPUTE INTERSECTION FOR: 2D AND 2D
459  ************************************************************************************************************/
461 {
462  plucker_coordinates_.resize(2*RefElement<2>::n_sides, nullptr);
463  plucker_products_.resize(3*RefElement<2>::n_sides, nullptr);
464 };
465 
467  Simplex< 2 >& triaB, Mesh *mesh)
468 {
469  plucker_coordinates_.resize(2*RefElement<2>::n_sides);
470  plucker_products_.resize(3*RefElement<2>::n_sides);
471 
472  for(unsigned int side = 0; side < 2*RefElement<2>::n_sides; side++){
473  plucker_coordinates_[side] = new Plucker();
474  }
475 
476  // compute Plucker products for each pair triangle A side and triangle B side
477  for(unsigned int p = 0; p < 3*RefElement<2>::n_sides; p++){
478  plucker_products_[p] = new double(plucker_empty);
479  }
480 
481  set_data(triaA, triaB);
482 };
483 
485 {
486  // unset pointers:
487  for(unsigned int side = 0; side < 2*RefElement<2>::n_sides; side++)
488  CI12[side].clear_all();
489 
490  // then delete objects:
491  for(unsigned int side = 0; side < 2*RefElement<2>::n_sides; side++){
492  if(plucker_coordinates_[side] != nullptr)
493  delete plucker_coordinates_[side];
494  }
495 
496  for(unsigned int p = 0; p < 3*RefElement<2>::n_sides; p++){
497  if(plucker_products_[p] != nullptr)
498  delete plucker_products_[p];
499  }
500 }
501 
503 {
504  // unset all pointers
505  for(unsigned int side = 0; side < 2*RefElement<2>::n_sides; side++)
506  {
507  plucker_coordinates_[side] = nullptr;
508  }
509  for(unsigned int p = 0; p < 3*RefElement<2>::n_sides; p++){
510  plucker_products_[p] = nullptr;
511  }
512 }
513 
515 
516 // DBGMSG("init\n");
517  for(unsigned int i = 0; i < RefElement<2>::n_sides; i++){
518  // set side A vs triangle B
519  for(unsigned int j = 0; j < RefElement<2>::n_sides; j++)
520  CI12[i].set_pc_triangle(plucker_coordinates_[3+j], j); // set triangle B
521  // set side of triangle A
522  CI12[i].set_pc_abscissa(plucker_coordinates_[i]);
523 
524  // set side B vs triangle A
525  for(unsigned int j = 0; j < RefElement<2>::n_sides; j++)
526  CI12[RefElement<2>::n_sides + i].set_pc_triangle(plucker_coordinates_[j], j); // set triangle A
527  // set side of triangle B
528  CI12[RefElement<2>::n_sides + i].set_pc_abscissa(plucker_coordinates_[RefElement<2>::n_sides + i]);
529 
530  // set plucker products
531  for(unsigned int j = 0; j < RefElement<2>::n_sides; j++)
532  {
533  //for A[i]_B set pp. A[i] x B[j]
534  CI12[i].set_plucker_product(get_plucker_product(i,j),j);
535  //for B[i]_A set pp. A[j] x B[i]
536  CI12[RefElement<2>::n_sides + i].set_plucker_product(get_plucker_product(j,i),j);
537  }
538 
539  }
540 };
541 
543  Simplex< 2 >& triaB){
544  for(unsigned int i = 0; i < RefElement< 2 >::n_sides;i++){
545  // A[i]_B
546  CI12[i].set_data(triaA.abscissa(i), triaB);
547  // B[i]_A
548  CI12[RefElement<2>::n_sides + i].set_data(triaB.abscissa(i), triaA);
549  }
550 };
551 
553 {
554  // final intersection points
555  std::vector<IntersectionPointAux<2,2>> &IP22s = intersection.points();
556  // temporary vector for lower dimensional IPs
558  IP12s.reserve(2);
559  unsigned int ip_coutner = 0;
560 
561  // loop over CIs (side vs triangle): [A0_B, A1_B, A2_B, B0_A, B1_A, B2_A].
562  for(unsigned int i = 0; i < 2*RefElement<2>::n_sides && ip_coutner < 2; i++){
563  if(!CI12[i].is_computed()) // if not computed yet
564  {
565 // DBGVAR(i);
566  if(CI12[i].compute_final(IP12s) == 0) continue;
567 
568  unsigned int triangle_side = i%3; //i goes from 0 to 5 -> i%3 = 0,1,2,0,1,2
569 
570  for(IntersectionPointAux<1,2> &IP : IP12s)
571  {
572  IntersectionPointAux<2,1> IP21 = IP.switch_objects(); // swicth dim 12 -> 21
573  IntersectionPointAux<2,2> IP22(IP21, triangle_side); // interpolate dim 21 -> 22
574 
575  if(i < 3){
576  //switch back to keep order of triangles [A,B]
577  IP22 = IP22.switch_objects();
578 
579  if( IP.dim_A() == 0 ) // if IP is vertex of triangle
580  {
581 // DBGCOUT("set_node A\n");
582  // we are on line of the triangle A, and IP.idx_A contains local node of the line
583  // we know vertex index
584  unsigned int node = RefElement<2>::interact(Interaction<0,1>(triangle_side))[IP.idx_A()];
585  IP22.set_topology_A(node, 0);
586 
587  // set flag on all sides of tetrahedron connected by the node
588  for(unsigned int s=0; s < RefElement<2>::n_sides_per_node; s++)
589  CI12[RefElement<2>::interact(Interaction<1,0>(node))[s]].set_computed();
590  }
591  if( IP.dim_B() == 0 ) // if IP is vertex of triangle
592  {
593 // DBGCOUT("set_node B\n");
594  // set flag on both sides of triangle connected by the node
595  for(unsigned int s=0; s < RefElement<2>::n_sides_per_node; s++)
596  CI12[3 + RefElement<2>::interact(Interaction<1,0>(IP.idx_B()))[s]].set_computed();
597  }
598  else if( IP.dim_B() == 1 ) // if IP is vertex of triangle
599  {
600 // DBGCOUT("set line B\n");
601  // set flag on both sides of triangle connected by the node
602  CI12[3 + IP.idx_B()].set_computed();
603  }
604  }
605  else if( IP.dim_A() == 0 ) // if IP is vertex of triangle B (triangles switched!!! A <-> B)
606  {
607  //we do not need to look back to triangle A, because if IP was at vertex, we would know already
608 // DBGCOUT("set_node B\n");
609  // we are on line of the triangle, and IP.idx_A contains local node of the line
610  // we know vertex index
611  unsigned int node = RefElement<2>::interact(Interaction<0,1>(triangle_side))[IP.idx_A()];
612  IP22.set_topology_B(node, 0);
613 
614  // set flag on both sides of triangle connected by the node
615  for(unsigned int s=0; s < RefElement<2>::n_sides_per_node; s++)
616  CI12[3 + RefElement<2>::interact(Interaction<1,0>(node))[s]].set_computed();
617  }
618 // DBGCOUT( << IP22);
619  ip_coutner++;
620  IP22s.push_back(IP22);
621  }
622  IP12s.clear();
623  }
624  }
625 
626  return ip_coutner;
627 };
628 
629 // void ComputeIntersection< Simplex<2>, Simplex<2>>::correct_triangle_ip_topology(IntersectionPointAux<2,2>& ip)
630 // {
631 // // create mask for zeros in barycentric coordinates
632 // // coords (*,*,*,*) -> byte bitwise xxxx
633 // // only least significant one byte used from the integer
634 // unsigned int zeros = 0;
635 // unsigned int n_zeros = 0;
636 // for(char i=0; i < 3; i++){
637 // if(std::fabs(ip.local_bcoords_B()[i]) < geometry_epsilon)
638 // {
639 // zeros = zeros | (1 << (2-i));
640 // n_zeros++;
641 // }
642 // }
643 //
644 // switch(n_zeros)
645 // {
646 // default: ip.set_topology_B(0,2); //inside triangle
647 // break;
648 // case 1: ip.set_topology_B(RefElement<2>::topology_idx<1>(zeros),2);
649 // break;
650 // case 2: ip.set_topology_B(RefElement<2>::topology_idx<0>(zeros),1);
651 // break;
652 // }
653 // };
654 
655 
656 void ComputeIntersection<Simplex<2>, Simplex<2>>::print_plucker_coordinates(std::ostream &os){
657 
658  for(unsigned int i = 0; i < RefElement<2>::n_lines; i++){
659  os << "\tPluckerCoordinates Triangle A[" << i << "]";
660  if(plucker_coordinates_[i] == nullptr){
661  os << "NULL" << endl;
662  }else{
663  os << plucker_coordinates_[i];
664  }
665  }
666  for(unsigned int i = 0; i < RefElement<2>::n_lines; i++){
667  os << "\tPluckerCoordinates Triangle B[" << i << "]";
668  if(plucker_coordinates_[RefElement<2>::n_lines + i] == nullptr){
669  os << "NULL" << endl;
670  }else{
671  os << plucker_coordinates_[RefElement<2>::n_lines + i];
672  }
673  }
674 };
675 
676 void ComputeIntersection<Simplex<2>, Simplex<2>>::print_plucker_coordinates_tree(std::ostream &os){
677  os << "ComputeIntersection<Simplex<2>, <Simplex<2>> Plucker Coordinates Tree:" << endl;
678  print_plucker_coordinates(os);
679  for(unsigned int i = 0; i < 6;i++){
680  os << "ComputeIntersection<Simplex<1>, Simplex<2>>["<< i <<"] Plucker Coordinates:" << endl;
681  CI12[i].print_plucker_coordinates(os);
682  }
683 };
684 
685 
686 /*************************************************************************************************************
687  * COMPUTE INTERSECTION FOR: 1D AND 3D
688  ************************************************************************************************************/
690 {
691  plucker_coordinates_abscissa_ = nullptr;
692  plucker_coordinates_tetrahedron.resize(6, nullptr);
693  plucker_products_.resize(6, nullptr);
694 };
695 
697  Simplex< 3 >& tetrahedron, Mesh *mesh)
698 {
699  plucker_coordinates_abscissa_ = new Plucker();
700  plucker_coordinates_tetrahedron.resize(6);
701  plucker_products_.resize(6);
702 
703  for(unsigned int line = 0; line < RefElement<3>::n_lines; line++){
704  plucker_coordinates_tetrahedron[line] = new Plucker();
705  // compute Plucker products (abscissa X tetrahedron line)
706  plucker_products_[line] = new double(plucker_empty);
707  }
708 
709  set_data(abscissa, tetrahedron);
710 };
711 
713 {
714  // unset pointers:
715  for(unsigned int side = 0; side < RefElement<3>::n_sides; side++)
716  CI12[side].clear_all();
717 
718  // then delete objects:
719  if(plucker_coordinates_abscissa_ != nullptr)
720  delete plucker_coordinates_abscissa_;
721 
722  for(unsigned int line = 0; line < RefElement<3>::n_lines; line++){
723  if(plucker_products_[line] != nullptr)
724  delete plucker_products_[line];
725  if(plucker_coordinates_tetrahedron[line] != nullptr)
726  delete plucker_coordinates_tetrahedron[line];
727  }
728 }
729 
731 {
732  // unset all pointers
733  for(unsigned int side = 0; side < RefElement<3>::n_lines; side++)
734  {
735  plucker_products_[side] = nullptr;
736  plucker_coordinates_tetrahedron[side] = nullptr;
737  }
738  plucker_coordinates_abscissa_ = nullptr;
739 }
740 
742 
743  for(unsigned int side = 0; side < RefElement<3>::n_sides; side++){
744  for(unsigned int line = 0; line < RefElement<3>::n_lines_per_side; line++){
745  CI12[side].set_pc_triangle(plucker_coordinates_tetrahedron[
747 
748  CI12[side].set_plucker_product(
749  plucker_products_[RefElement<3>::interact(Interaction<1,2>(side))[line]],
750  line);
751  }
752  CI12[side].set_pc_abscissa(plucker_coordinates_abscissa_);
753  }
754 };
755 
757  Simplex< 3 >& tetrahedron){
758  for(unsigned int i = 0; i < 4;i++){
759  CI12[i].set_data(abscissa, tetrahedron[i]);
760  }
761 };
762 
764 {
765 
766  unsigned int count = compute(intersection.i_points_);
767 
768  // set if pathologic!!
769  /*
770  for(IntersectionPointAux<1,3> &p : intersection.i_points_){
771  if(p.is_pathologic()) intersection.pathologic_ = true;
772  break;
773  }*/
774 
775  return count;
776 
777 }
778 
780 
782  ASSERT_EQ_DBG(0, IP13s.size());
783 
784  // loop over faces of tetrahedron
785  for(unsigned int face = 0; face < RefElement<3>::n_sides && IP13s.size() < 2; face++){
786  IP12s.clear();
787 
788 
789  if (CI12[face].is_computed()) continue;
790  IntersectionResult result = CI12[face].compute(IP12s);
791  //DebugOut() << print_var(face) << print_var(int(result)) << "1d-3d";
792 
793  if (int(result) < int(IntersectionResult::degenerate) ) {
794  ASSERT_EQ_DBG(1, IP12s.size());
795  IntersectionPointAux<1,2> &IP = IP12s.back(); // shortcut
796  IntersectionPointAux<1,3> IP13(IP, face);
797 
798  // set the 'computed' flag on the connected sides by IP
799  if(IP.dim_B() == 0) // IP is vertex of triangle
800  {
801  // map side (triangle) node index to tetrahedron node index
802  unsigned int node = RefElement<3>::interact(Interaction<0,2>(face))[IP.idx_B()];
803  IP13.set_topology_B(node, IP.dim_B());
804  // set flag on all sides of tetrahedron connected by the node
805  for(unsigned int node_face : RefElement<3>::interact(Interaction<2,0>(node)))
806  CI12[node_face].set_computed();
807  // set topology data for object B (tetrahedron) - node
808 
809  }
810  else if(IP.dim_B() == 1) // IP is on edge of triangle
811  {
812  unsigned int edge = RefElement<3>::interact(Interaction<1,2>(face))[IP.idx_B()];
813  IP13.set_topology_B(edge, IP.dim_B());
814  for(unsigned int edge_face : RefElement<3>::interact(Interaction<2,1>(edge)))
815  CI12[edge_face].set_computed();
816  }
817 
818  //DebugOut() << IP13;
819  IP13s.push_back(IP13);
820  }
821  }
822  if (IP13s.size() == 0) return IP13s.size();
823 
824  // in the case, that line goes through vertex, but outside tetrahedron (touching vertex)
825  if(IP13s.size() == 1){
826  double f_theta = IP13s[0].local_bcoords_A()[1];
827  // TODO: move this test to separate function of 12 intersection
828  // no tolerance needed - it was already compared and normalized in 1d-2d
829  if(f_theta > 1 || f_theta < 0){
830  IP13s.pop_back();
831  }
832 
833  } else {
834  ASSERT_EQ_DBG(2, IP13s.size());
835  // order IPs according to the lline parameter
836  if(IP13s[0].local_bcoords_A()[1] > IP13s[1].local_bcoords_A()[1])
837  std::swap(IP13s[0], IP13s[1]);
838  double t[2];
839  int sign[2];
840  int ip_sign[] = {-2, +2}; // states to cut
841  for( unsigned int ip=0; ip<2; ip++) {
842  t[ip] = IP13s[ip].local_bcoords_A()[1];
843 
844  // TODO move this into 12d intersection, possibly with results -2, -1, 0, 1, 2; -1,1 for position on end points
845  sign[ip] = (t[ip] < 0 ? -2 : (t[ip] > 1 ? +2 : 0) );
846  if (t[ip] == 0) sign[ip] = -1;
847  if (t[ip] == 1) sign[ip] = +1;
848 
849  // cut every IP to its end of the line segment
850  if (sign[ip] == ip_sign[ip]) {
851  t[ip]=ip;
852  sign[ip] /=2; // -2 to -1; +2 to +1
853  correct_tetrahedron_ip_topology(t[ip], ip, IP13s);
854  }
855  if (sign[ip] == -1) IP13s[ip].set_topology_A(0, 0);
856  if (sign[ip] == +1) IP13s[ip].set_topology_A(1, 0);
857  }
858 
859  // intersection outside of abscissa => NO intersection
860  if (t[1] < t[0]) {
861  IP13s.clear();
862  return IP13s.size();
863  }
864 
865  // if IPs are the same, then throw the second one away
866  if(t[0] == t[1]) {
867  IP13s.pop_back();
868  }
869  }
870 
871  return IP13s.size();
872 };
873 
874 void ComputeIntersection< Simplex< 1 >, Simplex< 3 > >::correct_tetrahedron_ip_topology(
875  double t, unsigned int ip, std::vector<IPAux> &ips)
876 {
877  arma::vec4 local_tetra = RefElement<3>::line_barycentric_interpolation(
878  ips[0].local_bcoords_B(), ips[1].local_bcoords_B(),
879  ips[0].local_bcoords_A()[1], ips[1].local_bcoords_A()[1], t);
880  arma::vec2 local_abscissa({1 - t, t}); // abscissa local barycentric coords
881  ips[ip].set_coordinates(local_abscissa, local_tetra);
882 
883  // create mask for zeros in barycentric coordinates
884  // coords (*,*,*,*) -> byte bitwise xxxx
885  // only least significant one byte used from the integer
886  unsigned int zeros = 0;
887  unsigned int n_zeros = 0;
888  for(char i=0; i < 4; i++){
889  if(std::fabs(ips[ip].local_bcoords_B()[i]) < geometry_epsilon)
890  {
891  zeros = zeros | (1 << i);
892  n_zeros++;
893  }
894  }
895 
896  /**
897  * TODO:
898  * 1. Try to avoid setting topology from coords. Try to use just topology information.
899  * 2. If can not be done. Use interact method to setup a map mapping 16 possible zeros positions to appropriate topology,
900  * remove topology_idx from RefElement.
901  */
902 
903  switch(n_zeros)
904  {
905  default: ips[ip].set_topology_B(0,3); //inside tetrahedon
906  break;
907  case 1: ips[ip].set_topology_B(RefElement<3>::topology_idx<2>(zeros),2);
908  break;
909  case 2: ips[ip].set_topology_B(RefElement<3>::topology_idx<1>(zeros),1);
910  break;
911  case 3: ips[ip].set_topology_B(RefElement<3>::topology_idx<0>(zeros),0);
912  break;
913  }
914 };
915 
916 
917 void ComputeIntersection<Simplex<1>, Simplex<3>>::print_plucker_coordinates(std::ostream &os){
918  os << "\tPluckerCoordinates Abscissa[0]";
919  if(plucker_coordinates_abscissa_ == nullptr){
920  os << "NULL" << endl;
921  }else{
922  os << plucker_coordinates_abscissa_;
923  }
924 
925  for(unsigned int i = 0; i < 6;i++){
926  os << "\tPluckerCoordinates Tetrahedron[" << i << "]";
927  if(plucker_coordinates_tetrahedron[i] == nullptr){
928  os << "NULL" << endl;
929  }else{
930  os << plucker_coordinates_tetrahedron[i];
931  }
932  }
933 };
934 
935 void ComputeIntersection<Simplex<1>, Simplex<3>>::print_plucker_coordinates_tree(std::ostream &os){
936  os << "ComputeIntersection<Simplex<1>, <Simplex<3>> Plucker Coordinates Tree:" << endl;
937  print_plucker_coordinates(os);
938  for(unsigned int i = 0; i < 4;i++){
939  os << "ComputeIntersection<Simplex<1>, Simplex<2>>["<< i <<"] Plucker Coordinates:" << endl;
940  CI12[i].print_plucker_coordinates(os);
941  }
942 };
943 
944 
945 
946 /*************************************************************************************************************
947  * COMPUTE INTERSECTION FOR: 2D AND 3D
948  ************************************************************************************************************/
950 : no_idx(100),
951 s3_dim_starts({0, 4, 10, 14}), // vertices, edges, faces, volume
952 s2_dim_starts({15, 18, 21}), // vertices, sides, surface
953 object_next(22, no_idx) // 4 vertices, 6 edges, 4 faces, 1 volume, 3 corners, 3 sides, 1 surface; total 22
954  {
955 
956  plucker_coordinates_triangle_.resize(3, nullptr);
957  plucker_coordinates_tetrahedron.resize(6, nullptr);
958  plucker_products_.resize(3*6, nullptr);
959 };
960 
961 
964 {
965  mesh_ = mesh;
966  plucker_coordinates_triangle_.resize(3);
967  plucker_coordinates_tetrahedron.resize(6);
968 
969  // set CI object for 1D-2D intersection 'tetrahedron edge - triangle'
970  for(unsigned int i = 0; i < 6;i++){
971  plucker_coordinates_tetrahedron[i] = new Plucker();
972  CI12[i].set_data(tetrahedron.abscissa(i), triangle);
973  }
974  // set CI object for 1D-3D intersection 'triangle side - tetrahedron'
975  for(unsigned int i = 0; i < 3;i++){
976  plucker_coordinates_triangle_[i] = new Plucker();
977  CI13[i].set_data(triangle.abscissa(i) , tetrahedron);
978  }
979 
980  // compute Plucker products (triangle side X tetrahedron line)
981  // order: triangle sides X tetrahedron lines:
982  // TS[0] X TL[0..6]; TS[1] X TL[0..6]; TS[1] X TL[0..6]
984  plucker_products_.resize(np, nullptr);
985  for(unsigned int line = 0; line < np; line++){
986  plucker_products_[line] = new double(plucker_empty);
987 
988  }
989 };
990 
992 {
993  // unset pointers:
994  for(unsigned int triangle_side = 0; triangle_side < RefElement<2>::n_sides; triangle_side++)
995  CI13[triangle_side].clear_all();
996 
997  for(unsigned int line = 0; line < RefElement<3>::n_lines; line++)
998  CI12[line].clear_all();
999 
1000  // then delete objects:
1001  unsigned int np = RefElement<2>::n_sides * RefElement<3>::n_lines;
1002  for(unsigned int line = 0; line < np; line++){
1003  if(plucker_products_[line] != nullptr)
1004  delete plucker_products_[line];
1005  }
1006 
1007  for(unsigned int i = 0; i < RefElement<3>::n_lines;i++){
1008  if(plucker_coordinates_tetrahedron[i] != nullptr)
1009  delete plucker_coordinates_tetrahedron[i];
1010  }
1011  for(unsigned int i = 0; i < RefElement<2>::n_sides;i++){
1012  if(plucker_coordinates_triangle_[i] != nullptr)
1013  delete plucker_coordinates_triangle_[i];
1014  }
1015 };
1016 
1018 
1019  // set pointers to Plucker coordinates for 1D-2D
1020  // set pointers to Plucker coordinates for 1D-3D
1021  // distribute Plucker products - CI13
1022  for(unsigned int triangle_side = 0; triangle_side < RefElement<2>::n_sides; triangle_side++){
1023  for(unsigned int line = 0; line < RefElement<3>::n_lines; line++){
1024  CI13[triangle_side].set_plucker_product(
1025  plucker_products_[triangle_side * RefElement<3>::n_lines + line],
1026  line);
1027  CI12[line].set_plucker_product(
1028  plucker_products_[triangle_side * RefElement<3>::n_lines + line],
1029  triangle_side);
1030 
1031  CI13[triangle_side].set_pc_tetrahedron(plucker_coordinates_tetrahedron[line],line);
1032  CI12[line].set_pc_triangle(plucker_coordinates_triangle_[triangle_side],triangle_side);
1033  }
1034  CI13[triangle_side].set_pc_abscissa(plucker_coordinates_triangle_[triangle_side]);
1035  CI13[triangle_side].init();
1036  }
1037 
1038  // set pointers to Plucker coordinates for 1D-2D
1039  for(unsigned int line = 0; line < RefElement<3>::n_lines; line++)
1040  CI12[line].set_pc_abscissa(plucker_coordinates_tetrahedron[line]);
1041 
1042 };
1043 
1044 
1045 
1046 bool ComputeIntersection<Simplex<2>, Simplex<3>>::have_backlink(uint i_obj) {
1047  ASSERT_LT_DBG(i_obj, object_next.size());
1048  unsigned int ip = object_next[i_obj];
1049  if (ip == no_idx) return false;
1050  ASSERT_LT_DBG(ip, IP_next.size());
1051  return IP_next[ip] == i_obj;
1052 }
1053 
1054 /**
1055  * Set links: obj_before -> IP -> obj_after
1056  * if obj_after have null successor, set obj_after -> IP (backlink)
1057  */
1058 void ComputeIntersection<Simplex<2>, Simplex<3>>::set_links(uint obj_before_ip, uint ip_idx, uint obj_after_ip) {
1059  if (have_backlink(obj_after_ip)) {
1060  // target object is already target of other IP, so it must be source object
1061  std::swap(obj_before_ip, obj_after_ip);
1062  }
1063  //DebugOut().fmt("before: {} ip: {} after: {}\n", obj_before_ip, ip_idx, obj_after_ip );
1064  ASSERT_DBG( ! have_backlink(obj_after_ip) )
1065  (mesh_->element.get_id(intersection_->component_ele_idx()))
1066  (mesh_->element.get_id(intersection_->bulk_ele_idx()))
1067  (obj_before_ip)(ip_idx)(obj_after_ip); // at least one could be target object
1068  object_next[obj_before_ip] = ip_idx;
1069  IP_next.push_back( obj_after_ip);
1070  if (object_next[obj_after_ip] == no_idx) {
1071  object_next[obj_after_ip] = ip_idx;
1072  }
1073 }
1074 
1075 
1076 
1078 {
1079  intersection_= &intersection;
1080  //DebugOut().fmt("2d ele: {} 3d ele: {}\n",
1081  // intersection.component_ele_idx(),
1082  // intersection.bulk_ele_idx());
1083 
1084  IP23_list.clear();
1085  IP_next.clear();
1086  std::fill(object_next.begin(), object_next.end(), no_idx);
1087  std::vector<IPAux13> IP13s;
1088 
1089  std::array<bool, 6> edge_touch={false,false, false, false, false, false};
1090  unsigned int object_before_ip, object_after_ip;
1091 
1092  //unsigned int last_triangle_vertex=30; // no vertex at last IP
1093  unsigned int current_triangle_vertex;
1094 
1095  // pass through the ccwise oriented sides in ccwise oriented order
1096  // How to make this in independent way?
1097  // Move this into RefElement?
1098  std::vector<unsigned int> side_cycle_orientation = { 0, 0, 1};
1099  std::vector<unsigned int> cycle_sides = {0, 2, 1};
1100 
1101  // TODO:
1102  // better mechanism for detecting vertex duplicities, do no depend on cyclic order of sides
1103  // still need cyclic orientation
1104  for(unsigned int _i_side = 0; _i_side < RefElement<2>::n_lines; _i_side++) { // go through triangle lines
1105  unsigned int i_side = cycle_sides[_i_side];
1106  IP13s.clear();
1107  CI13[ i_side ].compute(IP13s);
1108  ASSERT_DBG(IP13s.size() < 3);
1109  if (IP13s.size() == 0) continue;
1110  for(unsigned int _ip=0; _ip < IP13s.size(); _ip++) {
1111  //int ip_topo_position = _ip*2-1; // -1 (incoming ip), +1 (outcoming ip), 0 both
1112 
1113  // fix order of IPs
1114  unsigned int ip = (side_cycle_orientation[_i_side] + _ip) % IP13s.size();
1115 
1116  //DebugOut().fmt("rside: {} cside: {} rip: {} cip: {}", _i_side, i_side, _ip, ip);
1117 
1118  // convert from 13 to 23 IP
1119  IPAux13 &IP = IP13s[ip];
1120  IntersectionPointAux<3,1> IP31 = IP.switch_objects(); // switch idx_A and idx_B and coords
1121  IntersectionPointAux<3,2> IP32(IP31, i_side); // interpolation uses local_bcoords_B and given idx_B
1122  IPAux23 IP23 = IP32.switch_objects(); // switch idx_A and idx_B and coords back
1123  //DebugOut() << IP;
1124 
1125  // Tracking info
1126  unsigned int tetra_object = s3_dim_starts[IP23.dim_B()] + IP23.idx_B();
1127  unsigned int side_object = s2_dim_starts[1] + i_side;
1128 
1129 
1130  object_before_ip = tetra_object;
1131  object_after_ip = side_object;
1132 
1133 
1134  // IP is vertex of triangle,
1135  if( IP.dim_A() == 0 )
1136  {
1137  // we are on line of the triangle, and IP.idx_A contains local node of the line
1138  // E-E, we know vertex index
1139 
1140  // ?? This should be done in interpolation
1141 
1142  current_triangle_vertex=RefElement<2>::interact(Interaction<0,1>(i_side))[IP.idx_A()];
1143  //ASSERT_EQ_DBG(IP23.idx_A(), current_triangle_vertex);
1144  IP23.set_topology_A(current_triangle_vertex, 0);
1145 
1146  // This should be set only if IP.dim_B() == 3
1147  if (IP.dim_B() == 3)
1148  object_before_ip = s2_dim_starts[0]+current_triangle_vertex;
1149 
1150  }// else current_triangle_vertex=3+IP23_list.size(); // no vertex, and unique
1151 
1152  // side of triangle touching S3, in vertex or in edge
1153  if (IP13s.size() == 1 ) {
1154  if (IP.dim_B() == 0) {
1155  continue; // skip, S3 vertices are better detected in phase 2
1156  }
1157  if (IP.dim_A() == 0) { // vertex of triangle
1158  object_before_ip = tetra_object;
1159  object_after_ip = s2_dim_starts[0]+current_triangle_vertex;
1160 
1161  // source vertex of the side vector (oriented CCwise)
1162  //if ( (IP.idx_A()+side_cycle_orientation[_i_side])%2 == 0)
1163  // std::swap(object_before_ip, object_after_ip);
1164  } else {
1165  // touch in edge
1166 
1167  //continue;
1168  ASSERT_EQ_DBG(IP.dim_B(), 1);
1169  edge_touch[IP23.idx_B()]=true;
1170  std::swap(object_before_ip, object_after_ip);
1171  }
1172  }
1173 
1174  IP23_list.push_back(IP23);
1175 
1176  unsigned int ip_idx = IP23_list.size()-1;
1177  //DebugOut().fmt("before: {} after: {} ip: {}\n", object_before_ip, object_after_ip, ip_idx);
1178  ASSERT_EQ_DBG(IP23_list.size(), IP_next.size()+1);
1179  set_links(object_before_ip, ip_idx, object_after_ip);
1180  }
1181 
1182  }
1183 
1184  // now we have at most single true degenerate IP in IP23
1185  // TODO:
1186  // - deal with degenerate IPs in the edge-trinagle phase
1187  // - remove degenerate_list (just count degen points)
1188  // - remove check for duplicities in final list copy
1189  // - add more comment to individual cases in order to be sure that any case in particular branch is
1190  // treated right
1191 
1192 
1193  IP12s_.clear();
1194  // S3 Edge - S2 intersections; collect all signs, make dummy intersections
1195  for(unsigned int tetra_edge = 0; tetra_edge < 6; tetra_edge++) {
1196  std::vector<IPAux12> IP12_local;
1197  IntersectionResult result = CI12[tetra_edge].compute(IP12_local);
1198  //DebugOut() << print_var(tetra_edge) << print_var(int(result));
1199  if (result < IntersectionResult::degenerate) {
1200  ASSERT_DBG(IP12_local.size() ==1);
1201  IP12s_.push_back(IP12_local[0]);
1202  } else {
1203  ASSERT_DBG(IP12_local.size() ==0);
1204  // make dummy intersection
1205  IP12s_.push_back(IPAux12());
1206  IP12s_.back().set_orientation(result);
1207  }
1208  }
1209  vector<uint> processed_edge(6, 0);
1210  FacePair face_pair;
1211  for(unsigned int tetra_edge = 0; tetra_edge < 6;tetra_edge++) {
1212  if (! processed_edge[tetra_edge]) {
1213  IPAux12 &IP12 = IP12s_[tetra_edge];
1214 
1215 
1216  double edge_coord = IP12.local_bcoords_A()[0];
1217  // skip no intersection and degenerate intersections
1218  if ( edge_coord > 1 || edge_coord < 0 || int(IP12.orientation()) >= 2 ) continue;
1219  //DebugOut() << print_var(tetra_edge) << IP12;
1220 
1221  uint edge_dim = IP12.dim_A();
1222  uint i_edge = tetra_edge;
1223  ASSERT_LT_DBG(edge_dim, 2);
1224 
1225  if ( edge_dim == 1) {
1226  face_pair = edge_faces(i_edge);
1227  } else { // edge_dim == 0
1228  // i_edge is a vertex index in this case
1229  i_edge = RefElement<3>::interact(Interaction<0,1>(tetra_edge))[IP12.idx_A()];
1230  //DebugOut() << print_var(tetra_edge) << print_var(i_edge);
1231  face_pair = vertex_faces(i_edge);
1232  // mark edges coincident with the vertex
1233  for( uint ie : RefElement<3>::interact(Interaction<1,0>(i_edge)) )
1234  processed_edge[ie] = 1;
1235 
1236  }
1237  //DebugOut() << print_var(face_pair[0])<< print_var(face_pair[1]);
1238 
1239  IPAux23 IP23(IP12.switch_objects(), tetra_edge);
1240  IP23.set_topology_B(i_edge, edge_dim);
1241 
1242  IP23_list.push_back(IP23);
1243  unsigned int ip_idx = IP23_list.size()-1;
1244 
1245  unsigned int s3_object = s3_dim_starts[edge_dim] + i_edge;
1246 
1247  //DebugOut() << print_var(edge_touch[i_edge]) << print_var(have_backlink(s3_object));
1248  if (IP12.dim_B() < 2
1249  && (! edge_touch[i_edge])
1250  && object_next[s3_object] != no_idx) { // boundary of S2, these ICs are duplicate
1251 
1252  if ( have_backlink(s3_object) ) {
1253  set_links(s3_object, ip_idx, face_pair[1]);
1254  } else {
1255  set_links(face_pair[0], ip_idx, s3_object);
1256  }
1257 
1258  } else { // interior of S2, just use the face pair
1259  //DebugOut() << print_var(face_pair[0])<< print_var(face_pair[1]);
1260  set_links(face_pair[0], ip_idx, face_pair[1]);
1261 
1262  if ( have_backlink(s3_object) ) {
1263  object_next[s3_object]=ip_idx;
1264  }
1265  }
1266  }
1267  }
1268 
1269 
1270  // Return IPs in correct order and remove duplicates
1271  ASSERT_EQ(0, intersection.size());
1272 
1273  if (IP23_list.size() == 0) return; // empty intersection
1274 
1275  // detect first IP, this needs to be done only in the case of
1276  // point or line intersections, where IPs links do not form closed cycle
1277  // Possibly we do this only if we detect such case through previous phases.
1278  vector<char> have_predecessor(IP23_list.size(), 0);
1279  for(auto obj : IP_next) {
1280  ASSERT_LT_DBG(obj, object_next.size());
1281  unsigned int ip = object_next[obj];
1282  if (ip < IP_next.size()) have_predecessor[ip]=1;
1283  }
1284  unsigned int ip_init=0;
1285  for(unsigned int i=0; i< IP23_list.size(); i++) if (! have_predecessor[i]) ip_init=i;
1286 
1287  // regular case, merge duplicit IPs
1288  unsigned int ip=ip_init;
1289  ASSERT_EQ_DBG(IP_next.size(), IP23_list.size());
1290  intersection.points().push_back(IP23_list[ip]);
1291  //DebugOut() << print_var(ip) << IP23_list[ip];
1292  while (1) {
1293  //DebugOut() << print_var(ip) << IP23_list[ip];
1294 
1295  unsigned int object = IP_next[ip];
1296  //IP_next[ip]=no_idx;
1297  ASSERT_LT_DBG(object, object_next.size());
1298  ip = object_next[object];
1299  object_next[object]=no_idx;
1300  if ((ip == no_idx)) break;
1301  ASSERT_LT_DBG(ip, IP_next.size());
1302 
1303  if ( ! ips_topology_equal(intersection.points().back(), IP23_list[ip]) ) {
1304  //DebugOut() << print_var(ip) << IP23_list[ip];
1305  intersection.points().push_back(IP23_list[ip]);
1306  }
1307 
1308 
1309  }
1310 
1311  if (intersection.points().size() == 1) return;
1312 
1313  if (ips_topology_equal(intersection.points().back(), IP23_list[ip_init]) )
1314  intersection.points().pop_back();
1315 }
1316 
1317 
1318 
1319 
1320 bool ComputeIntersection<Simplex<2>, Simplex<3>>::ips_topology_equal(const IPAux23 &first, const IPAux23 &second)
1321 {
1322  return
1323  first.dim_A() == second.dim_A() &&
1324  first.dim_B() == second.dim_B() &&
1325  first.idx_A() == second.idx_A() &&
1326  first.idx_B() == second.idx_B();
1327 }
1328 
1330 {
1331  auto &line_faces=RefElement<3>::interact(Interaction<2,1>(i_edge));
1332  unsigned int ip_ori = (unsigned int)(IP12s_[i_edge].orientation());
1333  ASSERT_DBG(ip_ori < 2); // no degenerate case
1334 
1335  // RefElement returns edge faces in clockwise order (edge pointing to us)
1336  // negative ip sign (ori 0) = faces counter-clockwise
1337  // positive ip sign (ori 1) = faces clockwise
1338  return { s3_dim_starts[2] + line_faces[1-ip_ori], s3_dim_starts[2] + line_faces[ip_ori] };
1339 }
1340 
1341 auto ComputeIntersection<Simplex<2>, Simplex<3>>::vertex_faces(uint i_vertex)-> FacePair
1342 {
1343  // vertex edges clockwise
1344  const IdxVector<3> &vtx_edges = RefElement<3>::interact(Interaction<1,0>(i_vertex));
1345  std::array<unsigned int, 3> n_ori, sum_idx;
1346  n_ori.fill(0);
1347  sum_idx.fill(0);
1348  for(unsigned int ie=0; ie <3; ie++) {
1349  unsigned int edge_ip_ori = (unsigned int)(IP12s_[ vtx_edges[ie]].orientation());
1350  if (RefElement<3>::interact(Interaction<0,1>(vtx_edges[ie]))[0] != i_vertex
1351  && edge_ip_ori!= int(IntersectionResult::degenerate) )
1352  edge_ip_ori = (edge_ip_ori +1)%2;
1353  //ASSERT_LT_DBG(edge_ip_ori, 3)(ie);
1354  if (edge_ip_ori == 3) edge_ip_ori=2; // none as degenerate
1355  n_ori[edge_ip_ori]++;
1356  sum_idx[edge_ip_ori]+=ie;
1357  }
1358  unsigned int n_degen = n_ori[ int(IntersectionResult::degenerate) ];
1359  unsigned int sum_degen = sum_idx[ int(IntersectionResult::degenerate) ];
1360  unsigned int n_positive = n_ori[ int(IntersectionResult::positive) ];
1361  unsigned int n_negative= n_ori[ int(IntersectionResult::negative) ];
1362  //DebugOut().fmt("nd: {} sd: {} np: {} nn: {}", n_degen, sum_degen, n_positive, n_negative);
1363  if ( n_degen == 2 ) {
1364  // S2 plane match a face of S3, we treat degenerated edges as the faces
1365  // incident with the single regualr edge.
1366 
1367  unsigned int i_edge = 3 - sum_degen; // regular edge index
1368  FacePair pair = edge_faces(vtx_edges[i_edge]);
1369  auto &vtx_faces = RefElement<3>::interact(Interaction<2,0>(i_vertex));
1370  // replace faces by edges
1371  if (pair[0] == s3_dim_starts[2] + vtx_faces[(i_edge+1)%3])
1372  return { s3_dim_starts[1] + (i_edge+2)%3, s3_dim_starts[1] + (i_edge+1)%3 };
1373  else
1374  return { s3_dim_starts[1] + (i_edge+1)%3, s3_dim_starts[1] + (i_edge+2)%3 };
1375 
1376  } else if (n_degen == 1) {
1377  // One edge in S2 plane.
1378  unsigned int i_edge = sum_degen;
1379  ASSERT( n_positive + n_negative == 2);
1380  if ( n_positive == 1) {
1381  // opposite signs, S2 plane cuts S3
1382 
1383  FacePair pair = edge_faces(vtx_edges[(i_edge+1)%3]);
1384  unsigned int face = RefElement<3>::interact(Interaction<2,0>(i_vertex))[i_edge];
1385  // assign edges to faces
1386  //DebugOut().fmt("vtx: {} edg: {} face: {}", i_vertex, i_edge, face);
1387  if (pair[0] == s3_dim_starts[2] + face)
1388  return { s3_dim_starts[2] + face, s3_dim_starts[1] + vtx_edges[i_edge]};
1389  else
1390  return { s3_dim_starts[1] + vtx_edges[i_edge], s3_dim_starts[2] + face };
1391  } else {
1392  // same signs; S2 plane touch S3 vertex and a single edge
1393  //DebugOut() << "Touch in edge.";
1394  // same signs S2 plane touchs S3
1395  ASSERT(n_positive == 0 || n_positive== 2);
1396  return { s3_dim_starts[0]+i_vertex, s3_dim_starts[1] + vtx_edges[i_edge]};
1397  }
1398 
1399 
1400  } else {
1401  ASSERT(n_degen == 0);
1402  ASSERT( n_positive + n_negative == 3);
1403 
1404  if (n_positive == 1) {
1405  unsigned int i_edge = sum_idx[ int(IntersectionResult::positive) ];
1406  return edge_faces(vtx_edges[i_edge]);
1407  } else if (n_negative == 1) {
1408  unsigned int i_edge = sum_idx[ int(IntersectionResult::negative) ];
1409  return edge_faces(vtx_edges[i_edge]);
1410  } else {
1411  // S2 touch vertex of S3 in
1412  ASSERT( n_positive == 0 || n_positive == 3);
1413  return { s3_dim_starts[0]+i_vertex, s3_dim_starts[0]+i_vertex};
1414  }
1415  }
1416 }
1417 
1418 
1419 void ComputeIntersection<Simplex<2>, Simplex<3>>::print_plucker_coordinates(std::ostream &os){
1420  for(unsigned int i = 0; i < 3;i++){
1421  os << "\tPluckerCoordinates Triangle[" << i << "]";
1422  if(plucker_coordinates_triangle_[i] == nullptr){
1423  os << "NULL" << endl;
1424  }else{
1425  os << plucker_coordinates_triangle_[i];
1426  }
1427  }
1428  for(unsigned int i = 0; i < 6;i++){
1429  os << "\tPluckerCoordinates Tetrahedron[" << i << "]";
1430  if(plucker_coordinates_tetrahedron[i] == nullptr){
1431  os << "NULL" << endl;
1432  }else{
1433  os << plucker_coordinates_tetrahedron[i];
1434  }
1435  }
1436 };
1437 
1438 void ComputeIntersection<Simplex<2>, Simplex<3>>::print_plucker_coordinates_tree(std::ostream &os){
1439  os << "ComputeIntersection<Simplex<2>, <Simplex<3>> Plucker Coordinates Tree:" << endl;
1440  print_plucker_coordinates(os);
1441  for(unsigned int i = 0; i < 6;i++){
1442  os << "ComputeIntersection<Simplex<1>, Simplex<2>>["<< i <<"] Plucker Coordinates:" << endl;
1443  CI12[i].print_plucker_coordinates(os);
1444  }
1445  for(unsigned int i = 0; i < 3;i++){
1446  CI13[i].print_plucker_coordinates_tree(os);
1447  }
1448 };
1449 
unsigned int dim_A() const
Returns dimension of object A.
#define ASSERT_EQ_DBG(a, b)
Definition of comparative assert macro (EQual) only for debug mode.
Definition: asserts.hh:331
void set_topology_B(unsigned int idx, unsigned int dim_B)
Sets the topology of object B in Simplex<M>.
std::vector< IntersectionPointAux< dimA, dimB > > i_points_
Vector of internal intersection points.
unsigned int uint
Plucker coordinates class.
static BaryPoint line_barycentric_interpolation(BaryPoint first_coords, BaryPoint second_coords, double first_theta, double second_theta, double theta)
Definition: ref_element.cc:552
void clear()
Resets the object to default values.
Fundamental simplicial intersections.
void set_topology_A(unsigned int idx, unsigned int dim_A)
Sets the topology of object A in Simplex<N>.
Definition: mesh.h:99
static const double rounding_epsilon
unsigned int size() const
Returns number of intersection points.
void set_orientation(IntersectionResult orientation)
Setter orientation flag.
static const double geometry_epsilon
Simplex< 1 > & abscissa(unsigned int idx)
Get simplex of abscissa from different simplices - if it has own implementation in ...
#define ASSERT(expr)
Allow use shorter versions of macro names if these names is not used with external library...
Definition: asserts.hh:346
const arma::vec::fixed< N+1 > & local_bcoords_A() const
Returns barycentric coordinates in the Simplex<N>.
static unsigned int normal_orientation(unsigned int sid)
Definition: ref_element.cc:315
unsigned int idx_A() const
Returns the index of Simplex<N>.
unsigned int dim_B() const
Returns dimension of object B.
void set_coordinates(const arma::vec::fixed< N+1 > &lcA, const arma::vec::fixed< M+1 > &lcB)
Setter for coordinates.
static const IdxVector< (InDim >OutDim?InDim+1:dim-InDim) > interact(TInteraction< OutDim, InDim > interaction)
std::vector< IntersectionPointAux< dimA, dimB > > & points()
Returns intersection points by a reference.
void swap(nlohmann::json &j1, nlohmann::json &j2) noexcept(is_nothrow_move_constructible< nlohmann::json >::value andis_nothrow_move_assignable< nlohmann::json >::value)
exchanges the values of two JSON objects
Definition: json.hpp:8688
std::array< unsigned int, Size > IdxVector
Definition: ref_element.hh:144
IntersectionPointAux< M, N > switch_objects() const
Switches the object A and B.
#define ASSERT_DBG(expr)
Definition: asserts.hh:349
static const double plucker_empty
Auxiliary value for Plucker product. If equal this value, it is supposed not to be set yet...
Internal auxiliary class represents an intersection point of simplex<N> and simplex<M>.
Class RefElement defines numbering of vertices, sides, calculation of normal vectors etc...
IntersectionResult orientation() const
Returns the orientation.
unsigned int idx_B() const
Returns the index of Simplex<M>.
Internal class representing intersection point.
Plucker coordinates representing line given by points A,B.
Definition: plucker.hh:47
#define ASSERT_EQ(a, b)
Definition of comparative assert macro (EQual)
Definition: asserts.hh:327
Internal class representing intersection object.
#define ASSERT_LT_DBG(a, b)
Definition of comparative assert macro (Less Than) only for debug mode.
Definition: asserts.hh:299