EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_vhp_geometry.h
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ voxelized human phantom geometry headers
5 # Copyright (C) 2015 National Research Council Canada
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: Iwan Kawrakow, 2008
25 #
26 # Contributors: Frederic Tessier
27 # Reid Townson
28 # Hubert Ho
29 #
30 ###############################################################################
31 #
32 # A "Voxelized Human Phantom" (VHP) geometry.
33 #
34 # Although a VHP geometry is just a XYZ geometry, due to the huge number of
35 # voxels one has to be more careful with memory use for media indices, etc.
36 # That's why this separate geometry implementation. With Richard Kramer's
37 # phantom data the implementation requires ~12 MB to hold all the organ data
38 # in memory. Richard's ASCII phantom data was also transformed into binary
39 # format with the result that loading them is almost instantaneous.
40 #
41 # For now the implementation only provides the macro geometry, i.e., no
42 # spongiosa micro matrices. Adding the micro matrices is the next step.
43 #
44 ###############################################################################
45 */
46 
47 
54 #ifndef EGS_ND_GEOMETRY_
55 #define EGS_ND_GEOMETRY_
56 
57 #ifdef WIN32
58 
59  #ifdef BUILD_VHP_DLL
60  #define EGS_VHP_EXPORT __declspec(dllexport)
61  #else
62  #define EGS_VHP_EXPORT __declspec(dllimport)
63  #endif
64  #define EGS_VHP_LOCAL
65 
66 #else
67 
68  #ifdef HAVE_VISIBILITY
69  #define EGS_VHP_EXPORT __attribute__ ((visibility ("default")))
70  #define EGS_VHP_LOCAL __attribute__ ((visibility ("hidden")))
71  #else
72  #define EGS_VHP_EXPORT
73  #define EGS_VHP_LOCAL
74  #endif
75 
76 #endif
77 
78 
79 #include "egs_base_geometry.h"
80 #include "egs_functions.h"
81 
82 #include <iostream>
83 #include <string>
84 
85 using namespace std;
86 
87 #ifndef SKIP_DOXYGEN
88 
92 struct EGS_VHP_LOCAL VHP_RowInfo {
93  unsigned short nbin;
94  unsigned short *pix;
95  unsigned char *org;
96  VHP_RowInfo() : nbin(0) {};
97  ~VHP_RowInfo() {
98  if (nbin > 0) {
99  delete [] pix;
100  delete [] org;
101  }
102  };
103  int getBin(int i) const {
104  int ml=0, mu=nbin;
105  while (mu - ml > 1) {
106  int mav = (ml+mu)/2;
107  if (i < pix[mav]) {
108  mu = mav;
109  }
110  else {
111  ml = mav;
112  }
113  }
114  return mu-1;
115  };
116  int getOrgan(int pixel) const {
117  return pixel < pix[0] || pixel >= pix[nbin] ? 0 : org[getBin(pixel)];
118  };
119  int getSize() const {
120  int result = sizeof(nbin) + sizeof(unsigned short *) +
121  sizeof(unsigned char *);
122  if (nbin > 0) result += nbin*sizeof(unsigned char) +
123  (nbin+1)*sizeof(unsigned short);
124  return result;
125  };
126  void readData(istream &in);
127 };
128 #endif
129 
130 #ifndef SKIP_DOXYGEN
131 
135 struct EGS_VHP_LOCAL VHP_SliceInfo {
136  unsigned short firstr;
137  unsigned short lastr;
138  VHP_RowInfo *rinfo;
139  VHP_SliceInfo() : rinfo(0) {};
140  ~VHP_SliceInfo() {
141  if (rinfo) {
142  delete [] rinfo;
143  }
144  };
145  void getSliceDimensions(int &nx, int &ny) {
146  ny = lastr+1;
147  nx = 0;
148  int nrow = lastr - firstr + 1;
149  for (int j=0; j<nrow; ++j) {
150  int ni = rinfo[j].pix[rinfo[j].nbin];
151  if (ni > nx) {
152  nx = ni;
153  }
154  }
155  };
156  int getOrgan(int row, int pixel) const {
157  return rinfo && row >= firstr && row <= lastr ?
158  rinfo[row-firstr].getOrgan(pixel) : 0;
159  };
160  int getSize() const {
161  int result = sizeof(firstr) + sizeof(lastr) +
162  sizeof(VHP_RowInfo *);
163  if (rinfo) {
164  int nrow = lastr-firstr+1;
165  for (int j=0; j<nrow; ++j) {
166  result += rinfo[j].getSize();
167  }
168  }
169  return result;
170  };
171  void readData(istream &in);
172 };
173 #endif
174 
175 #ifndef SKIP_DOXYGEN
176 
180 class EGS_VHP_LOCAL VHP_OrganData {
181 public:
182  VHP_OrganData(const char *fname, int slice_min=0, int slice_max=1000000);
183  ~VHP_OrganData();
184 
185  int nSlice() const {
186  return nslice;
187  };
188  int getOrgan(int islice, int i, int j) const {
189  return islice >= 0 && islice < nslice ?
190  slices[islice].getOrgan(i,j) : 0;
191  };
192  const VHP_SliceInfo &getVHP_SliceInfo(int j) const {
193  return slices[j];
194  };
195  const VHP_SliceInfo &operator[](int j) const {
196  return slices[j];
197  };
198  int getSize() const {
199  int result = sizeof(nslice) + sizeof(VHP_SliceInfo *);
200  if (nslice > 0) {
201  for (int j=0; j<nslice; ++j) {
202  result += slices[j].getSize();
203  }
204  }
205  return result;
206  };
207  void getPhantomDimensions(int &Nx, int &Ny, int &Nz) {
208  Nx = nx;
209  Ny = ny;
210  Nz = nslice;
211  };
212  void getVoxelSizes(EGS_Float &Dx, EGS_Float &Dy, EGS_Float &Dz) {
213  Dx = dx;
214  Dy = dy;
215  Dz = dz;
216  };
217  int getOrgan(int ireg) const {
218  int k = ireg/nxy;
219  if (k < 0 || k >= nslice) {
220  return 0;
221  }
222  int jj = ireg - k*nx*ny;
223  int j = jj/nx;
224  int i = jj - j*nx;
225  return getOrgan(k,j,i);
226  };
227 
228  bool isOK() const {
229  return ok;
230  };
231 
232 protected:
233  double dx, dy, dz;
234  VHP_SliceInfo *slices;
235  unsigned short nslice;
236  int nx, ny, nxy;
237  bool ok;
238 };
239 #endif
240 
241 #ifndef SKIP_DOXYGEN
242 
246 struct EGS_VHP_LOCAL EGS_VoxelInfo {
247  unsigned short ix, iy, iz;
248 };
249 #endif
250 
251 #ifndef SKIP_DOXYGEN
252 
256 class EGS_VHP_LOCAL EGS_VoxelGeometry {
257 
258 public:
259 
260  EGS_Float dx, dxi, xmin, xmax;
261  EGS_Float dy, dyi, ymin, ymax;
262  EGS_Float dz, dzi, zmin, zmax;
263  int nx, ny, nz, nxy;
264  int ix, iy, iz;
265 
266  static EGS_VoxelInfo *v;
267  static int nv;
268 
269  EGS_VoxelGeometry(int Nx, int Ny, int Nz,
270  EGS_Float Dx, EGS_Float Dy, EGS_Float Dz) :
271  dx(Dx), dxi(1/Dx), xmin(0), xmax(Dx*Nx),
272  dy(Dy), dyi(1/Dy), ymin(0), ymax(Dy*Ny),
273  dz(Dz), dzi(1/Dz), zmin(0), zmax(Dz*Nz),
274  nx(Nx), ny(Ny), nz(Nz), nxy(nx*ny) {};
275 
276  ~EGS_VoxelGeometry() {
277  if (v) {
278  delete [] v;
279  v = 0;
280  nv = 0;
281  }
282  };
283 
284  bool isInside(const EGS_Vector &x) {
285  return (x.x >= xmin && x.x <= xmax &&
286  x.y >= ymin && x.y <= ymax &&
287  x.z >= zmin && x.z <= zmax) ? true : false;
288  };
289 
290  void setIndeces(const EGS_Vector &x) {
291  ix = (int)(x.x*dxi);
292  if (ix >= nx) {
293  ix = nx-1;
294  }
295  iy = (int)(x.y*dyi);
296  if (iy >= ny) {
297  iy = ny-1;
298  }
299  iz = (int)(x.z*dzi);
300  if (iz >= nz) {
301  iz = nz-1;
302  }
303  };
304 
305  int isWhere(const EGS_Vector &x) {
306  if (!isInside(x)) {
307  return -1;
308  }
309  setIndeces(x);
310  return ix + iy*nx + iz*nxy;
311  };
312 
313  int isWhereFast(const EGS_Vector &x) {
314  setIndeces(x);
315  return ix + iy*nx + iz*nxy;
316  };
317 
318  int computeIntersections(int ireg, int n, const EGS_Vector &X,
319  const EGS_Vector &u, EGS_GeometryIntersections *isections) {
320  if (n < 1) {
321  return -1;
322  }
323  if (nv < n) {
324  if (nv > 0) {
325  delete [] v;
326  }
327  v = new EGS_VoxelInfo [n];
328  nv = n;
329  }
330  int ifirst = 0;
331  EGS_Float t;
332  EGS_Vector x(X);
333  if (ireg < 0) {
334  t = veryFar;
335  ireg = howfar(ireg,x,u,t);
336  if (ireg < 0) {
337  return 0;
338  }
339  isections[0].t = t;
340  isections[0].rhof = 1;
341  isections[0].ireg = -1;
342  isections[0].imed = -1;
343  ++ifirst;
344  x += u*t;
345  }
346  int iz = ireg/nxy;
347  int ir = ireg - iz*nxy;
348  int iy = ir/nx;
349  int ix = ir - iy*nx;
350  EGS_Float uxi, uyi, uzi, nextx, nexty, nextz, sx, sy, sz;
351  int dirx, diry, dirz;
352  if (u.x > 0) {
353  uxi = 1/u.x;
354  dirx = 1;
355  nextx = (dx*(ix+1)-x.x)*uxi;
356  sx = uxi*dx;
357  }
358  else if (u.x < 0) {
359  uxi = 1/u.x;
360  dirx = -1;
361  nextx = (dx*ix-x.x)*uxi;
362  sx = -uxi*dx;
363  }
364  else {
365  dirx = 1;
366  nextx = veryFar*1e3;
367  sx = veryFar*1e3;
368  }
369  if (u.y > 0) {
370  uyi = 1/u.y;
371  diry = 1;
372  nexty = (dy*(iy+1)-x.y)*uyi;
373  sy = uyi*dy;
374  }
375  else if (u.y < 0) {
376  uyi = 1/u.y;
377  diry = -1;
378  nexty = (dy*iy-x.y)*uyi;
379  sy = -uyi*dy;
380  }
381  else {
382  diry = 1;
383  nexty = veryFar*1e3;
384  sy = veryFar*1e3;
385  }
386  if (u.z > 0) {
387  uzi = 1/u.z;
388  dirz = 1;
389  nextz = (dz*(iz+1)-x.z)*uzi;
390  sz = uzi*dz;
391  }
392  else if (u.z < 0) {
393  uzi = 1/u.z;
394  dirz = -1;
395  nextz = (dz*iz-x.z)*uzi;
396  sz = -uzi*dz;
397  }
398  else {
399  dirz = 1;
400  nextz = veryFar*1e3;
401  sz = veryFar*1e3;
402  }
403  for (int j=ifirst; j<n; j++) {
404  isections[j].ireg = ireg;
405  v[j].ix = ix;
406  v[j].iy = iy;
407  v[j].iz = iz;
408  int inew;
409  if (nextx < nexty && nextx < nextz) {
410  t = nextx;
411  ix += dirx;
412  if (ix < 0 || ix >= nx) {
413  inew = -1;
414  }
415  else {
416  inew = ireg + dirx;
417  nextx += sx;
418  }
419  }
420  else if (nexty < nextz) {
421  t = nexty;
422  iy += diry;
423  if (iy < 0 || iy >= ny) {
424  inew = -1;
425  }
426  else {
427  inew = ireg + nx*diry;
428  nexty += sy;
429  }
430  }
431  else {
432  t = nextz;
433  iz += dirz;
434  if (iz < 0 || iz >= nz) {
435  inew = -1;
436  }
437  else {
438  inew = ireg + nxy*dirz;
439  nextz += sz;
440  }
441  }
442  isections[j].t = t;
443  if (inew < 0) {
444  return j+1;
445  }
446  }
447  return ireg >= 0 ? -1 : n;
448  };
449 
450  EGS_Float howfarToOutside(int ireg, const EGS_Vector &x,
451  const EGS_Vector &u) {
452  if (ireg < 0) {
453  return 0;
454  }
455  EGS_Float tx = u.x > 0 ? (xmax-x.x)/u.x :
456  u.x < 0 ? (xmin-x.x)/u.x : veryFar*1e5;
457  EGS_Float ty = u.y > 0 ? (ymax-x.y)/u.y :
458  u.y < 0 ? (ymin-x.y)/u.y : veryFar*1e5;
459  EGS_Float tz = u.z > 0 ? (zmax-x.z)/u.z :
460  u.z < 0 ? (zmin-x.z)/u.z : veryFar*1e5;
461  return tx < ty && tx < tz ? tx : ty < tz ? ty : tz;
462  };
463 
464  void setIndeces(int ireg) {
465  iz = ireg/nxy;
466  int ir = ireg - iz*nxy;
467  iy = ir/nx;
468  ix = ir - iy*nx;
469  };
470 
471  //int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
472  // EGS_Float &t, EGS_Vector *normal=0) {
473  // setIndeces(ireg);
474  // return howfar(ireg,ix,iy,iz,x,u,t,normal);
475  //};
476  int howfarIn(int ireg, int Ix, int Iy, int Iz, const EGS_Vector &x,
477  const EGS_Vector &u, EGS_Float &t, EGS_Vector *normal=0) {
478  ix = Ix;
479  iy = Iy;
480  iz = Iz;
481  return howfarIn(ireg,x,u,t,normal);
482  };
483 
484  int howfarIn(int ireg, const EGS_Vector &x, const EGS_Vector &u,
485  EGS_Float &t, EGS_Vector *normal=0) {
486  int ixs = ix, iys = iy;
487  int inew = ireg;
488  if (u.x > 0) {
489  EGS_Float d = (dx*(ix+1)-x.x)/u.x;
490  if (d <= t) {
491  t = d;
492  if ((++ix) < nx) {
493  inew = ireg + 1;
494  }
495  else {
496  inew = -1;
497  }
498  if (normal) {
499  *normal = EGS_Vector(-1,0,0);
500  }
501  }
502  }
503  else if (u.x < 0) {
504  EGS_Float d = (dx*ix-x.x)/u.x;
505  if (d <= t) {
506  t = d;
507  if ((--ix) >= 0) {
508  inew = ireg - 1;
509  }
510  else {
511  inew = -1;
512  }
513  if (normal) {
514  *normal = EGS_Vector(1,0,0);
515  }
516  }
517  }
518  if (u.y > 0) {
519  EGS_Float d = (dy*(iy+1)-x.y)/u.y;
520  if (d <= t) {
521  ix = ixs;
522  t = d;
523  if ((++iy) < ny) {
524  inew = ireg + nx;
525  }
526  else {
527  inew = -1;
528  }
529  if (normal) {
530  *normal = EGS_Vector(0,-1,0);
531  }
532  }
533  }
534  else if (u.y < 0) {
535  EGS_Float d = (dy*iy-x.y)/u.y;
536  if (d <= t) {
537  ix = ixs;
538  t = d;
539  if ((--iy) >= 0) {
540  inew = ireg - nx;
541  }
542  else {
543  inew = -1;
544  }
545  if (normal) {
546  *normal = EGS_Vector(0,1,0);
547  }
548  }
549  }
550  if (u.z > 0) {
551  EGS_Float d = (dz*(iz+1)-x.z)/u.z;
552  if (d <= t) {
553  ix = ixs;
554  iy = iys;
555  t = d;
556  if ((++iz) < nz) {
557  inew = ireg+nxy;
558  }
559  else {
560  inew = -1;
561  }
562  if (normal) {
563  *normal = EGS_Vector(0,0,-1);
564  }
565  }
566  }
567  else if (u.z < 0) {
568  EGS_Float d = (dz*iz-x.z)/u.z;
569  if (d <= t) {
570  ix = ixs;
571  iy = iys;
572  t = d;
573  if ((--iz) >= 0) {
574  inew = ireg-nxy;
575  }
576  else {
577  inew = -1;
578  }
579  if (normal) {
580  *normal = EGS_Vector(0,0,1);
581  }
582  }
583  }
584  return inew;
585  };
586 
587  int howfarOut(const EGS_Vector &x, const EGS_Vector &u,
588  EGS_Float &t, EGS_Vector *normal=0) {
589  EGS_Float tlong = 2*t, d;
590  if (x.x <= xmin && u.x > 0) {
591  ix = 0;
592  d = (xmin-x.x)/u.x;
593  }
594  else if (x.x >= xmax && u.x < 0) {
595  ix = nx-1;
596  d = (xmax-x.x)/u.x;
597  }
598  else {
599  d = tlong;
600  }
601  if (d <= t) {
602  EGS_Float yy = x.y + u.y*d, zz = x.z + u.z*d;
603  if (yy >= ymin && yy <= ymax && zz >= zmin && zz <= zmax) {
604  t = d;
605  iy = (int)(yy*dyi);
606  if (iy > ny-1) {
607  iy = ny-1;
608  }
609  iz = (int)(zz*dzi);
610  if (iz > nz-1) {
611  iz = nz-1;
612  }
613  if (normal) *normal = ix == 0 ? EGS_Vector(-1,0,0) :
614  EGS_Vector(1,0,0);
615  return ix + iy*nx + iz*nxy;
616  }
617  }
618  if (x.y <= ymin && u.y > 0) {
619  iy = 0;
620  d = (ymin-x.y)/u.y;
621  }
622  else if (x.y >= ymax && u.y < 0) {
623  iy = ny-1;
624  d = (ymax-x.y)/u.y;
625  }
626  else {
627  d = tlong;
628  }
629  if (d <= t) {
630  EGS_Float xx = x.x + u.x*d, zz = x.z + u.z*d;
631  if (xx >= xmin && xx <= xmax && zz >= zmin && zz <= zmax) {
632  t = d;
633  ix = (int)(xx*dxi);
634  if (ix > nx-1) {
635  ix = nx-1;
636  }
637  iz = (int)(zz*dzi);
638  if (iz > nz-1) {
639  iz = nz-1;
640  }
641  if (normal) *normal = iy == 0 ? EGS_Vector(0,-1,0) :
642  EGS_Vector(0,1,0);
643  return ix + iy*nx + iz*nxy;
644  }
645  }
646  if (x.z <= zmin && u.z > 0) {
647  iz = 0;
648  d = (zmin-x.z)/u.z;
649  }
650  else if (x.z >= zmax && u.z < 0) {
651  iz = nz-1;
652  d = (zmax-x.z)/u.z;
653  }
654  else {
655  d = tlong;
656  }
657  if (d <= t) {
658  EGS_Float xx = x.x + u.x*d, yy = x.y + u.y*d;
659  if (xx >= xmin && xx <= xmax && yy >= ymin && yy <= ymax) {
660  t = d;
661  ix = (int)(xx*dxi);
662  if (ix > nx-1) {
663  ix = nx-1;
664  }
665  iy = (int)(yy*dyi);
666  if (iy > ny-1) {
667  iy = ny-1;
668  }
669  if (normal) *normal = iz == 0 ? EGS_Vector(0,0,-1) :
670  EGS_Vector(0,0,1);
671  return ix + iy*nx + iz*nxy;
672  }
673  }
674  return -1;
675  };
676 
677  int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
678  EGS_Float &t, EGS_Vector *normal=0) {
679  if (ireg >= 0) {
680  setIndeces(ireg);
681  return howfarIn(ireg,x,u,t,normal);
682  }
683  return howfarOut(x,u,t,normal);
684  };
685 
686  EGS_Float hownearIn(int Ix, int Iy, int Iz, const EGS_Vector &x) {
687  ix = Ix;
688  iy = Iy;
689  iz = Iz;
690  return hownearIn(x);
691  };
692 
693  EGS_Float hownearIn(const EGS_Vector &x) {
694  EGS_Float t1,t2,tx,ty,tz;
695  t1 = x.x-dx*ix;
696  t2 = dx - t1;
697  tx = t1 < t2 ? t1 : t2;
698  t1 = x.y-dy*iy;
699  t2 = dy - t1;
700  ty = t1 < t2 ? t1 : t2;
701  t1 = x.z-dz*iz;
702  t2 = dz - t1;
703  tz = t1 < t2 ? t1 : t2;
704  return tx < ty && tx < tz ? tx : ty < tz ? ty : tz;
705  };
706 
707  EGS_Float hownear(int ireg, const EGS_Vector &x) {
708  if (ireg >= 0) {
709  setIndeces(ireg);
710  return hownearIn(x);
711  }
712  int nc = 0;
713  EGS_Float s1=0, s2=0;
714  if (x.x < xmin || x.x > xmax) {
715  EGS_Float t = x.x < xmin ? xmin-x.x : x.x-xmax;
716  nc++;
717  s1 += t;
718  s2 += t*t;
719  }
720  if (x.y < ymin || x.y > ymax) {
721  EGS_Float t = x.y < ymin ? ymin-x.y : x.y-ymax;
722  nc++;
723  s1 += t;
724  s2 += t*t;
725  }
726  if (x.z < zmin || x.z > zmax) {
727  EGS_Float t = x.z < zmin ? zmin-x.z : x.z-zmax;
728  nc++;
729  s1 += t;
730  s2 += t*t;
731  }
732  return nc == 1 ? s1 : sqrt(s2);
733  };
734 };
735 #endif
736 
737 #ifndef SKIP_DOXYGEN
738 
742 struct VHPBox {
743  EGS_Float xmin, xmax;
744  EGS_Float ymin, ymax;
745  EGS_Float zmin, zmax;
746  bool isInside(const EGS_Vector &x) {
747  return
748  (x.x>=xmin&&x.x<=xmax&&x.y>=ymin&&ymax<=ymin&&x.z>=zmin&&x.z<=zmax);
749  };
750  bool willEnter(const EGS_Vector &x, const EGS_Vector &u, EGS_Float &t) {
751  EGS_Float tlong = 2*t, d;
752  if (x.x <= xmin && u.x > 0) {
753  d = (xmin-x.x)/u.x;
754  }
755  else if (x.x >= xmax && u.x < 0) {
756  d = (xmax-x.x)/u.x;
757  }
758  else {
759  d = tlong;
760  }
761  if (d <= t) {
762  EGS_Float yy = x.y + u.y*d, zz = x.z + u.z*d;
763  if (yy >= ymin && yy <= ymax && zz >= zmin && zz <= zmax) {
764  t = d;
765  return true;
766  }
767  }
768  if (x.y <= ymin && u.y > 0) {
769  d = (ymin-x.y)/u.y;
770  }
771  else if (x.y >= ymax && u.y < 0) {
772  d = (ymax-x.y)/u.y;
773  }
774  else {
775  d = tlong;
776  }
777  if (d <= t) {
778  EGS_Float xx = x.x + u.x*d, zz = x.z + u.z*d;
779  if (xx >= xmin && xx <= xmax && zz >= zmin && zz <= zmax) {
780  t = d;
781  return true;
782  }
783  }
784  if (x.z <= zmin && u.z > 0) {
785  d = (zmin-x.z)/u.z;
786  }
787  else if (x.z >= zmax && u.z < 0) {
788  d = (zmax-x.z)/u.z;
789  }
790  else {
791  d = tlong;
792  }
793  if (d <= t) {
794  EGS_Float xx = x.x + u.x*d, yy = x.y + u.y*d;
795  if (xx >= xmin && xx <= xmax && yy >= ymin && yy <= ymax) {
796  t = d;
797  return true;
798  }
799  }
800  return false;
801  };
802  EGS_Float howfarToOut(const EGS_Vector &x, const EGS_Vector &u) {
803  EGS_Float t = veryFar*1e5, t1;
804  if (u.x > 0) {
805  t1 = (xmax-x.x)/u.x;
806  if (t1 < t) {
807  t = t1;
808  }
809  }
810  else if (u.x < 0) {
811  t1 = (xmin-x.x)/u.x;
812  if (t1 < t) {
813  t = t1;
814  }
815  }
816  if (u.y > 0) {
817  t1 = (ymax-x.y)/u.y;
818  if (t1 < t) {
819  t = t1;
820  }
821  }
822  else if (u.y < 0) {
823  t1 = (ymin-x.y)/u.y;
824  if (t1 < t) {
825  t = t1;
826  }
827  }
828  if (u.z > 0) {
829  t1 = (zmax-x.z)/u.z;
830  if (t1 < t) {
831  t = t1;
832  }
833  }
834  else if (u.z < 0) {
835  t1 = (zmin-x.z)/u.z;
836  if (t1 < t) {
837  t = t1;
838  }
839  }
840  return t;
841  };
842 };
843 #endif
844 
845 #ifndef SKIP_DOXYGEN
846 
850 class EGS_VHP_LOCAL EGS_MicroMatrixCluster {
851 
852 public:
853 
854  EGS_MicroMatrixCluster(EGS_Float Dx, EGS_Float Dy, EGS_Float Dz,
855  EGS_Float bsc_thickness, int tb_med, int bm_med,
856  const char *micro_file);
857 
858  ~EGS_MicroMatrixCluster();
859 
860 
861  int howfar(int imic, int ireg, int &lax, int &lay, int &laz, int &newmic,
862  const EGS_Vector &x, const EGS_Vector &u,
863  EGS_Float &t, int *newmed=0, EGS_Vector *normal=0) {
864  int inew = vg->howfar(ireg,x,u,t,normal);
865  newmic = imic;
866  if (inew < 0) {
867  int iz = imic/(mx*my);
868  int itmp = imic - iz*mx*my;
869  int iy = itmp/mx;
870  int ix = itmp - mx*iy;
871  if (vg->ix < 0) {
872  --lax;
873  if ((--ix) < 0) {
874  ix = mx-1;
875  }
876  }
877  else if (vg->ix >= vg->nx) {
878  ++lax;
879  if ((++ix) >= mx) {
880  ix = 0;
881  }
882  }
883  else if (vg->iy < 0) {
884  --lay;
885  if ((--iy) < 0) {
886  iy = my-1;
887  }
888  }
889  else if (vg->iy >= vg->ny) {
890  ++lay;
891  if ((++iy) >= my) {
892  iy = 0;
893  }
894  }
895  else if (vg->iz < 0) {
896  --laz;
897  if ((--iz) < 0) {
898  iz = mz-1;
899  }
900  }
901  else if (vg->iz >= vg->nz) {
902  ++laz;
903  if ((++iz) >= mz) {
904  iz = 0;
905  }
906  }
907  newmic = ix + iy*mx + iz*mx*my;
908  }
909  if (newmed) {
910  *newmed = micros[newmic][inew] ? med_bm : med_tb;
911  }
912  return inew;
913  };
914 
915  EGS_Float hownear(int ireg, const EGS_Vector &x) {
916  return vg->hownear(ireg,x);
917  };
918 
919  int medium(int imic, int ireg) const {
920  return micros[imic][ireg] ? med_bm : med_tb;
921  };
922 
923  int medium(int ireg) const {
924  int imic = ireg/nreg;
925  ireg -= imic*nreg;
926  return medium(imic,ireg);
927  };
928 
929  int isWhere(int &imic, const EGS_Vector &x) {
930  int ix = (int)(x.x*dxi), iy = (int)(x.y*dyi), iz = (int)(x.z*dzi);
931  EGS_Vector x1(x - EGS_Vector(dx*ix, dy*iy, dz*iz));
932  ix = ix%mx;
933  iy = iy%my;
934  iz = iz%mz;
935  imic = ix + iy*mx + iz*mz;
936  return vg->isWhere(x1);
937  };
938 
939  void getIndeces(int ireg, int &imic, int &ix, int &iy, int &iz) {
940  imic = ireg/nreg;
941  ireg -= imic*nreg;
942  iz = ireg/nxy;
943  iy = (ireg - iz*nxy)/nx;
944  ix = ireg - iz*nxy - iy*nx;
945  };
946 
947  int isWhere(int jx, int jy, int jz, const EGS_Vector &x1, int *newmed=0) {
948  int ix = jx%mx, iy = jy%my, iz = jz%mz;
949  int imic = ix + iy*mx + iz*mz;
950  int iloc = vg->isWhereFast(x1);
951  if (newmed) {
952  *newmed = medium(imic,iloc);
953  }
954  return imic*nreg + iloc;
955  };
956 
957  bool isValid() const {
958  return (vg && micros);
959  };
960 
961  void getStepFractions(int imic, int ireg,
962  const EGS_Vector &xi, const EGS_Vector &xf,
963  EGS_Float &bsc_step, EGS_Float &bm_step) {
964  bsc_step = 0;
965  bm_step = 0;
966  int mict = micros[imic][ireg];
967  if (mict) {
968  // a BM voxel => check step fractions
969  if (mict == 1) {
970  bsc_step = 1; // all BSC
971  }
972  else if (mict == 2) {
973  bm_step = 1; // all BM
974  }
975  else {
976  mict -= 2;
977  // get positions in bm_boxes co-ordinate system
978  int jz = ireg/nxy;
979  int jy = (ireg-jz*nxy)/nx;
980  int jx = ireg-jz*nxy-jy*nx;
981  EGS_Vector xcorner(vg->dx*jx,vg->dy*jy,vg->dz*jz);
982  EGS_Vector Xi(xi-xcorner), Xf(xf-xcorner);
983  bool i_inside = bm_boxes[mict].isInside(Xi),
984  f_inside = bm_boxes[mict].isInside(Xf);
985  // if both positions are inside the BM box, the entire step
986  // is in the BM box
987  if (i_inside && f_inside) {
988  bm_step = 1;
989  }
990  else {
991  // we have a fraction in BM and remainder in BSC
992  EGS_Vector u(Xf-Xi);
993  EGS_Float t = u.length();
994  EGS_Float ti = 1/t;
995  u *= ti;
996  if (!i_inside) {
997  // initial position outside of BM box => find entry
998  EGS_Float tt = t;
999  if (!bm_boxes[mict].willEnter(Xi,u,tt)) {
1000  // line Xi->Xf does not intersect BM box
1001  bsc_step = 1;
1002  return;
1003  }
1004  // move to entry point
1005  bsc_step = tt;
1006  Xi += u*tt;
1007  }
1008  if (f_inside) {
1009  // final position inside BM box. This implies initial
1010  // position was outside. Because we already computed
1011  // distance to BM box entry, the remainder goes to BM
1012  bsc_step *= ti;
1013  bm_step = 1 - bsc_step;
1014  return;
1015  }
1016  // final position outside. this means that either the
1017  // initial position was inside or that we moved to the
1018  // entry point => BM fraction is distance to outside
1019  bm_step = ti*bm_boxes[mict].howfarToOut(Xi,u);
1020  bsc_step = 1 - bm_step;
1021  }
1022  }
1023  }
1024  };
1025 
1026  void getVolumes(int imic, EGS_Float &tb, EGS_Float &bm, EGS_Float &bsc) {
1027  tb = v_tb[imic];
1028  bm = v_bm[imic];
1029  bsc = v_bsc[imic];
1030  };
1031 
1032 
1033  // ********************************************************************
1034 
1035  int nx, ny, nz, nxy, nreg;
1036  int mx, my, mz;
1037  int mxy, nmic;
1038  EGS_Float dx, dy, dz;
1039  EGS_Float dxi, dyi, dzi;
1040  EGS_Float t_bsc;
1041 
1042  int med_tb;
1043  int med_bm;
1044 
1052  unsigned char **micros;
1053  EGS_VoxelGeometry *vg;
1054  EGS_Float *v_tb;
1055  EGS_Float *v_bm;
1056  EGS_Float *v_bsc;
1057 
1058  static VHPBox bm_boxes[64];
1059  static bool bm_boxes_initialized;
1060 
1061 };
1062 #endif
1063 
1064 class EGS_VHP_EXPORT EGS_TestMicro : public EGS_BaseGeometry {
1065 
1066 public:
1067 
1068  EGS_TestMicro(EGS_Float Dx, EGS_Float Dy, EGS_Float Dz, EGS_Float bsc_t,
1069  int tb_med, int bm_med,const char *micro_file, const string &Name="");
1070 
1071  ~EGS_TestMicro();
1072 
1073  int inside(const EGS_Vector &x) {
1074  return isWhere(x);
1075  };
1076  bool isInside(const EGS_Vector &x) {
1077  return vg->isInside(x);
1078  }
1079  int isWhere(const EGS_Vector &x) {
1080  int ireg = vg->isWhere(x);
1081  if (ireg < 0) {
1082  return ireg;
1083  }
1084  EGS_Vector x1(x-EGS_Vector(vg->dx*vg->ix,vg->dy*vg->iy,vg->dz*vg->iz));
1085  int ix = vg->ix%micro->mx,
1086  iy = vg->iy%micro->my,
1087  iz = vg->iz%micro->mz;
1088  int imic = ix + iy*micro->mx + iz*micro->mxy;
1089  int iloc = micro->vg->isWhere(x1);
1090  return imic*nr + iloc;
1091  };
1092 
1093  int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
1094  EGS_Float &t, int *newmed=0, EGS_Vector *normal=0) {
1095  if (ireg >= 0) {
1096  int voxel = ireg/nr;
1097  int ilocal = ireg - voxel*nr;
1098  vg->setIndeces(voxel);
1099  EGS_Vector x1(x-EGS_Vector(vg->dx*vg->ix,vg->dy*vg->iy,vg->dz*vg->iz));
1100  int inew = micro->vg->howfar(ilocal,x1,u,t,normal);
1101  if (inew == ilocal) {
1102  return ireg;
1103  }
1104  if (inew < 0) {
1105  if (micro->vg->ix < 0) {
1106  if ((--vg->ix) < 0) {
1107  return -1;
1108  }
1109  micro->vg->ix = micro->vg->nx-1;
1110  }
1111  else if (micro->vg->ix >= micro->vg->nx) {
1112  if ((++vg->ix) >= vg->nx) {
1113  return -1;
1114  }
1115  micro->vg->ix = 0;
1116  }
1117  else if (micro->vg->iy < 0) {
1118  if ((--vg->iy) < 0) {
1119  return -1;
1120  }
1121  micro->vg->iy = micro->vg->ny-1;
1122  }
1123  else if (micro->vg->iy >= micro->vg->ny) {
1124  if ((++vg->iy) >= vg->ny) {
1125  return -1;
1126  }
1127  micro->vg->iy = 0;
1128  }
1129  else if (micro->vg->iz < 0) {
1130  if ((--vg->iz) < 0) {
1131  return -1;
1132  }
1133  micro->vg->iz = micro->vg->nz-1;
1134  }
1135  else if (micro->vg->iz >= micro->vg->nz) {
1136  if ((++vg->iz) >= vg->nz) {
1137  return -1;
1138  }
1139  micro->vg->iz = 0;
1140  }
1141  inew = micro->vg->ix + micro->vg->iy*micro->vg->nx +
1142  micro->vg->iz*micro->vg->nxy;
1143  }
1144  voxel = vg->ix + vg->iy*vg->nx + vg->iz*vg->nxy;
1145  if (newmed) {
1146  *newmed = micro->medium(voxel,inew);
1147  }
1148  return voxel*nr + inew;
1149  }
1150  int voxel = vg->howfar(ireg,x,u,t,normal);
1151  if (voxel < 0) {
1152  return voxel;
1153  }
1154  EGS_Vector x1(x + u*t);
1155  x1 -= EGS_Vector(vg->dx*vg->ix,vg->dy*vg->iy,vg->dz*vg->iz);
1156  int ilocal = micro->vg->isWhereFast(x1);
1157  if (ilocal < 0) {
1158  egsFatal("x=(%g,%g,%g) x+u*t=(%g,%g,%g) x1=(%g,%g,%g)\n",x.x,x.y,x.z,(x+u*t).x,(x+u*t).y,(x+u*t).z,x1.x,x1.y,x1.z);
1159  }
1160  if (newmed) {
1161  *newmed = micro->medium(voxel,ilocal);
1162  }
1163  return voxel*nr + ilocal;
1164  };
1165 
1166  EGS_Float howfarToOutside(int ireg, const EGS_Vector &x,
1167  const EGS_Vector &u) {
1168  return vg->howfarToOutside(ireg,x,u);
1169  };
1170 
1171  EGS_Float hownear(int ireg, const EGS_Vector &x) {
1172  if (ireg < 0) {
1173  return vg->hownear(ireg,x);
1174  }
1175  int voxel = ireg/nr;
1176  int ilocal = ireg - voxel*nr;
1177  vg->setIndeces(voxel);
1178  EGS_Vector x1(x-EGS_Vector(vg->dx*vg->ix,vg->dy*vg->iy,vg->dz*vg->iz));
1179  return micro->vg->hownear(ilocal,x1);
1180  };
1181 
1182  int medium(int ireg) const {
1183  int voxel = ireg/nr;
1184  int ilocal = ireg - voxel*nr;
1185  return micro->medium(voxel,ilocal);
1186  };
1187 
1188  int getMaxStep() const {
1189  return micro->mx*micro->nx + micro->my*micro->ny +
1190  micro->mz*micro->nz + 1;
1191  };
1192 
1193  const string &getType() const {
1194  return type;
1195  };
1196 
1197 protected:
1198 
1199  EGS_VoxelGeometry *vg;
1200  EGS_MicroMatrixCluster *micro;
1201  int nr;
1202 
1203  void setMedia(EGS_Input *inp, int nmed, const int *med_ind);
1204 
1205  static string type;
1206 };
1207 
1303 class EGS_VHP_EXPORT EGS_VHPGeometry : public EGS_BaseGeometry {
1304 
1305 public:
1306 
1307  EGS_VHPGeometry(const char *phantom_file, const char *media_file,
1308  int slice_min=0, int slice_max=1000000, const string &Name="");
1309 
1310  ~EGS_VHPGeometry();
1311 
1312  bool isInside(const EGS_Vector &x) {
1313  return vg->isInside(x);
1314  };
1315 
1316  int isWhere(const EGS_Vector &x) {
1317  int ireg = vg->isWhere(x);
1318  if (!nmicro) {
1319  return ireg;
1320  }
1321  int iorg = organs->getOrgan(vg->iz,vg->iy,vg->ix);
1322  int mict = organ_micro[iorg];
1323  if (mict < 0) {
1324  return ireg; // i.e., no micros in this macro voxel
1325  }
1326  EGS_Vector x1(x - EGS_Vector(vg->dx*vg->ix,vg->dy*vg->iy,vg->dz*vg->iz));
1327  int micr = micros[mict]->isWhere(vg->ix,vg->iy,vg->iz,x1);
1328  return nmax*mict + micr + nmacro;
1329  };
1330 
1331  int inside(const EGS_Vector &x) {
1332  return isWhere(x);
1333  };
1334 
1335  int medium(int ireg) const {
1336  if (ireg < nmacro) {
1337  return organ_media[organs->getOrgan(ireg)];
1338  }
1339  ireg -= nmacro;
1340  int mict = ireg/nmax;
1341  int iloc = ireg - mict*nmax;
1342  return micros[mict]->medium(iloc);
1343  };
1344 
1345  int computeIntersections(int ireg, int n, const EGS_Vector &X,
1346  const EGS_Vector &u, EGS_GeometryIntersections *isections) {
1347  // fix the following
1348  if (nmicro > 0) return EGS_BaseGeometry::computeIntersections(ireg,
1349  n,X,u,isections);
1350  if (n < 1) {
1351  return -1;
1352  }
1353  int result = vg->computeIntersections(ireg,n,X,u,isections);
1354  if (!result) {
1355  return result; // no intersections
1356  }
1357  int nloop = result > 0 ? result : n;
1358  int first = isections[0].ireg >= 0 ? 0 : 1;
1359  EGS_VoxelInfo *v = vg->v;
1360  for (int j=first; j<nloop; ++j) isections[j].imed =
1361  organ_media[organs->getOrgan(v[j].iz,v[j].iy,v[j].ix)];
1362  return result;
1363  };
1364 
1365  EGS_Float howfarToOutside(int ireg, const EGS_Vector &x,
1366  const EGS_Vector &u) {
1367  return vg->howfarToOutside(ireg,x,u);
1368  };
1369 
1370  int howfar(int ireg, const EGS_Vector &x, const EGS_Vector &u,
1371  EGS_Float &t, int *newmed=0, EGS_Vector *normal=0) {
1372  if (nmicro < 1) { // no micro matrices
1373  int inew = vg->howfar(ireg,x,u,t,normal);
1374  if (newmed && inew >= 0 && inew != ireg) {
1375  *newmed = organ_media[organs->getOrgan(vg->iz,vg->iy,vg->ix)];
1376  }
1377  return inew;
1378  }
1379  if (ireg >= 0 && ireg < nmacro) {
1380  // in macro matrix
1381  int inew = vg->howfar(ireg,x,u,t,normal);
1382  if (t < 0) {
1383  if (t < -boundaryTolerance) {
1384  egsWarning("negative step %g in macro voxel\n",t);
1385  egsWarning("x=(%g,%g,%g) u=(%g,%g,%g)\n",x.x,x.y,x.z,
1386  u.x,u.y,u.z);
1387  egsWarning("ix=%d iy=%d iz=%d\n",vg->ix,vg->iy,vg->iz);
1388  egsFatal("quitting\n");
1389  }
1390  t = boundaryTolerance;
1391  }
1392  if (inew < 0 || inew == ireg) {
1393  return inew;
1394  }
1395  // i.e., exits macro geometry or stays in same macro voxel
1396  int iorg = organs->getOrgan(vg->iz,vg->iy,vg->ix);
1397  int mict = organ_micro[iorg];
1398  if (mict < 0) { // no micro matrix in the new macro voxel
1399  if (newmed) {
1400  *newmed = organ_media[iorg];
1401  }
1402  return inew;
1403  }
1404  // if here, enters micro matrix.
1405  EGS_Vector x1(x + u*t -
1406  EGS_Vector(vg->dx*vg->ix,vg->dy*vg->iy,vg->dz*vg->iz));
1407  int micr = micros[mict]->isWhere(vg->ix,vg->iy,vg->iz,x1,newmed);
1408  return nmax*mict + micr + nmacro;
1409  }
1410  if (ireg >= 0) {
1411  // in a micro matrix.
1412  int ireg1 = ireg - nmacro;
1413  int mict = ireg1/nmax;
1414  int iloc = ireg1 - mict*nmax;
1415  //return micros[mict]->medium(iloc);
1416  int imic, ix, iy, iz;
1417  EGS_MicroMatrixCluster *micro = micros[mict];
1418  micro->getIndeces(iloc,imic,ix,iy,iz);
1419  int ilocal = iloc - imic*micros[mict]->nreg;
1420  // now we have to figure out the macro voxel indeces
1421  // in principle one could simply use vg->isWhere(x), but
1422  // this is bound to get us in trouble with roundoff errors.
1423  // we therefore treat the special case where x is in an edge
1424  // voxel of the micro matrix in a special way
1425  int lax, lay, laz;
1426  EGS_Float aux = x.x*vg->dxi;
1427  if (ix > 0 && ix < micros[mict]->vg->nx-1) {
1428  lax = (int) aux;
1429  }
1430  else if (ix == 0) {
1431  lax = (int)(aux+0.5);
1432  }
1433  else {
1434  lax = (int)(aux-0.5);
1435  }
1436  aux = x.y*vg->dyi;
1437  if (iy > 0 && iy < micros[mict]->vg->ny-1) {
1438  lay = (int) aux;
1439  }
1440  else if (iy == 0) {
1441  lay = (int)(aux+0.5);
1442  }
1443  else {
1444  lay = (int)(aux-0.5);
1445  }
1446  aux = x.z*vg->dzi;
1447  if (iz > 0 && iz < micros[mict]->vg->nz-1) {
1448  laz = (int) aux;
1449  }
1450  else if (iz == 0) {
1451  laz = (int)(aux+0.5);
1452  }
1453  else {
1454  laz = (int)(aux-0.5);
1455  }
1456  EGS_Vector x1(x - EGS_Vector(vg->dx*lax,vg->dy*lay,vg->dz*laz));
1457  int inew = micro->vg->howfarIn(ilocal,ix,iy,iz,x1,u,t,normal);
1458  if (t < 0) {
1459  if (t < -boundaryTolerance) {
1460  egsWarning("negative step %g in micro matrix\n",t);
1461  egsWarning("x=(%g,%g,%g) u=(%g,%g,%g)\n",x.x,x.y,x.z,
1462  u.x,u.y,u.z);
1463  egsWarning("ix=%d iy=%d iz=%d\n",ix,iy,iz);
1464  egsWarning("lax=%d lay=%d laz=%d\n",lax,lay,laz);
1465  egsWarning("x1=(%g,%g,%g)\n",x1.x,x1.y,x1.z);
1466  egsFatal("quitting\n");
1467  }
1468  t = 0;
1469  }
1470  if (inew == ilocal) {
1471  return ireg;
1472  }
1473  if (inew < 0) {
1474  // exiting current micro matrix => entering new
1475  // macro voxel.
1476  // 1. find which one and set new micro region
1477  if (micro->vg->ix < 0) {
1478  if ((--lax) < 0) {
1479  return -1;
1480  }
1481  micro->vg->ix = micro->vg->nx-1;
1482  }
1483  else if (micro->vg->ix >= micro->vg->nx) {
1484  if ((++lax) >= vg->nx) {
1485  return -1;
1486  }
1487  micro->vg->ix = 0;
1488  }
1489  else if (micro->vg->iy < 0) {
1490  if ((--lay) < 0) {
1491  return -1;
1492  }
1493  micro->vg->iy = micro->vg->ny-1;
1494  }
1495  else if (micro->vg->iy >= micro->vg->ny) {
1496  if ((++lay) >= vg->ny) {
1497  return -1;
1498  }
1499  micro->vg->iy = 0;
1500  }
1501  else if (micro->vg->iz < 0) {
1502  if ((--laz) < 0) {
1503  return -1;
1504  }
1505  micro->vg->iz = micro->vg->nz-1;
1506  }
1507  else if (micro->vg->iz >= micro->vg->nz) {
1508  if ((++laz) >= vg->nz) {
1509  return -1;
1510  }
1511  micro->vg->iz = 0;
1512  }
1513  // 2. micro matrix in new macro voxel?
1514  int iorg = organs->getOrgan(laz,lay,lax);
1515  mict = organ_micro[iorg];
1516  if (mict < 0) { // no.
1517  if (newmed) {
1518  *newmed = organ_media[iorg];
1519  }
1520  return lax + lay*vg->nx + laz*vg->nxy;
1521  }
1522  inew = micro->vg->ix + micro->vg->iy*micro->vg->nx +
1523  micro->vg->iz*micro->vg->nxy;
1524  int lix = lax%micros[mict]->mx;
1525  int liy = lay%micros[mict]->my;
1526  int liz = laz%micros[mict]->mz;
1527  imic = lix + micros[mict]->mx*liy + micros[mict]->mxy*liz;
1528  }
1529  if (newmed) {
1530  *newmed = micros[mict]->medium(imic,inew);
1531  }
1532  return nmax*mict + inew + nmacro;
1533  }
1534  // outside
1535  int imac = vg->howfarOut(x,u,t,normal);
1536  if (imac < 0) {
1537  return imac;
1538  }
1539  int iorg = organs->getOrgan(vg->iz,vg->iy,vg->ix);
1540  int mict = organ_micro[iorg];
1541  if (mict < 0) {
1542  if (newmed) {
1543  *newmed = organ_media[iorg];
1544  }
1545  return imac;
1546  }
1547  EGS_Vector x1(x + u*t);
1548  x1 -= EGS_Vector(vg->dx*vg->ix,vg->dy*vg->iy,vg->dz*vg->iz);
1549  int ilocal = micros[mict]->vg->isWhereFast(x1);
1550  int ix=vg->ix%micros[mict]->mx,
1551  iy=vg->iy%micros[mict]->my,
1552  iz=vg->iz%micros[mict]->mz;
1553  int imic = ix + iy*micros[mict]->mx + iz*micros[mict]->mxy;
1554  if (newmed) {
1555  *newmed = micros[mict]->medium(imic,ilocal);
1556  }
1557  return nmax*mict + imic*micros[mict]->nreg + ilocal + nmacro;
1558  };
1559 
1560  EGS_Float hownear(int ireg, const EGS_Vector &x) {
1561  if (ireg < nmacro) {
1562  return vg->hownear(ireg,x);
1563  }
1564  ireg -= nmacro;
1565  int mict = ireg/nmax;
1566  int iloc = ireg - mict*nmax;
1567  int imic, ix, iy, iz;
1568  EGS_MicroMatrixCluster *micro = micros[mict];
1569  micro->getIndeces(iloc,imic,ix,iy,iz);
1570  // now we have to figure out the macro voxel indeces
1571  // in principle one could simply use vg->isWhere(x), but
1572  // this is bound to get us in trouble with roundoff errors.
1573  // we therefore treat the special case where x is in an edge
1574  // voxel of the micro matrix in a special way
1575  int lax, lay, laz;
1576  EGS_Float aux = x.x*vg->dxi;
1577  if (ix > 0 && ix < micro->vg->nx-1) {
1578  lax = (int) aux;
1579  }
1580  else if (ix == 0) {
1581  lax = (int)(aux+0.5);
1582  }
1583  else {
1584  lax = (int)(aux-0.5);
1585  }
1586  aux = x.y*vg->dyi;
1587  if (iy > 0 && iy < micro->vg->ny-1) {
1588  lay = (int) aux;
1589  }
1590  else if (iy == 0) {
1591  lay = (int)(aux+0.5);
1592  }
1593  else {
1594  lay = (int)(aux-0.5);
1595  }
1596  aux = x.z*vg->dzi;
1597  if (iz > 0 && iz < micro->vg->nz-1) {
1598  laz = (int) aux;
1599  }
1600  else if (iz == 0) {
1601  laz = (int)(aux+0.5);
1602  }
1603  else {
1604  laz = (int)(aux-0.5);
1605  }
1606  EGS_Vector x1(x - EGS_Vector(vg->dx*lax,vg->dy*lay,vg->dz*laz));
1607  return micro->vg->hownearIn(ix,iy,iz,x1);
1608  };
1609 
1610  int getMaxStep() const {
1611  if (!nmicro) {
1612  return vg->nx+vg->ny+vg->nz+1;
1613  }
1614  int nmx=0, nmy=0, nmz=0;
1615  for (int mict=0; mict<nmicro; ++mict) {
1616  if (micros[mict]->nx > nmx) {
1617  nmx = micros[mict]->nx;
1618  }
1619  if (micros[mict]->ny > nmy) {
1620  nmy = micros[mict]->ny;
1621  }
1622  if (micros[mict]->nx > nmz) {
1623  nmx = micros[mict]->nz;
1624  }
1625  }
1626  return vg->nx*nmx+vg->ny*nmy+vg->nz*nmz+1;
1627  };
1628 
1629  bool isOK() const {
1630  return (vg && organs);
1631  };
1632 
1633  int getNx() const {
1634  return vg->nx;
1635  };
1636  int getNy() const {
1637  return vg->ny;
1638  };
1639  int getNz() const {
1640  return vg->nz;
1641  };
1642 
1643  const string &getType() const {
1644  return type;
1645  };
1646 
1647  void printInfo() const;
1648 
1649  //static EGS_VHPGeometry* createGeometry(EGS_Input *);
1650  void setMicros(EGS_Input *);
1651 
1652 protected:
1653 
1654  EGS_VoxelGeometry *vg;
1655  VHP_OrganData *organs;
1656 
1657  int organ_media[256];
1658  int organ_micro[256];
1659  string organ_names[256];
1660  EGS_MicroMatrixCluster **micros;
1661  int nmicro;
1662  int nmax, nmacro;
1663 
1664  static string type;
1665 
1666  void setup();
1667 
1668  void setMedia(EGS_Input *inp, int nmed, const int *med_ind);
1669 
1670 };
1671 
1672 #endif
EGS_Float t
distance to next region boundary
EGS_Float rhof
relative mass density in that region
EGS_Float y
y-component
Definition: egs_vector.h:61
A class representing 3D vectors.
Definition: egs_vector.h:56
Global egspp functions header file.
const EGS_Float veryFar
A very large float.
EGS_I32 imed
medium index
Base geometry class. Every geometry class must be derived from EGS_BaseGeometry.
EGS_Float z
z-component
Definition: egs_vector.h:62
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
A Voxelized Human Phantom (VHP) geometry.
virtual int computeIntersections(int ireg, int n, const EGS_Vector &x, const EGS_Vector &u, EGS_GeometryIntersections *isections)
Calculates intersection distances to region boundaries.
int nr
number of voxels in a micro-matrix
EGS_Float x
x-component
Definition: egs_vector.h:60
EGS_I32 ireg
region index
A class for storing information in a tree-like structure of key-value pairs. This class is used throu...
Definition: egs_input.h:182
EGS_BaseGeometry class header file.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.