EGSnrc C++ class library  Report PIRS-898 (2021)
Iwan Kawrakow, Ernesto Mainegra-Hing, Frederic Tessier, Reid Townson and Blake Walters
egs_dynamic_shape.cpp
Go to the documentation of this file.
1 /*
2 ###############################################################################
3 #
4 # EGSnrc egs++ dynamic shape
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: Reid Townson
25 #
26 # Contributors:
27 #
28 ###############################################################################
29 */
30 
31 
37 #include "egs_dynamic_shape.h"
38 #include "egs_input.h"
39 #include "egs_functions.h"
40 #include <sstream>
41 
42 extern "C" {
43 
44  EGS_DYNAMIC_SHAPE_EXPORT EGS_BaseShape *createShape(EGS_Input *input,
45  EGS_ObjectFactory *f) {
46  if (!input) {
47  egsWarning("createShape(dynamic shape): null input?\n");
48  return 0;
49  }
50  EGS_Input *ishape = input->takeInputItem("shape",false);
51  EGS_BaseShape *shape=0;;
52  if (ishape) {
53  shape = EGS_BaseShape::createShape(ishape);
54  delete ishape;
55  }
56  if (!shape) {
57  string shape_name;
58  int err = input->getInput("shape name",shape_name);
59  if (err) {
60  egsWarning("createShape(dynamic shape): no inline shape definition"
61  " and no 'shape name' keyword\n");
62  return 0;
63  }
64  shape = EGS_BaseShape::getShape(shape_name);
65  if (!shape) {
66  egsWarning("createShape(dynamic shape): no shape named %s "
67  "exists\n",shape_name.c_str());
68  return 0;
69  }
70  }
71 
72  // Now getting motion information for dynamic component
73  EGS_Input *dyninp = input->takeInputItem("motion");
74 
75  if (dyninp) {
76  EGS_DynamicShape *s = new EGS_DynamicShape(shape, dyninp, "", f);
77  s->setName(input);
78  return s;
79  }
80  else {
81  egsWarning("EGS_DynamicShape: no control points input.\n");
82  return 0;
83  }
84  }
85 
87  stringstream itos;
88  ncpts=0;
89  vector<EGS_Float> point;
90  EGS_ControlPoint cpt;
91  int err;
92  int icpts=1;
93  itos << icpts;
94  string inputTag = "control point";
95  string inputTag_backCompat = "control point " + itos.str();
96  EGS_Input *currentInput;
97  int rotsize=0;
98 
99  // Control points read one by one from motion block in dynamic geometry definition, and saved as a vector to points
100  while (true) {
101  currentInput = dyninp->takeInputItem(inputTag);
102  if (!currentInput || currentInput->getInput(inputTag, point)) {
103  currentInput = dyninp->takeInputItem(inputTag_backCompat);
104  if (!currentInput || currentInput->getInput(inputTag_backCompat, point)) {
105  delete currentInput;
106  break;
107  }
108  }
109  delete currentInput;
110 
111  // Checking the size to make sure it is a valid control point input
112  if (point.size()!=6 && point.size()!=7) {
113  egsFatal("EGS_DynamicShape: Control point %i must specify either 6 or 7 values.\n",icpts);
114  }
115  else {
116  if (ncpts == 0) {
117  rotsize=point.size();// Variable to make sure all control point definitions have consistent formats
118  }
119  if (ncpts>0 && point[0] < cpts[ncpts-1].time) {// Make sure each time index is larger than the last
120  egsFatal("EGS_DynamicShape: Time index of control point %i < time index of control point %i\n",icpts,ncpts);
121  }
122  else if (point[0] < 0.) {// Checks that time index is valid (larger than zero)
123  egsFatal("EGS_DynamicShape: Time index of control point %i < 0.0\n",icpts);
124  }
125  else if (ncpts> 0 && point.size() != rotsize) { // Checks that control point formats follow the first
126  egsFatal("EGS_DynamicShape: Rotation definition inconsistent \n");
127  }
128  else {
129  ncpts++;
130 
131  if (ncpts ==1 && point[0] > 0.0) {
132  egsWarning("EGS_DynamicShape: Time index of control point 1 > 0.0. This will generate many warning messages.\n");
133  }
134 
135  vector<EGS_Float> T_vect;// Vector storing translation information
136  vector<EGS_Float> R_vect;// Vector storing rotation information
137  // Add translation coordinates to the translation vector
138  T_vect.push_back(point[1]);
139  T_vect.push_back(point[2]);
140  T_vect.push_back(point[3]);
141  // Add rotation coordinates to rotation vector (cases differentiate cpt formats, 6 is 2 rotation parameters, 7 is 3)
142  // In each case vector order is determined by format of EGS_rotationMatrix constructor (EGS_Float arguments)
143  if (point.size()==6) {
144  R_vect.push_back(point[6]);//rotation about z
145  R_vect.push_back(point[4]);//rotation about x
146  }//2 number case
147  if (point.size()==7) {
148  R_vect.push_back(point[4]);//rotation about x
149  R_vect.push_back(point[5]);//rotation about y
150  R_vect.push_back(point[6]);//rotation about z
151  }//3 number case
152 
153  // Add it to the vector of control points
154  cpt.time = point[0];
155  cpt.trnsl = T_vect;
156  cpt.rot = R_vect;
157  cpts.push_back(cpt);// Add created control point to list of control points
158  icpts++;
159  itos.str("");
160  itos << icpts;
161  inputTag_backCompat = "control point " + itos.str();// Define next control point i string for getInput in while condition
162  }
163  }
164  }
165  if (ncpts<=1) {
166  egsFatal("EGS_DynamicShape: not enough or missing control points.\n");
167  }
168  if (cpts[ncpts-1].time == 0.0) {
169  egsFatal("EGS_DynamicShape: time index of last control point = 0. Something's wrong.\n");
170  }
171  else {
172  // Normalize time index to max. value
173  for (int i=0; i<=ncpts-1; i++) {// I changed the normalization here (and in dynamic source) to have <= instead of <. Otherwise last cpt never gets normalized, which is not an issue for final cpt time>1 but is an issue if final cpt time<1.
174  cpts[i].time /= cpts[ncpts-1].time;
175  }
176  }
177  updatePosition(0); // Sets position to initial time in egs_view upon opening
178  };
179 
181  int errg = 1;
182  EGS_ControlPoint gipt;
183 
184  // Here get source from activeapplication in order to extract time
186  while (errg) {
187  // Gets time if it's already set (otherwise gives -1).
188  ptime = app->getTimeIndex();
189 
190  if (ptime<0) {
191  // If no time is given by the source the shape will randomly sample from 0 to 1.
192  ptime = rndm->getUniform();
193 
194  // Set randomly sampled time index for all objects in the simulation
195  app->setTimeIndex(ptime);
196  }
197 
198  // Now run the get coord method that will sample the cpt given to find the transformation that will be applied for the current history
199  errg = getCoord(ptime,gipt);
200  }
201 
202  // Create and set the current shape transformation using the sampled coordinates from getCoord. This is where overloaded EGS_AffineTransform is used
204  shape->setTransformation(tDG);
205  delete tDG;
206 
207  // Call getNextShapePosition on base shape in case there are lower level dynamic shapes
208  shape->getNextShapePosition(rndm);
209  };
210 
211  int EGS_DynamicShape::getCoord(EGS_Float rand, EGS_ControlPoint &gipt) {
212  int iindex=0;
213  int i;
214 
215  // The following loop determines which 2 control points the current time index falls between
216  for (i=0; i<ncpts; i++) {
217  if (rand < cpts[i].time-epsilon) { // If the control point i time index is larger than the current time index, we know this is the upper bound control point (represented by iindex)
218  iindex = i;
219  break;
220  }
221  }
222 
223  if (i==ncpts) {
224  egsWarning("EGS_DynamicShape: could not locate control point.\n");
225  return 1;
226  }
227 
228  // Below 3 vectors are defined, a vector containing the lower bound translation coordinates, a vector containing the upper bound translation coordinates, and a vector for the sampled translation coordinates
229  vector<EGS_Float> translation_LB=cpts[iindex-1].trnsl;
230  vector<EGS_Float> translation_UB=cpts[iindex].trnsl;
231  vector<EGS_Float> translation_samp;
232 
233  // The following is a factor (between 0 and 1) used for sampling. Essentially, it represents the fractional position within the interval
234  EGS_Float factor = (rand-cpts[iindex-1].time)/(cpts[iindex].time-cpts[iindex-1].time);
235 
236  // Translations are given as the lower bound plus the length of the interval multiplied by the fractional position factor. So its essentially lower bound + n% of the interval length
237  translation_samp.push_back(translation_LB[0]+(translation_UB[0]-translation_LB[0])*factor);
238  translation_samp.push_back(translation_LB[1]+(translation_UB[1]-translation_LB[1])*factor);
239  translation_samp.push_back(translation_LB[2]+(translation_UB[2]-translation_LB[2])*factor);
240  // Update the translation coordinates in the current state control point object
241  gipt.trnsl=translation_samp;
242 
243  // Again 3 vectors defined, lower bound, upper bound, and sampled, this time for rotation coordinates
244  vector<EGS_Float> rotation_LB=cpts[iindex-1].rot;
245  vector<EGS_Float> rotation_UB=cpts[iindex].rot;
246  vector<EGS_Float> rotation_samp;
247 
248  // Now set rotations. Current coordinates computed as before (lowerbound+n% of interval length), but now we also convert degrees to radians
249  // These must be done case by case (since order of arguments matters)
250  if (cpts[iindex].rot.size()==2) {
251  rotation_samp.push_back((rotation_LB[0]+(rotation_UB[0]-rotation_LB[0])*factor)*(M_PI/180));
252  rotation_samp.push_back((rotation_LB[1]+(rotation_UB[1]-rotation_LB[1])*factor)*(M_PI/180));
253  }
254  else if (cpts[iindex].rot.size()==3) {
255  rotation_samp.push_back((rotation_LB[0]+(rotation_UB[0]-rotation_LB[0])*factor)*(M_PI/180));
256  rotation_samp.push_back((rotation_LB[1]+(rotation_UB[1]-rotation_LB[1])*factor)*(M_PI/180));
257  rotation_samp.push_back((rotation_LB[2]+(rotation_UB[2]-rotation_LB[2])*factor)*(M_PI/180));
258  }
259  else {
260  egsWarning("EGS_DynamicShape: Invalid number of rotation parameters\n");
261  }
262  gipt.rot=rotation_samp;
263 
264  // Update the rotation coordinates in the current state control point object
265  return 0;
266  };
267 
268 } // extern "C"
269 
A class providing affine transformations.
static EGS_AffineTransform * getTransformation(EGS_Input *inp)
Constructs an affine transformation object from the input pointed to by inp and returns a pointer to ...
Base class for advanced EGSnrc C++ applications.
static EGS_Application * activeApplication()
Get the active application.
EGS_Float getTimeIndex()
Returns the value of the time synchronization parameter.
void setTimeIndex(EGS_Float temp_time)
Base shape class. All shapes in the EGSnrc C++ class library are derived from EGS_BaseShape.
Definition: egs_shapes.h:114
static EGS_BaseShape * getShape(const string &Name)
Get a pointer to the shape named Name.
Definition: egs_shapes.cpp:64
static EGS_BaseShape * createShape(EGS_Input *inp)
Create a shape from the information pointed to by inp.
Definition: egs_shapes.cpp:51
void setTransformation(EGS_Input *inp)
Set the transformation attached to this shape.
Definition: egs_shapes.cpp:69
virtual void updatePosition(EGS_Float time)
Update the position of the shape if it is in motion.
Definition: egs_shapes.h:248
An dynamic shape.
EGS_Float ptime
Time index corresponding to particle.
int getCoord(EGS_Float rand, EGS_ControlPoint &gipt)
Extract coordinates for the next dynamic shape position.
void getNextShapePosition(EGS_RandomGenerator *rndm)
Get the next state of the dynamic shape.
void buildDynamicShape(EGS_Input *dyninp)
Build the dynamic shape using input specifications.
vector< EGS_ControlPoint > cpts
Control points.
int ncpts
Number of control points.
EGS_BaseShape * shape
Base shape made dynamic.
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_Input * takeInputItem(const string &key, bool self=true)
Get the property named key.
Definition: egs_input.cpp:226
int getInput(const string &key, vector< string > &values) const
Assign values to an array of strings from an input identified by key.
Definition: egs_input.cpp:338
An object factory.
void setName(EGS_Input *inp)
Set the name of the object from the information provided by inp.
Base random number generator class. All random number generators should be derived from this class.
Definition: egs_rndm.h:67
EGS_Float getUniform()
Returns a random number uniformly distributed between zero (inclusive) and 1 (exclusive).
Definition: egs_rndm.h:103
A dynamic shape.
Global egspp functions header file.
EGS_Input class header file.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
const EGS_Float epsilon
The epsilon constant for floating point comparisons.
Definition: egs_functions.h:62
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.
Structure representing a control point for dynamic motion.
vector< EGS_Float > rot
Rotation vector.
EGS_Float time
Time index for control point.
vector< EGS_Float > trnsl
Vector specifying x, y, z translation.