EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_lattice.h
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ lattice geometry headers
5 # Copyright (C) 2019 Rowan Thomson and Martin Martinov
6 #
7 # This file is part of EGSnrc.
8 #
9 # EGSnrc is free software: you can redistribute it and/or modify it under
10 # the terms of the GNU Affero General Public License as published by the
11 # Free Software Foundation, either version 3 of the License, or (at your
12 # option) any later version.
13 #
14 # EGSnrc is distributed in the hope that it will be useful, but WITHOUT ANY
15 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU Affero General Public License
20 # along with EGSnrc. If not, see <http://www.gnu.org/licenses/>.
21 #
22 ###############################################################################
23 #
24 # Author: Martin Martinov, 2019
25 #
26 # Contributors: Frederic Tessier
27 # Ernesto Mainegra-Hing
28 #
29 ###############################################################################
30 #
31 # When egs_lattice is used for publications, please cite the following paper:
32 #
33 # Martinov, Martin P., and Rowan M. Thomson. Taking EGSnrc to new lows:
34 # Development of egs++ lattice geometry and testing with microscopic
35 # geometries. Medical Physics 47, 3225-3232 (2020).
36 #
37 ###############################################################################
38 */
39 
40 
45 #include "egs_base_geometry.h"
46 #include "../egs_gtransformed/egs_gtransformed.h"
47 
48 #ifndef EGS_LATTICE_GEOMETRY_
49 #define EGS_LATTICE_GEOMETRY_
50 
51 #ifdef WIN32
52 
53  #ifdef BUILD_LATTICE_DLL
54  #define EGS_LATTICE_EXPORT __declspec(dllexport)
55  #else
56  #define EGS_LATTICE_EXPORT __declspec(dllimport)
57  #endif
58  #define EGS_LATTICE_LOCAL
59 
60 #else
61 
62  #ifdef HAVE_VISIBILITY
63  #define EGS_LATTICE_EXPORT __attribute__ ((visibility ("default")))
64  #define EGS_LATTICE_LOCAL __attribute__ ((visibility ("hidden")))
65  #else
66  #define EGS_LATTICE_EXPORT
67  #define EGS_LATTICE_LOCAL
68  #endif
69 
70 #endif
71 
146 class EGS_LATTICE_EXPORT EGS_Lattice : public EGS_BaseGeometry {
147 protected:
148 
151  int ind;
152  int maxStep;
153  EGS_Float a, b, c;
154  string type;
155 
156 public:
157 
158  EGS_Lattice(EGS_BaseGeometry *B, EGS_BaseGeometry *S, int i, EGS_Float x,
159  EGS_Float y, EGS_Float z, const string &Name = "");
160  ~EGS_Lattice();
161 
162  EGS_Vector closestPoint(const EGS_Vector &x) {
163  return EGS_Vector(int(round(x.x/a))*a,
164  int(round(x.y/b))*b,
165  int(round(x.z/c))*c);
166  };
167 
168  int computeIntersections(int ireg, int n, const EGS_Vector &x,
169  const EGS_Vector &u, EGS_GeometryIntersections *isections) {
170  return base->computeIntersections(ireg,n,x,u,isections);
171  };
172 
173  bool isRealRegion(int ireg) const {
174  if (ireg < base->regions()) { // If ireg is less than base regions
175  return base->isRealRegion(ireg); // check against base regions
176  }
177  return sub->isRealRegion(ireg - base->regions()); // then check sub regions
178  };
179 
180  bool isInside(const EGS_Vector &x) {
181  return base->isInside(x);
182  };
183 
184  int isWhere(const EGS_Vector &x) {
185  int temp = base->isWhere(x);
186  if (temp == ind) {// Are we in the subgeom?
187  sub->setTransformation(closestPoint(x));
188  if (sub->isInside(x)) {
189  return sub->isWhere(x) + base->regions();
190  }
191  }
192  return temp; // otherwise base geom
193  };
194 
195  int inside(const EGS_Vector &x) {
196  return isWhere(x);
197  };
198 
199  int medium(int ireg) const {
200  if (ireg >= base->regions()) { // If ireg is greater than base regions
201  return sub->medium(ireg-base->regions());
202  }
203  return base->medium(ireg); // If in base region
204  };
205 
206  EGS_Float howfarToOutside(int ireg, const EGS_Vector &x, const EGS_Vector &u) {
207  if (ireg < 0) { // Error catch, not inside
208  return 0;
209  }
210 
211  // Are we in the subgeom
212  if (ireg >= base->regions()) {
213  return base->howfarToOutside(ind,x,u);
214  }
215  return base->howfarToOutside(ireg,x,u);
216  };
217 
218  int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
219  EGS_Float &t,int *newmed=0, EGS_Vector *normal=0) {
220  // Catch t=0 exception, which sometimes causes issues when ind is the region neighboring -1
221  if (t < epsilon) {
222  t = 0.0;
223  return ireg;
224  }
225 
226  if (ireg >= base->regions()) { // Are we in the subgeom?
227  sub->setTransformation(closestPoint(x));
228 
229  // Do the howfar call
230  EGS_Float tempT = t;
231  int tempReg = sub->howfar(ireg-base->regions(),x,u,tempT,newmed,normal);
232 
233  // If we do leave the subgeom, we want to return the index
234  // of the region of the base geometry we would be entering,
235  // which is not necessarily ind if subgeom is at a boundary
236  EGS_Vector newX = u;
237  newX.normalize();
238  newX = x + (newX * tempT);
239 
240  if (base->isWhere(newX) != ind) {// If we leave ind region of base
241  t = tempT;
242 
243  tempReg = base->howfar(ind,x,u,t,0,normal);
244  if (newmed && tempReg >= 0) {
245  *newmed = base->medium(tempReg);
246  }
247 
248  //if (t<0) {
249  // egsWarning("Returning negative t from subgeom of %s\n",getName().c_str());
250  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
251  //}
252  return tempReg;
253  }
254 
255  if (!(tempReg+1)) {// If we leave sub geom back into ind
256  if (newmed) {
257  *newmed = base->medium(ind);
258  }
259  t = tempT;
260  return ind;
261  }
262 
263  // else we stay in sub geom
264  t = tempT;
265  //if (t<0) {
266  // egsWarning("Returning negative t from subgeom of %s\n",getName().c_str());
267  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
268  //}
269  return tempReg+base->regions();
270  }
271  else if (ireg == ind) {// If we are in the region that could contain subgeoms
272  // Determine the path travelled ------------------------------------------------ //
273  EGS_Float tempT = t;
274  base->howfar(ireg,x,u,tempT); // Get how far it is in temp
275  EGS_Float max = tempT;
276 
277  // Iterate through the lattice ------------------------------------------------- //
278  EGS_Float min = max, minX = max, minY = max, minZ = max; // Distance to closest subgeom for three different cases
279  EGS_Vector unit = u;
280  unit.normalize();
281  EGS_Vector xInt = unit*(a/4.0/fabs(unit.x)), yInt = unit*(b/4.0/fabs(unit.y)), zInt = unit*(c/4.0/fabs(unit.z));
282  EGS_Vector tempP; // Temporarily hold indices of subgeom we are testing against
283  EGS_Vector finalP, finalX, finalY, finalZ; // Current closest intersecting subgeom
284 
285  EGS_Vector x0;
286  EGS_Float max2 = max*max;
287 
288  x0 = x;
289  while ((x-x0).length2() < max2) {// Quit as soon as our testing position is beyond current closest intersection (which could be tempT)
290  tempT = minX;
291  tempP = closestPoint(x0);
292  sub->setTransformation(tempP);
293  if (sub->howfar(-1,x,u,tempT)+1) // Intersection!
294  if (tempT < max && tempT > 0) {
295  finalX = tempP;
296  minX = tempT;
297  break;
298  }
299  x0 += xInt;
300  }
301 
302  x0 = x;
303  while ((x-x0).length2() < max2) {// Quit as soon as our testing position is beyond current closest intersection (which could be tempT)
304  tempT = minY;
305  tempP = closestPoint(x0);
306  sub->setTransformation(tempP);
307  if (sub->howfar(-1,x,u,tempT)+1) // Intersection!
308  if (tempT < max && tempT > 0) {
309  finalY = tempP;
310  minY = tempT;
311  break;
312  }
313  x0 += yInt;
314  }
315 
316  x0 = x;
317  while ((x-x0).length2() < max2) {// Quit as soon as our testing position is beyond current closest intersection (which could be tempT)
318  tempT = minZ;
319  tempP = closestPoint(x0);
320  sub->setTransformation(tempP);
321  if (sub->howfar(-1,x,u,tempT)+1) // Intersection!
322  if (tempT < max && tempT > 0) {
323  finalZ = tempP;
324  minZ = tempT;
325  break;
326  }
327  x0 += zInt;
328  }
329 
330  finalP = finalX;
331  min = minX;
332  if (min > minY) {
333  min = minY;
334  finalP = finalY;
335  }
336  if (min > minZ) {
337  min = minZ;
338  finalP = finalZ;
339  }
340 
341  // Check last point
342  tempT = max;
343  sub->setTransformation(closestPoint(x+unit*tempT));
344  sub->howfar(-1,x,u,tempT);
345  if (tempT < min && tempT > 0) {
346  min = tempT;
347  finalP = closestPoint(x+unit*tempT);
348  }
349 
350  // We did intersect subgeom
351  if (min < max) {
352  tempT = t;
353  sub->setTransformation(finalP);
354  int tempReg = sub->howfar(-1,x,u,tempT,newmed,normal);
355  if (tempReg+1) {
356  if (newmed && tempReg >= 0) {
357  *newmed = sub->medium(tempReg);
358  }
359  t = tempT;
360 
361  //if (t<0) {
362  // egsWarning("Returning negative t from region %d in base geom of %s\n", ind, getName().c_str());
363  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
364  //}
365  return tempReg+base->regions();
366  }
367  }
368 
369  // We didn't intersect subgeom
370  int tempReg = base->howfar(ireg,x,u,t,newmed,normal);
371  //if (t<0) {
372  // egsWarning("Returning negative t from region %d in base geom of %s\n", ind, getName().c_str());
373  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
374  //}
375  if (newmed && tempReg >= 0) {
376  *newmed = base->medium(tempReg);
377  }
378 
379  return tempReg;
380  }
381  else {// Not in region containing subgeoms, then it is quite easy
382  // unless we enter directly into a subgeom when entering
383  // region ind
384  int tempReg = base->howfar(ireg,x,u,t,newmed,normal);
385 
386  // If we enter region ind
387  if (tempReg == ind) {
388  // newX is the point of entrance
389  EGS_Vector newX = u;
390  newX.normalize();
391  newX = x + (newX * t);
392 
393  sub->setTransformation(closestPoint(newX));
394  int newReg = sub->isWhere(newX);
395  if (newReg+1) { // see what region we are in
396  if (newmed && newReg >= 0) { // in subgeom, if its not -1
397  *newmed = sub->medium(newReg); // then return the proper
398  }
399  //if (t<0) { // media and region
400  // egsWarning("Returning negative t from region %d (not ind) in base geom of %s\n", ireg, getName().c_str());
401  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
402  //}
403  return newReg + base->regions();
404  }
405  }
406 
407  if (newmed && tempReg >= 0) {
408  *newmed = base->medium(tempReg);
409  }
410  //if (t<0) {
411  // egsWarning("Returning negative t from region %d (not ind) in base geom of %s\n", ireg, getName().c_str());
412  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
413  //}
414  return tempReg;
415  }
416  };
417 
418  EGS_Float hownear(int ireg, const EGS_Vector &x) {
419  EGS_Float temp, dist = base->hownear(ind,x);
420  if (ireg >= base->regions()) {
421  sub->setTransformation(closestPoint(x));
422  temp = sub->hownear(ireg-base->regions(),x);
423  dist=(temp<dist)?temp:dist;
424  }
425  else if (ireg == ind) {
426  // Check all nearby geometries
427  EGS_Float xa = floor(x.x/a)*a, yb = floor(x.y/b)*b, zc = floor(x.z/c)*c;
428  EGS_Vector x0[8] = {EGS_Vector(xa, yb, zc),
429  EGS_Vector(xa+a,yb, zc),
430  EGS_Vector(xa, yb+b,zc),
431  EGS_Vector(xa+a,yb+b,zc),
432  EGS_Vector(xa, yb, zc+c),
433  EGS_Vector(xa+a,yb, zc+c),
434  EGS_Vector(xa, yb+b,zc+c),
435  EGS_Vector(xa+a,yb+b,zc+c)
436  };
437  for (int i = 0; i < 8; i++) {
438  sub->setTransformation(x0[i]);
439  temp = sub->hownear(-1,x);
440  if (temp < dist) {
441  dist = temp;
442  }
443  }
444  }
445  else {
446  dist = base->hownear(ireg,x);
447  }
448  return dist;
449  };
450 
451  int regions() {
452  return base->regions() + sub->regions();
453  }
454 
455  int getMaxStep() const {
456  return maxStep;
457  };
458 
459  const string &getType() const {
460  return type;
461  };
462 
463  void printInfo() const;
464 
465  // I have no idea what this boolean stuff is for
466  bool hasBooleanProperty(int ireg, EGS_BPType prop) const {
467  if (ireg < base->regions()) { // If ireg is less than base regions
468  return base->hasBooleanProperty(ireg, prop); // check against base regions
469  }
470  return sub->hasBooleanProperty(ireg - base->regions(), prop); // then check sub regions
471  };
472  void setBooleanProperty(EGS_BPType prop) {
473  base->setBooleanProperty(prop);
474  };
475  void addBooleanProperty(int bit) {
476  base->addBooleanProperty(bit);
477  };
478  void setBooleanProperty(EGS_BPType prop, int start, int end, int step=1) {
479  base->setBooleanProperty(prop,start,end,step);
480  };
481  void addBooleanProperty(int bit, int start, int end, int step=1) {
482  base->addBooleanProperty(bit,start,end,step);
483  };
484 
485  EGS_Float getRelativeRho(int ireg) const {
486  if (ireg < base->regions()) { // If ireg is less than base regions
487  return base->getRelativeRho(ireg); // check against base regions
488  }
489  return sub->getRelativeRho(ireg - base->regions()); // then check sub regions
490  };
491  void setRelativeRho(int start, int end, EGS_Float rho);
492  void setRelativeRho(EGS_Input *);
493 
494  void setBScaling(int start, int end, EGS_Float rho);
495  void setBScaling(EGS_Input *);
496  EGS_Float getBScaling(int ireg) const {
497  if (ireg < base->regions()) { // If ireg is less than base regions
498  return base->getBScaling(ireg); // check against base regions
499  }
500  return sub->getBScaling(ireg - base->regions()); // then check sub regions
501  };
502 
503  virtual void getLabelRegions(const string &str, vector<int> &regs);
504 
505 protected:
506  void setMedia(EGS_Input *inp,int,const int *);
507 };
508 
509 class EGS_LATTICE_EXPORT EGS_Hexagonal_Lattice : public EGS_BaseGeometry {
510 protected:
511 
514  int ind;
515  int maxStep;
516  EGS_Float a;
517  vector<EGS_Float> d;
518  string type;
519  EGS_Float gap;
520  // y and z have a shorter recurrence scale than a
521 public:
522 
523  EGS_Hexagonal_Lattice(EGS_BaseGeometry *B, EGS_BaseGeometry *S, int i, EGS_Float x, const string &Name = "");
525 
526  // Based off the closestPoint() function in the egs_lattice definition, here we check against the four
527  // Bravais lattices that make up the hexagonal lattice to find the closest point
528  EGS_Vector closestPoint(const EGS_Vector &x) {
529  EGS_Float i1,j1,k1,i2,j2,j3,k3,j4;
530  EGS_Float r3a = 2.0*gap;
531 
532  i1 = a*(round(x.x/a));
533  j1 = r3a*(round(x.y/r3a));
534  k1 = r3a*(round(x.z/r3a));
535 
536  i2 = a*(0.5+round(x.x/a-0.5));
537  j2 = r3a*(0.5+round(x.y/r3a-0.5));
538 
539  j3 = r3a*(0.25+round(x.y/r3a-0.25));
540  k3 = r3a*(0.5+round(x.z/r3a-0.5));
541 
542  j4 = r3a*(-0.25+round(x.y/r3a+0.25));
543 
544  EGS_Vector p1(i1,j1,k1);
545  EGS_Vector p2(i2,j2,k1);
546  EGS_Vector p3(i1,j3,k3);
547  EGS_Vector p4(i2,j4,k3);
548 
549  d[0] = (x-p1).length2();
550  d[1] = (x-p2).length2();
551  d[2] = (x-p3).length2();
552  d[3] = (x-p4).length2();
553 
554  if (d[0] < d[1] && d[0] < d[2] && d[0] < d[3]) {
555  return p1;
556  }
557  if (d[1] < d[2] && d[1] < d[3]) {
558  return p2;
559  }
560  if (d[2] < d[3]) {
561  return p3;
562  }
563  return p4;
564  };
565 
566  int computeIntersections(int ireg, int n, const EGS_Vector &x,
567  const EGS_Vector &u, EGS_GeometryIntersections *isections) {
568  return base->computeIntersections(ireg,n,x,u,isections);
569  };
570 
571  bool isRealRegion(int ireg) const {
572  if (ireg < base->regions()) { // If ireg is less than base regions
573  return base->isRealRegion(ireg); // check against base regions
574  }
575  return sub->isRealRegion(ireg - base->regions()); // then check sub regions
576  };
577 
578  bool isInside(const EGS_Vector &x) {
579  return base->isInside(x);
580  };
581 
582  int isWhere(const EGS_Vector &x) {
583  int temp = base->isWhere(x);
584  if (temp == ind) {// Are we in the subgeom?
585  sub->setTransformation(closestPoint(x));
586  if (sub->isInside(x)) {
587  return sub->isWhere(x) + base->regions();
588  }
589  }
590  return temp; // otherwise base geom
591  };
592 
593  int inside(const EGS_Vector &x) {
594  return isWhere(x);
595  };
596 
597  int medium(int ireg) const {
598  if (ireg >= base->regions()) { // If ireg is greater than base regions
599  return sub->medium(ireg-base->regions());
600  }
601  return base->medium(ireg); // If in base region
602  };
603 
604  EGS_Float howfarToOutside(int ireg, const EGS_Vector &x, const EGS_Vector &u) {
605  if (ireg < 0) { // Error catch, not inside
606  return 0;
607  }
608 
609  // Are we in the subgeom
610  if (ireg >= base->regions()) {
611  return base->howfarToOutside(ind,x,u);
612  }
613  return base->howfarToOutside(ireg,x,u);
614  };
615 
616  int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
617  EGS_Float &t,int *newmed=0, EGS_Vector *normal=0) {
618  // Catch t=0 exception, which sometimes causes issues when ind is the region neighboring -1
619  if (t < epsilon) {
620  t = 0.0;
621  return ireg;
622  }
623 
624  if (ireg >= base->regions()) { // Are we in the subgeom?
625  sub->setTransformation(closestPoint(x));
626 
627  // Do the howfar call
628  EGS_Float tempT = t;
629  int tempReg = sub->howfar(ireg-base->regions(),x,u,tempT,newmed,normal);
630 
631  // If we do leave the subgeom, we want to return the index
632  // of the region of the base geometry we would be entering,
633  // which is not necessarily ind if subgeom is at a boundary
634  EGS_Vector newX = u;
635  newX.normalize();
636  newX = x + (newX * tempT);
637 
638  if (base->isWhere(newX) != ind) {// If we leave ind region of base
639  t = tempT;
640 
641  tempReg = base->howfar(ind,x,u,t,0,normal);
642  if (newmed && tempReg >= 0) {
643  *newmed = base->medium(tempReg);
644  }
645 
646  //if (t<0) {
647  // egsWarning("Returning negative t from subgeom of %s\n",getName().c_str());
648  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
649  //}
650  return tempReg;
651  }
652 
653  if (!(tempReg+1)) {// If we leave sub geom back into ind
654  if (newmed) {
655  *newmed = base->medium(ind);
656  }
657  t = tempT;
658  return ind;
659  }
660 
661  // else we stay in sub geom
662  t = tempT;
663  //if (t<0) {
664  // egsWarning("Returning negative t from subgeom of %s\n",getName().c_str());
665  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
666  //}
667  return tempReg+base->regions();
668  }
669  else if (ireg == ind) {// If we are in the region that could contain subgeoms
670  // Determine the path travelled ------------------------------------------------ //
671  EGS_Float tempT = t;
672  base->howfar(ireg,x,u,tempT); // Get how far it is in temp
673  EGS_Float max = tempT;
674 
675  // Iterate through the lattice ------------------------------------------------- //
676  EGS_Float min = max, minX = max, minY = max, minZ = max; // Distance to closest subgeom for three different cases
677  EGS_Vector unit = u;
678  unit.normalize();
679  EGS_Vector xInt = unit*(a/8.0/fabs(unit.x)), yInt = unit*(gap/8.0/fabs(unit.y)), zInt = unit*(gap/8.0/fabs(unit.z));
680  EGS_Vector tempP; // Temporarily hold indices of subgeom we are testing against
681  EGS_Vector finalP, finalX, finalY, finalZ; // Current closest intersecting subgeom
682 
683  EGS_Vector x0;
684  EGS_Float max2 = max*max;
685 
686  x0 = x;
687  while ((x-x0).length2() < max2) {// Quit as soon as our testing position is beyond current closest intersection (which could be tempT)
688  tempT = minX;
689  tempP = closestPoint(x0);
690  sub->setTransformation(tempP);
691  if (sub->howfar(-1,x,u,tempT)+1) // Intersection!
692  if (tempT < max && tempT > 0) {
693  finalX = tempP;
694  minX = tempT;
695  break;
696  }
697  x0 += xInt;
698  }
699 
700  x0 = x;
701  while ((x-x0).length2() < max2) {// Quit as soon as our testing position is beyond current closest intersection (which could be tempT)
702  tempT = minY;
703  tempP = closestPoint(x0);
704  sub->setTransformation(tempP);
705  if (sub->howfar(-1,x,u,tempT)+1) // Intersection!
706  if (tempT < max && tempT > 0) {
707  finalY = tempP;
708  minY = tempT;
709  break;
710  }
711  x0 += yInt;
712  }
713 
714  x0 = x;
715  while ((x-x0).length2() < max2) {// Quit as soon as our testing position is beyond current closest intersection (which could be tempT)
716  tempT = minZ;
717  tempP = closestPoint(x0);
718  sub->setTransformation(tempP);
719  if (sub->howfar(-1,x,u,tempT)+1) // Intersection!
720  if (tempT < max && tempT > 0) {
721  finalZ = tempP;
722  minZ = tempT;
723  break;
724  }
725  x0 += zInt;
726  }
727 
728  finalP = finalX;
729  min = minX;
730  if (min > minY) {
731  min = minY;
732  finalP = finalY;
733  }
734  if (min > minZ) {
735  min = minZ;
736  finalP = finalZ;
737  }
738 
739  // Check last point
740  tempT = max;
741  sub->setTransformation(closestPoint(x+unit*tempT));
742  sub->howfar(-1,x,u,tempT);
743  if (tempT < min && tempT > 0) {
744  min = tempT;
745  finalP = closestPoint(x+unit*tempT);
746  }
747 
748  // We did intersect subgeom
749  if (min < max) {
750  tempT = t;
751  sub->setTransformation(finalP);
752  int tempReg = sub->howfar(-1,x,u,tempT,newmed,normal);
753  if (tempReg+1) {
754  if (newmed && tempReg >= 0) {
755  *newmed = sub->medium(tempReg);
756  }
757  t = tempT;
758 
759  //if (t<0) {
760  // egsWarning("Returning negative t from region %d in base geom of %s\n", ind, getName().c_str());
761  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
762  //}
763  return tempReg+base->regions();
764  }
765  }
766 
767  // We didn't intersect subgeom
768  int tempReg = base->howfar(ireg,x,u,t,newmed,normal);
769  //if (t<0) {
770  // egsWarning("Returning negative t from region %d in base geom of %s\n", ind, getName().c_str());
771  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n",ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
772  //}
773  if (newmed && tempReg >= 0) {
774  *newmed = base->medium(tempReg);
775  }
776 
777  return tempReg;
778  }
779  else {// Not in region containing subgeoms, then it is quite easy
780  // unless we enter directly into a subgeom when entering
781  // region ind
782  int tempReg = base->howfar(ireg,x,u,t,newmed,normal);
783 
784  // If we enter region ind
785  if (tempReg == ind) {
786  // newX is the point of entrance
787  EGS_Vector newX = u;
788  newX.normalize();
789  newX = x + (newX * t);
790 
791  sub->setTransformation(closestPoint(newX));
792  int newReg = sub->isWhere(newX);
793  if (newReg+1) { // see what region we are in
794  if (newmed && newReg >= 0) { // in subgeom, if its not -1
795  *newmed = sub->medium(newReg); // then return the proper
796  }
797  //if (t<0) { // media and region
798  // egsWarning("Returning negative t from region %d (not ind) in base geom of %s\n", ireg, getName().c_str());
799  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n", ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
800  //}
801  return newReg + base->regions();
802  }
803  }
804 
805  if (newmed && tempReg >= 0) {
806  *newmed = base->medium(tempReg);
807  }
808  //if (t<0) {
809  // egsWarning("Returning negative t from region %d (not ind) in base geom of %s\n", ireg, getName().c_str());
810  // egsWarning("howfar(%7d,[%e,%e,%e],[%e,%e,%e],%e)\n", ireg, x.x, x.y, x.z, u.x, u.y, u.z, t);
811  //}
812  return tempReg;
813  }
814  };
815 
816  EGS_Float hownear(int ireg, const EGS_Vector &x) {
817  EGS_Float temp, dist = base->hownear(ireg>=base->regions()?ind:ireg,x);
818  if (ireg >= base->regions()) {
819  sub->setTransformation(closestPoint(x));
820  temp = sub->hownear(ireg-base->regions(),x);
821  dist=(temp<dist)?temp:dist;
822  }
823  else if (ireg == ind) {
824  // Check all nearby geometries, making use of the 4 Bravais lattice substructure of the geometry
825  EGS_Float i,j,k;
826  EGS_Float r3a = 2.0*gap, hgap = gap/2.0, ha = a/2.0;
827  EGS_Vector x0[8];
828 
829  // Calculate the edge of an oblique rhombic prism formed around x
830  i = a*(floor(x.x/a));
831  j = r3a*(round(x.y/r3a));
832  k = r3a*(round(x.z/r3a));
833 
834  // One of the following 4 trigonal trapezohedrons must enclose x, they all share an edge defined
835  // as (i,j,k) to (i+a,j,k) and can recurse through all space
836  if (x.y<=j && x.z<=k)
837  EGS_Vector x0[8] = {EGS_Vector(i,j,k),
838  EGS_Vector(i-ha,j-gap,k),
839  EGS_Vector(i,j-gap-hgap,k-gap),
840  EGS_Vector(i+ha,j-hgap,k-gap),
841  EGS_Vector(i+a,j,k),
842  EGS_Vector(i+ha,j-gap,k),
843  EGS_Vector(i+a,j-gap-hgap,k-gap),
844  EGS_Vector(i+a+ha,j-hgap,k-gap)
845  };
846  else if (x.y>j && x.z<=k)
847  EGS_Vector x0[8] = {EGS_Vector(i,j,k),
848  EGS_Vector(i+ha,j+gap,k),
849  EGS_Vector(i+a,j+hgap,k-gap),
850  EGS_Vector(i+ha,j-hgap,k-gap),
851  EGS_Vector(i+a,j,k),
852  EGS_Vector(i+a+ha,j+gap,k),
853  EGS_Vector(i+a+a,j+hgap,k-gap),
854  EGS_Vector(i+a+ha,j-hgap,k-gap)
855  };
856  else if (x.y<j && x.z>k)
857  EGS_Vector x0[8] = {EGS_Vector(i,j,k),
858  EGS_Vector(i+ha,j-gap,k),
859  EGS_Vector(i,j-gap-hgap,k+gap),
860  EGS_Vector(i-ha,j-hgap,k+gap),
861  EGS_Vector(i+a,j,k),
862  EGS_Vector(i+a+ha,j-gap,k),
863  EGS_Vector(i+a,j-gap-hgap,k+gap),
864  EGS_Vector(i+ha,j-hgap,k+gap)
865  };
866  else //(x.y>j && x.z>k)
867  EGS_Vector x0[8] = {EGS_Vector(i,j,k),
868  EGS_Vector(i-ha,j+gap,k),
869  EGS_Vector(i-a,j+hgap,k+gap),
870  EGS_Vector(i-ha,j-hgap,k+gap),
871  EGS_Vector(i+a,j,k),
872  EGS_Vector(i+ha,j+gap,k),
873  EGS_Vector(i,j+hgap,k+gap),
874  EGS_Vector(i+ha,j-hgap,k+gap)
875  };
876  for (int i = 0; i < 8; i++) {
877  sub->setTransformation(x0[i]);
878  temp = sub->hownear(-1,x);
879  if (temp < dist) {
880  dist = temp;
881  }
882  }
883  }
884  return dist;
885  };
886 
887  int regions() {
888  return base->regions() + sub->regions();
889  }
890 
891  int getMaxStep() const {
892  return maxStep;
893  };
894 
895  const string &getType() const {
896  return type;
897  };
898 
899  void printInfo() const;
900 
901  // I have no idea what this boolean stuff is for
902  bool hasBooleanProperty(int ireg, EGS_BPType prop) const {
903  if (ireg < base->regions()) { // If ireg is less than base regions
904  return base->hasBooleanProperty(ireg, prop); // check against base regions
905  }
906  return sub->hasBooleanProperty(ireg - base->regions(), prop); // then check sub regions
907  };
908  void setBooleanProperty(EGS_BPType prop) {
909  base->setBooleanProperty(prop);
910  };
911  void addBooleanProperty(int bit) {
912  base->addBooleanProperty(bit);
913  };
914  void setBooleanProperty(EGS_BPType prop, int start, int end, int step=1) {
915  base->setBooleanProperty(prop,start,end,step);
916  };
917  void addBooleanProperty(int bit, int start, int end, int step=1) {
918  base->addBooleanProperty(bit,start,end,step);
919  };
920 
921  EGS_Float getRelativeRho(int ireg) const {
922  if (ireg < base->regions()) { // If ireg is less than base regions
923  return base->getRelativeRho(ireg); // check against base regions
924  }
925  return sub->getRelativeRho(ireg - base->regions()); // then check sub regions
926  };
927  void setRelativeRho(int start, int end, EGS_Float rho);
928  void setRelativeRho(EGS_Input *);
929 
930  void setBScaling(int start, int end, EGS_Float rho);
931  void setBScaling(EGS_Input *);
932  EGS_Float getBScaling(int ireg) const {
933  if (ireg < base->regions()) { // If ireg is less than base regions
934  return base->getBScaling(ireg); // check against base regions
935  }
936  return sub->getBScaling(ireg - base->regions()); // then check sub regions
937  };
938 
939  virtual void getLabelRegions(const string &str, vector<int> &regs);
940 
941 protected:
942  void setMedia(EGS_Input *inp,int,const int *);
943 };
944 
945 #endif
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
virtual int computeIntersections(int ireg, int n, const EGS_Vector &x, const EGS_Vector &u, EGS_GeometryIntersections *isections)
Calculates intersection distances to region boundaries.
virtual EGS_Float hownear(int ireg, const EGS_Vector &x)=0
Calculate the distance to a boundary for position x in any direction.
virtual int inside(const EGS_Vector &x)=0
Returns the region index, if inside, or -1 if outside (obsolete)
virtual bool hasBooleanProperty(int ireg, EGS_BPType prop) const
Is the boolean property prop set for region ireg ?
virtual EGS_Float howfarToOutside(int ireg, const EGS_Vector &x, const EGS_Vector &u)
virtual EGS_Float getBScaling(int ireg) const
Get the B field scaling factor in region ireg.
virtual void setBScaling(int start, int end, EGS_Float bf)
Set the B field scaling factor in regions.
void setMedia(EGS_Input *inp)
Set the media in the geometry from the input pointed to by inp.
virtual const string & getType() const =0
Get the geometry type.
virtual void getLabelRegions(const string &str, vector< int > &regs)
Get the list of all regions labeled with str.
virtual int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u, EGS_Float &t, int *newmed=0, EGS_Vector *normal=0)=0
Calculate the distance to a boundary from x along the direction u.
virtual bool isRealRegion(int ireg) const
Returnes true if ireg is a real region, false otherwise.
virtual bool isInside(const EGS_Vector &x)=0
Is the position x inside the geometry?
virtual EGS_Float getRelativeRho(int ireg) const
Get the relative mass density in region ireg.
virtual void setBooleanProperty(EGS_BPType prop)
Set the boolean properties of the entire geometry to prop.
virtual int getMaxStep() const
Returns the maximum number of steps through the geometry.
virtual int medium(int ireg) const
Returns the medium index in region ireg.
int regions() const
Returns the number of local regions in this geometry.
virtual void setRelativeRho(int start, int end, EGS_Float rho)
Set the relative mass density in regions.
virtual void printInfo() const
Print information about this geometry.
virtual void addBooleanProperty(int bit)
Add a boolean property for the entire geometry by setting the bit'th bit.
virtual int isWhere(const EGS_Vector &x)=0
In which region is poisition x?
EGS_Float a
The center-to-center distance to the nearest 12 neighbours.
Definition: egs_lattice.h:516
vector< EGS_Float > d
Don't redefine 4 dists in closestPoint each invocation.
Definition: egs_lattice.h:517
EGS_BaseGeometry * base
The geometry within which the sub geometry appears.
Definition: egs_lattice.h:512
EGS_Float gap
Translating the hexagonal lattice to xyz coordinate,.
Definition: egs_lattice.h:519
EGS_TransformedGeometry * sub
The sub geometry that could appear within base.
Definition: egs_lattice.h:513
int maxStep
The maximum number of steps.
Definition: egs_lattice.h:515
int ind
The region in base geom where we could encounter sub geom.
Definition: egs_lattice.h:514
string type
The geometry type.
Definition: egs_lattice.h:518
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
A Bravais, cubic, and hexagonal lattice geometry.
Definition: egs_lattice.h:146
EGS_TransformedGeometry * sub
The sub geometry that could appear within base.
Definition: egs_lattice.h:150
string type
The geometry type.
Definition: egs_lattice.h:154
EGS_BaseGeometry * base
The geometry within which the sub geometry appears.
Definition: egs_lattice.h:149
EGS_Float c
The center-to-center distance along x, y, and z.
Definition: egs_lattice.h:153
int maxStep
The maximum number of steps.
Definition: egs_lattice.h:152
int ind
The region in base geom where we could encounter sub geom.
Definition: egs_lattice.h:151
A transformed geometry.
A class representing 3D vectors.
Definition: egs_vector.h:57
EGS_Float y
y-component
Definition: egs_vector.h:62
EGS_Float z
z-component
Definition: egs_vector.h:63
EGS_Float x
x-component
Definition: egs_vector.h:61
EGS_BaseGeometry class header file.
const EGS_Float epsilon
The epsilon constant for floating point comparisons.
Definition: egs_functions.h:62