GEAR  1.9.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Friends Pages
TPCModuleImpl.cc
1 #include "gearimpl/TPCModuleImpl.h"
2 #include "gearimpl/FixedPadSizeDiskLayout.h"
3 #include "gearimpl/RectangularPadRowLayout.h"
4 #include <cmath>
5 #include <complex>
6 #include <iostream>
7 
8 namespace gear {
9  /* Transforms a point from the global coordinates to Layout2D coordinates.*/
10  gear::Vector2D TPCModuleImpl::globalToLocal(double c0,double c1)const
11  {
12  if ( _localIsGlobal )
13  {
14  return Vector2D( c0, c1 );
15  }
16 
17  // invert the x coordinate for negative half TPC
18  if ( _zPosition <= 0 ) // 0 is also part of the negative half TPC
19  {
20  switch (_momsCoordinateType)
21  {
22  case PadRowLayout2D::POLAR :
23  // this is the angle corresponding a mirroring at the y axis
24  c1 = M_PI - c1;
25  break;
26  case PadRowLayout2D::CARTESIAN :
27  c0 = -c0; // just invert the x coordinate
28  break;
29  default:
30  throw gear::Exception("TPCModuleImpl::globalToLocal: unkown coorinate type");
31  }
32  }
33 
34  // now that the incomming global coordinates have the right position relative to the
35  // end plate we can start the conversion to local
36 
37  // the global coordinates in cartesian coordinates
38  double x, y;
39  switch (_momsCoordinateType)
40  {
41  case PadRowLayout2D::POLAR :
42  {
43  // to speed this up: if the local coordinate system is polar and there is no offset
44  // the calculation is much easyer
45  if ( (_padRowLayout->getCoordinateType() == PadRowLayout2D::POLAR ) &&
46  (_offset_cartesian[0] == 0 ) &&
47  (_offset_cartesian[0] == 0 ) )
48  {
49  double localAngle = c1 - _angle ;
50  // wrap to 0..2pi
51  if (localAngle < 0) localAngle+= 2*M_PI;
52  if (localAngle > 2*M_PI) localAngle+= 2*M_PI;
53 
54  return Vector2D(c0, localAngle);
55  }
56 
57  // there is an offset or pad plane is cartesian, we have to do the full stuff
58  x = c0 * std::cos( c1 );
59  y = c0 * std::sin( c1 );
60  }
61  break;
62  case PadRowLayout2D::CARTESIAN :
63  {
64  x = c0;
65  y = c1;
66  }
67  break;
68  default:
69  throw gear::Exception("TPCModuleImpl::globalToLocal: unkown coorinate type");
70  }
71 
72  // x_prime and y_prime are the cartesian coordinates after moving to local origin
73  double x_prime = x - _offset_cartesian[0];
74  double y_prime = y - _offset_cartesian[1];
75 
76  // now rotate arround local origin
77  double x_prime_rot = x_prime * _cos_angle + y_prime * _sin_angle;
78  double y_prime_rot = y_prime * _cos_angle - x_prime * _sin_angle;
79 
80  Vector2D toReturn;
81  switch (_padRowLayout->getCoordinateType())
82  {
83  case PadRowLayout2D::POLAR :
84  {
85  toReturn[0] = std::sqrt(x_prime_rot*x_prime_rot + y_prime_rot*y_prime_rot);
86  toReturn[1] = atan2( y_prime_rot, x_prime_rot);
87  // atan gives +-pi as range, convert to 0..2pi
88  if ( toReturn[1] < 0)
89  {
90  toReturn[1]+=2*M_PI;
91  }
92  }
93  break;
94  case PadRowLayout2D::CARTESIAN :
95  {
96  toReturn[0] = x_prime_rot;
97  toReturn[1] = y_prime_rot;
98  }
99  break;
100  default:
101  throw gear::Exception("TPCModuleImpl::localToGlobal: unkown coorinate type");
102  }
103 
104  return toReturn;
105  }
106 
107  /* Transforms a point from the Layout2D coordinates to global coordinates. */
108  gear::Vector2D TPCModuleImpl::localToGlobal(double c0,double c1)const
109  {
110  if ( _localIsGlobal )
111  {
112  return Vector2D( c0, c1 );
113  }
114 
115  // x and y prime are c0 and c1 in local cartesian coordinates
116  double x_prime, y_prime;
117  switch (_padRowLayout->getCoordinateType())
118  {
119  case PadRowLayout2D::POLAR :
120  {
121  double r = c0;
122  double phi = c1 + _angle;
123 
124  // if the TPC coordinate system is also polar and there is no offset we are
125  // already done
126  if ( (_momsCoordinateType == PadRowLayout2D::POLAR ) &&
127  (_offset_cartesian[0] == 0 ) &&
128  (_offset_cartesian[1] == 0 ) )
129  {
130  // flip angle in case of negative half TPC
131  if ( _zPosition <=0 )
132  {
133  phi = M_PI - phi;
134  }
135 
136  // wrap phi to 0..2pi
137  if (phi < 0) phi += 2*M_PI;
138  if (phi > 2*M_PI) phi -= 2*M_PI;
139  return Vector2D( r, phi );
140  }
141 
142  x_prime = r * std::cos( phi );
143  y_prime = r * std::sin( phi );
144  }
145  break;
146  case PadRowLayout2D::CARTESIAN :
147  {
148  x_prime = c0 * _cos_angle - c1 * _sin_angle;
149  y_prime = c1 * _cos_angle + c0 * _sin_angle;
150  }
151  break;
152  default:
153  throw gear::Exception("TPCModuleImpl::localToGlobal: unkown coorinate type");
154  }
155 
156  // x and y are the global cartesian coordinates
157  double x = x_prime + _offset_cartesian[0];
158  double y = y_prime + _offset_cartesian[1];
159 
160  // flip x in case of negative half TPC
161  if ( _zPosition <= 0 )
162  {
163  x = -x;
164  }
165 
166  // calculate the return value
167  gear::Vector2D toReturn;
168  switch (_momsCoordinateType)
169  {
170  case PadRowLayout2D::POLAR :
171  {
172  toReturn[0] = std::sqrt(x*x+y*y);
173  toReturn[1] = atan2(y,x) ;
174  // atan gives +-pi as range, convert to 0..2pi
175  if ( toReturn[1] < 0 )
176  {
177  toReturn[1] += 2*M_PI;
178  }
179  }
180  break;
181  case PadRowLayout2D::CARTESIAN :
182  {
183  toReturn[0] = x;
184  toReturn[1] = y;
185  }
186  break;
187  default:
188  throw gear::Exception("TPCModuleImpl::localToGlobal: unkown coorinate type");
189  }
190 
191  return toReturn;
192  }
196  {
197  // first calculate the local module extend
198  if (_border == 0) // no border: local module extend is pad layout extend
199  {
200  _localModuleExtent = _padRowLayout->getPlaneExtent();
201  }
202  else
203  {
204  switch (_padRowLayout->getCoordinateType())
205  {
206  case PadRowLayout2D::POLAR :
207  {
208  //first handle the radius
209  double rMin = _padRowLayout->getPlaneExtent()[0] - _border;
210  _localModuleExtent[0] = ( rMin >=0. ? rMin : 0. );
211  _localModuleExtent[1] = _padRowLayout->getPlaneExtent()[1] + _border;//rMax
212 
213  // first calculate the angle which corresponds to the border
214  double phiBorder;
215  if (_padRowLayout->getPlaneExtent()[1] > 0) // inner radius of pad plane > 0
216  // to avoid divide by 0
217  {
218  //phiBorder = _border/_padRowLayout->getPlaneExtent()[1] * 2. *M_PI;
219  phiBorder = _border / _padRowLayout->getPlaneExtent()[0];
220  }
221  else // the plane extent is a full circle
222  {
223  phiBorder = M_PI;
224  }
225 
226  double phiMin = _padRowLayout->getPlaneExtent()[2] - phiBorder;
227  double phiMax = _padRowLayout->getPlaneExtent()[3] + phiBorder;
228 
229  //phi needs some safety checks
230  if (phiMax - phiMin > 2*M_PI)
231  {
232  // the border should be half of the gap between the pad layout edged
233  phiBorder = (2*M_PI - phiMax + phiMin)/2.;
234  phiMin = _padRowLayout->getPlaneExtent()[2] - phiBorder;
235  phiMax = _padRowLayout->getPlaneExtent()[3] + phiBorder;
236  }
237 
238  _localModuleExtent[2] = phiMin;
239  _localModuleExtent[3] = phiMax;
240 
241  }
242  break;
243  case PadRowLayout2D::CARTESIAN :
244  {
245  // this is easy, just add / subtract the border to the local extent
246  _localModuleExtent[0] = _padRowLayout->getPlaneExtent()[0] - _border;//xMin
247  _localModuleExtent[1] = _padRowLayout->getPlaneExtent()[1] + _border;//xMax
248  _localModuleExtent[2] = _padRowLayout->getPlaneExtent()[2] - _border;//yMin
249  _localModuleExtent[3] = _padRowLayout->getPlaneExtent()[3] + _border;//yMax
250  }
251  break;
252  default:
253  throw gear::Exception("TPCModuleImpl::convertLocalPlaneToGlobalPlaneExtend(): unkown coorinate type");
254 
255  }// switch (_padRowLayout->getCoordinateType())
256  } // else (_border == 0)
257 
258 
259  // now calculate the global extents
260  switch (_momsCoordinateType)
261  {
262  case PadRowLayout2D::POLAR :
263  {
264  switch (_padRowLayout->getCoordinateType())
265  {
266  case PadRowLayout2D::POLAR :
267  {
269  _planeExtent= calculateGlobalExtentPolarPolar( _padRowLayout->getPlaneExtent() );
270  }
271  break;
272  case PadRowLayout2D::CARTESIAN :
273  throw gear::NotImplementedException("TPCModuleImpl::convertLocalPlaneToGlobalPlaneExtend: not implemented for global polar/cartesian coordinates.");
274 // {
275 // _moduleExtent= calculateGlobalExtentPolarCartesian( _localModuleExtent );
276 // _planeExtent= calculateGlobalExtentPolarCartesian( _padRowLayout->getPlaneExtent() );
277 // }
278  break;
279  default:
280  throw gear::Exception("TPCModuleImpl::convertLocalPlaneToGlobalPlaneExtend():: unkown coorinate type");
281  }
282 
283  }// case _momsCoordinateSystem = POLAR
284  break;
285  case PadRowLayout2D::CARTESIAN :
286  {
287  switch (_padRowLayout->getCoordinateType())
288  {
289  case PadRowLayout2D::POLAR :
290  {
292  _planeExtent= calculateGlobalExtentCartesianPolar( _padRowLayout->getPlaneExtent() );
293  }
294  break;
295  case PadRowLayout2D::CARTESIAN :
296  {
298  _planeExtent= calculateGlobalExtentCartesianCartesian( _padRowLayout->getPlaneExtent() );
299  }
300  break;
301  default:
302  throw gear::Exception("TPCModuleImpl::convertLocalPlaneToGlobalPlaneExtend():: unkown coorinate type");
303  }
304  }
305  break;
306  default:
307  throw gear::Exception("TPCModuleImpl::convertLocalPlaneToGlobalPlaneExtend(): unkown coorinate type");
308  }// switch _momsCoordinateType
309 
310 
311  // throw gear::Exception("TPCModuleImpl::convertLocalPlaneToGlobalPlaneExtend:This Has Not Been Implimented");
312  }
313 
314  std::vector<double> TPCModuleImpl:: calculateGlobalExtentCartesianCartesian( std::vector<double> localExtent )
315  {
316  // this is esasy: just convert the local plane extent to global coordinates
317  // and find the minimum and maximum
318  Vector2D firstEdge = localToGlobal(localExtent[0],localExtent[2] );// xmin, yMin
319 
320  double xMin=firstEdge[0];
321  double xMax=firstEdge[0];
322  double yMin=firstEdge[1];
323  double yMax=firstEdge[1];
324 
325  Vector2D edges[3]; // the three other edges (combinations if x/y , min/max)
326  edges[0] = localToGlobal(localExtent[0],localExtent[3] ); // xMin, yMax
327  edges[1] = localToGlobal(localExtent[1],localExtent[2] ); // xMax, yMin
328  edges[2] = localToGlobal(localExtent[1],localExtent[3] ); // xMax, yMax
329 
330 
331  // look for maxima and minima
332  for (unsigned int i = 0; i < 3 ; i++)
333  {
334  if (xMin > edges[i][0]) xMin = edges[i][0];
335  if (xMax < edges[i][0]) xMax = edges[i][0];
336  if (yMin > edges[i][1]) yMin = edges[i][1];
337  if (yMax < edges[i][1]) yMax = edges[i][1];
338  }
339 
340  std::vector<double> globalExtent;
341  globalExtent.push_back(xMin);
342  globalExtent.push_back(xMax);
343  globalExtent.push_back(yMin);
344  globalExtent.push_back(yMax);
345 
346  return globalExtent;
347  }
348 
349  std::vector<double> TPCModuleImpl:: calculateGlobalExtentCartesianPolar( std::vector<double> localExtent )
350  {
351  // this is comparatively esasy:
352  // convert the edge coordinates to global coordinates
353  // add centreX+r, centreY+r, centreX-r and centreY-r to the list of test candidates
354  // only if they are in the active sector
355  // find the minimum and maximum
356  Vector2D firstEdge = localToGlobal(localExtent[0],localExtent[2] );// rMin, phiMin
357 
358  double xMin=firstEdge[0];
359  double xMax=firstEdge[0];
360  double yMin=firstEdge[1];
361  double yMax=firstEdge[1];
362 
363  Vector2D edges[3]; // the three other edges (combinations if r/y , min/max)
364  edges[0] = localToGlobal(localExtent[0],localExtent[3] ); // rMin, phiMax
365  edges[1] = localToGlobal(localExtent[1],localExtent[2] ); // rMax, phiMin
366  edges[2] = localToGlobal(localExtent[1],localExtent[3] ); // rMax, phiMax
367 
368  // look for maxima and minima
369  for (unsigned int i = 0; i < 3 ; i++)
370  {
371  if (xMin > edges[i][0]) xMin = edges[i][0];
372  if (xMax < edges[i][0]) xMax = edges[i][0];
373  if (yMin > edges[i][1]) yMin = edges[i][1];
374  if (yMax < edges[i][1]) yMax = edges[i][1];
375  }
376 
377  // test the possible new yMax
378  // Note: one cannot use _offset directly because the x coordinate might be
379  // inverted for negative half TPC. Just let loicalToGlobal take care of it.
380  Vector2D localOriginInGlobalCoordinates = localToGlobal( 0 , 0 );
381  double testYMax = localOriginInGlobalCoordinates[1] + localExtent[1]; // module centre + rMax
382  double localPhi1 = globalToLocal( localOriginInGlobalCoordinates[0], testYMax )[1];
383  // test for [0:2pi] and [-2pi:0]
384  double localPhi2 ;
385  if ( localPhi1 < 0 )
386  localPhi2 = localPhi1 + 2*M_PI;
387  else
388  localPhi2 = localPhi1 - 2*M_PI;
389  // change yMax if necessary
390  if ( ( (localPhi1 > localExtent[2]) && (localPhi1 < localExtent[3]) ) ||
391  ( (localPhi2 > localExtent[2]) && (localPhi2 < localExtent[3]) ) )
392  { // testYMax is in active sector, so it is automatically larger than the
393  // yMax of the edges
394  yMax = testYMax;
395  }
396 
397  // now test the other max extents of the circle
398 
399  // test the possible new yMin
400  double testYMin = localOriginInGlobalCoordinates[1] - localExtent[1]; // module centre - rMax
401  localPhi1 = globalToLocal( localOriginInGlobalCoordinates[0], testYMin )[1];
402  // std::cout <<"#DEBUG localPhi1 for ymin "<< localPhi1<<std::endl;
403  // test for [0:2pi] and [-2pi:0]
404  if ( localPhi1 < 0 )
405  localPhi2 = localPhi1 + 2*M_PI;
406  else
407  localPhi2 = localPhi1 - 2*M_PI;
408  //std::cout <<"#DEBUG localPhi2 for ymin "<< localPhi2<<std::endl;
409 
410  // change yMin if necessary
411  if ( ( (localPhi1 > localExtent[2]) && (localPhi1 < localExtent[3]) ) ||
412  ( (localPhi2 > localExtent[2]) && (localPhi2 < localExtent[3]) ) )
413  { // testYMin is in active sector, so it is automatically larger than the
414  // yMax of the edges
415  yMin = testYMin;
416  }
417 
418  // test tho possible new xMax
419  double testXMax = localOriginInGlobalCoordinates[0] + localExtent[1]; // module centre + rMax
420  localPhi1 = globalToLocal( testXMax, localOriginInGlobalCoordinates[1] )[1];
421  // test for [0:2pi] and [-2pi:0]
422  if ( localPhi1 < 0 )
423  localPhi2 = localPhi1 + 2*M_PI;
424  else
425  localPhi2 = localPhi1 - 2*M_PI;
426  // change yMax if necessary
427  if ( ( (localPhi1 > localExtent[2]) && (localPhi1 < localExtent[3]) ) ||
428  ( (localPhi2 > localExtent[2]) && (localPhi2 < localExtent[3]) ) )
429  { // testXMax is in active sector, so it is automatically larger than the
430  // yMax of the edges
431  xMax = testXMax;
432  }
433 
434  // test the possible new xMin
435  double testXMin = localOriginInGlobalCoordinates[0] - localExtent[1]; // module centre - rMax
436  localPhi1 = globalToLocal( testXMin, localOriginInGlobalCoordinates[1] )[1];
437  // test for [0:2pi] and [-2pi:0]
438  if ( localPhi1 < 0 )
439  localPhi2 = localPhi1 + 2*M_PI;
440  else
441  localPhi2 = localPhi1 - 2*M_PI;
442  // change yMax if necessary
443  if ( ( (localPhi1 > localExtent[2]) && (localPhi1 < localExtent[3]) ) ||
444  ( (localPhi2 > localExtent[2]) && (localPhi2 < localExtent[3]) ) )
445  { // testYMax is in active sector, so it is automatically larger than the
446  // yMax of the edges
447  xMin = testXMin;
448  }
449 
450  std::vector<double> globalExtent;
451  globalExtent.push_back(xMin);
452  globalExtent.push_back(xMax);
453  globalExtent.push_back(yMin);
454  globalExtent.push_back(yMax);
455 
456  //std::cout << "#DEBUG global extent "<< xMin <<"\t" << xMax <<"\t"
457  // << yMin <<"\t" << yMax <<std::endl;
458 
459  return globalExtent;
460  }
461 
462  std::vector<double> TPCModuleImpl:: calculateGlobalExtentPolarPolar( std::vector<double> localExtent )
463  {
464  // first check if the two origins are identical (to avoid divide by zero)
465  if (_offset[0]==0) // r is 0, no offset
466  {
467  double phiMin, phiMax;
468 
469  if ( _zPosition > 0 )
470  {
471  phiMin = localExtent[2] + _angle;
472  phiMax = localExtent[3] + _angle;
473  }
474  else // Negative half TPC, the angles are flipped at the y axis.
475  { // This means the phi_minus is pi - phi_minus and max and min are exchanged
476  phiMin = M_PI - localExtent[3] - _angle;
477  phiMax = M_PI - localExtent[2] - _angle;
478  }
479 
480  // force phiMax to 0 .. 2*M_PI
481  while (phiMax > 2*M_PI) phiMax -= 2*M_PI;
482  while (phiMax < 0 ) phiMax += 2*M_PI;
483 
484  // force phiMin to be smaller than phiMax, but max
485  while ( phiMin > phiMax ) phiMin -= 2*M_PI;
486  while ( phiMin < phiMax - 2*M_PI ) phiMin += 2*M_PI;
487 
488  std::vector<double> globalExtent;
489  globalExtent.push_back(localExtent[0]);
490  globalExtent.push_back(localExtent[1]);
491  globalExtent.push_back(phiMin);
492  globalExtent.push_back(phiMax);
493 
494  return globalExtent;
495 
496  }
497  else // there is an offset
498  {
499  // The potential global rmin and rmax are always on the straight line connecting
500  // the global and the local origins. rMin is in the direction of the global origin,
501  // rMax is in the oposite direction
502 
503  // Get coordinates of global origin in local coordinates
504  Vector2D globalOriginInLocal = globalToLocal( 0 , 0 );
505 
506  // The vectors of the four edges in global coordinates
507  // needed either for rMin/Max or phiMin/Max
508  Vector2D edges_global[4];
509  edges_global[0] = localToGlobal(localExtent[0],localExtent[2] );// rMin, phiMin
510  edges_global[1] = localToGlobal(localExtent[0],localExtent[3] );// rMin, phiMax
511  edges_global[2] = localToGlobal(localExtent[1],localExtent[2] );// rMax, phiMin
512  edges_global[3] = localToGlobal(localExtent[1],localExtent[3] );// rMax, phiMax
513 
514  for (int i=0; i<4; i++)
515  {
516  //std::cout <<"#edges_global["<<i<<"] = "<< edges_global[i][0] <<"\t"
517  // << edges_global[i][1]<< std::endl;
518  }
519 
520  // test if rMin direction is in pad plane
521  // test for [0:2pi] and [-2pi:0]
522  double phiTest1 = fmod(globalOriginInLocal[1], 2*M_PI);
523  double phiTest2;
524  if ( phiTest1 < 0 )
525  phiTest2 = phiTest1 + 2*M_PI;
526  else
527  phiTest2 = phiTest1 - 2*M_PI;
528 
529  double rMin;
530  // one of the two has to be in the active area for this to be the real rMin
531  if ( ( (phiTest1 > localExtent[2]) && (phiTest1 < localExtent[3]) ) ||
532  ( (phiTest2 > localExtent[2]) && (phiTest2 < localExtent[3]) ) )
533  {
534 
535  //std::cout << "#rmin in active area"<< std::endl;
536  // Three cases:
537  // distance to center < rmin
538  // rmin < distance to center < rmax
539  // distance to center > rmax
540 
541  if ( globalOriginInLocal[0] < localExtent[0] ) // distance to center < rmin
542  {
543  rMin = localExtent[0] - globalOriginInLocal[0] ;
544  }
545  else
546  if ( globalOriginInLocal[0] > localExtent[1] ) // distance to center > rmax
547  {
548  rMin = globalOriginInLocal[0] - localExtent[1];
549  }
550  else // rmin < distance to center < rmax // is inside the active area
551  rMin = 0;
552  }
553  else // not the active area, test the four edges
554  {
555  //std::cout << "#rmin not in active area"<< std::endl;
556  rMin = edges_global[0][0];
557  //std::cout << "#rMin = "<< rMin<< std::endl;
558 
559  for (int i=1; i <4 ; i++)
560  {
561  if ( edges_global[i][0] < rMin ) rMin = edges_global[i][0];
562  }
563  //std::cout << "#rMin = "<< rMin<< std::endl;
564 
565  // there is a special case: if r > rMin
566  // it might be that one of the sector edges causes the minimal global r
567  if ( globalOriginInLocal[0] > localExtent[0] )
568  {
569  //std::cout << "# special case" << std::endl;
570  // calculate the foot of the line perpendicular to the sector edge which goes
571  // through the global origin (note: this does not have to be in the range between
572  // the radii. In this case the edges are limiting)
573 
574  // use local coordinates
575  // the phiMin edge
576  double phiMinEdge = localExtent[2];
577  double phi= globalOriginInLocal[1];
578  double r = globalOriginInLocal[0];
579  // determine r_intersect for x = r_intersect * cos(_phiMinEdge) = r* cos(phi) - m * sin(_phiMinEdge)
580  // y = r_intersect * sin(_phiMinEdge) = r*sin(phi) + m * cos(_phiMinEdge)
581  // solve this to r_intersect and m
582  double r_intersect_phiMin = r * (cos(phi)*cos(phiMinEdge) + sin(phi)*sin(phiMinEdge));
583  double m_phiMin = fabs (r * (cos(phi)*sin(phiMinEdge) - sin(phi)*cos(phiMinEdge)));
584  // one can take the abs here, it has been checked that we are outside the active area before
585 
586  //std::cout << "#r_intersect_phiMin " << r_intersect_phiMin << std::endl;
587  //std::cout << "#m_phiMin " << m_phiMin << std::endl;
588 
589  if ( (r_intersect_phiMin > localExtent[0] ) &&
590  (r_intersect_phiMin < localExtent[1] ) &&
591  (m_phiMin < rMin) )
592  {
593  //std::cout << "beep"<< std::endl;
594  rMin = m_phiMin;
595  }
596 
597  // the phiMax edge
598  double phiMaxEdge = localExtent[3 ];
599  // determine r_intersect for x = r_intersect * cos(_phiMaxEdge) = r* cos(phi) - m * sin(_phiMaxEdge)
600  // y = r_intersect * sin(_phiMaxEdge) = r*sin(phi) + m * cos(_phiMaxEdge)
601  // solve this to r_intersect and m
602  double r_intersect_phiMax = r * (cos(phi)*cos(phiMaxEdge) + sin(phi)*sin(phiMaxEdge));
603  double m_phiMax = fabs (r * (cos(phi)*sin(phiMaxEdge) - sin(phi)*cos(phiMaxEdge)));
604  // one can take the abs here, it has been checked that we are outside the active area before
605 
606  //std::cout << "#r_intersect_phiMax " << r_intersect_phiMax << std::endl;
607  //std::cout << "#m_phiMax " << m_phiMax << std::endl;
608 
609 
610  if ( (r_intersect_phiMax > localExtent[0] ) &&
611  (r_intersect_phiMax < localExtent[1] ) &&
612  (m_phiMax < rMin) )
613  {
614  //std::cout << "baap"<< std::endl;
615  rMin = m_phiMax;
616  }
617  }
618  //std::cout << "#rMin = "<< rMin<< std::endl;
619  }
620 
621  // now rMax
622  // test for [0:2pi] and [-2pi:0], the direction opposite of the origin
623  double phiTest3 = fmod(globalOriginInLocal[1] + M_PI, 2*M_PI);
624  double phiTest4;
625  if ( phiTest3 < 0 )
626  phiTest4 = phiTest3 + 2*M_PI;
627  else
628  phiTest4 = phiTest3 - 2*M_PI;
629 
630  double rMax;
631  // one of the two has to be in the active area for this to be the real rMax
632  if ( ( (phiTest3 > localExtent[2]) && (phiTest3 < localExtent[3]) ) ||
633  ( (phiTest4 > localExtent[2]) && (phiTest4 < localExtent[3]) ) )
634  {
635  //std::cout << "#rmax in active area"<< std::endl;
636  // rMax is the sum of local rMax and the distance to the origin
637  rMax= globalOriginInLocal[0] + localExtent[1];
638  }
639  else // not the active area, test the four edges
640  {
641  //std::cout << "#rmax not in active area"<< std::endl;
642  rMax = edges_global[0][0];
643 
644  for (int i=1; i <4 ; i++)
645  {
646  if ( edges_global[i][0] > rMax ) rMax = edges_global[i][0];
647  }
648  }
649 
650  // phiMin and phiMax
651 
652  double phiMin, phiMax;
653 
654  // r > rMax
655  // If the global origin is outside of local rMax, the tangents on the rMax-circle are
656  // phiMin and phiMax in case of a full circle.
657  // In case the module is only a circle segment, the edged can define phi min
658  // and/or phi max. In any case they have to be within the angles defined by
659  // the tangents. The max angle between the tangents ca be pi
660  // => wrap all angles to ( phi_tangent_min -- phi_tangent_min + pi ),
661  // so one can compare them (which in generell is not possible as the angles
662  // are only defined to modulo 2pi )
663 
664 
665  if ( globalOriginInLocal[0] >= localExtent[1] )
666  {
667  // Note: one cannot use _offset directly because the x coordinate might be
668  // inverted for negative half TPC. Just let loicalToGlobal take care of it.
669  Vector2D localOriginInGlobalCoordinates = localToGlobal( 0 , 0 );
670 
671  // calclulate the two tangents to the circle: (see TPCModule_tangent_rMax.pdf )
672  double phi_tangent_min = localOriginInGlobalCoordinates[1] - asin( localExtent[1] / globalOriginInLocal[0] );
673  double phi_tangent_max = localOriginInGlobalCoordinates[1] + asin( localExtent[1] / globalOriginInLocal[0] );
674 
675  //std::cout << "#localOriginInGlobalCoordinates " << globalOriginInLocal[0] << "\t"<< localOriginInGlobalCoordinates[1]<< std:: endl;
676  double angles[4];
677 
678  // force the angles of the edges into the range phi_tangent_min -- phi_tangent_min + 2*pi
679  for (int i=0; i < 4; i++)
680  {
681  angles[i] = edges_global[i][1];
682  while ( angles[i] < phi_tangent_min )
683  angles[i] += 2*M_PI;
684  while ( angles[i] > phi_tangent_min + 2*M_PI)
685  angles[i] -= 2*M_PI;
686  }
687 
688  // check whether phi_tangent_min and phi_tangent_max are in the active area
689 
690  // Force local angle where the tangent touches the circle to phiMin -- phiMin+2pi.
691  // In case of negative half TPC min and max are exchanged since globalToLocal
692  // flips the x axis (= angle)
693  double phiTestMin = globalToLocal( sqrt(localOriginInGlobalCoordinates[0]*
694  localOriginInGlobalCoordinates[0]
695  - localExtent[1] * localExtent[1]),
696  ( _zPosition > 0 ? phi_tangent_min
697  : phi_tangent_max ) )[1];
698 
699  //std::cout << "#phiTestMin "<< phiTestMin << std::endl;
700  //std::cout << "#phi_tangen_min "<< phi_tangent_min << std::endl;
701  while ( phiTestMin < localExtent[2] )
702  phiTestMin += 2*M_PI;
703  while ( phiTestMin > localExtent[2] + 2*M_PI)
704  phiTestMin -= 2*M_PI;
705  //std::cout << "#phiTestMin "<< phiTestMin << std::endl;
706 
707  // test whether in active area
708  if ( phiTestMin < localExtent[3] )
709  {
710  // The phiTestMin is the minimum in local coordinates.
711  // For the negative half TPC it is the global maximum because the
712  // x coordinate is swapped
713  if ( _zPosition > 0 )
714  {
715  phiMin = phi_tangent_min;
716  }
717  else
718  {
719  phiMax = phi_tangent_max ;
720  }
721  }
722  else // not in active area, test edges
723  {
724  if ( _zPosition > 0 )
725  {
726  phiMin = angles[0];
727 
728  for (int i=1; i <4 ; i++)
729  {
730  if ( angles[i] < phiMin ) phiMin = angles[i];
731  }
732  }
733  else // _zPosition <= 0
734  {
735  phiMax = angles[0];
736 
737  for (int i=1; i <4 ; i++)
738  {
739  if ( angles[i] > phiMax ) phiMax = angles[i];
740  } // for i (angles)
741  }// else _zPositizion > 0
742 
743  }// else not in active area
744 
745  //std::cout << "#phi_tangen_max "<< phi_tangent_max << std::endl;
746 
747  // Force local angle where the tangent touches the circle to phiMin -- phiMin+2pi
748  // In case of negative half TPC min and max are exchanged since globalToLocal
749  // flips the x axis (= angle)
750  double phiTestMax = globalToLocal( sqrt(localOriginInGlobalCoordinates[0]*
751  localOriginInGlobalCoordinates[0]
752  - localExtent[1] * localExtent[1]),
753  ( _zPosition > 0 ? phi_tangent_max
754  : phi_tangent_min ) )[1];
755  //std::cout << "#phiTestMax "<< phiTestMax << std::endl;
756  // thest whether in active area
757  while ( phiTestMax < localExtent[2] )
758  phiTestMax += 2*M_PI;
759  while ( phiTestMax > localExtent[2] + 2*M_PI)
760  phiTestMax -= 2*M_PI;
761 
762 
763  // thest whether in active area
764  if ( phiTestMax < localExtent[3] )
765  {
766  // The phiTestMax is the maximum in local coordinates.
767  // For the negative half TPC it is the global minimum because the
768  // x coordinate is swapped
769  if ( _zPosition > 0 )
770  {
771  phiMax = phi_tangent_max;
772  }
773  else
774  {
775  phiMin = phi_tangent_min;
776  }
777  }
778  else // not in active area, test edges
779  {
780  if ( _zPosition > 0 )
781  {
782  phiMax = angles[0];
783 
784  for (int i=1; i <4 ; i++)
785  {
786  if ( angles[i] > phiMax ) phiMax = angles[i];
787  }
788  }
789  else
790  {
791  phiMin = angles[0];
792 
793  for (int i=1; i <4 ; i++)
794  {
795  if ( angles[i] < phiMin ) phiMin = angles[i];
796  } // for i (angles)
797  }// else zPosition > 0
798 
799  } // else not in active area
800 
801 
802  }
803  else // ( r < rMax )
804  {
805 
806  // There are may different cases ( in local coordinates ) // note r always < rMax in this section
807 
808  // A: The active sector is < pi (sector 1 is active)
809  // A1a. phi of global origin is in the active sector (1) and r <= rMin : phiMinG = (rMin,phiMin), phiMaxG = (rMin, phiMax)
810  // A1b. phi of global origin is in the active sector (1) and rMin< r : phiMinG = 0, phiMaxG= 2 pi
811  // A2. phi of the global origin is in sector 2 : phiMax is (rmax, phiMax), phiMin is min of (rMin, phiMax) and (rMin, phiMin)
812  // wrap to phiMax - 2pi first, phiMax is the fixed one in this case
813  // (( there is only a small triange near the edge for r > rMin where (rMin, phiMax) is phiMin, but it's difficult to calculate,
814  // so we just take the min of both possibilities
815  // A3. phi is in sector 3 : (rMax,phiMin), (rMax, phiMax)
816  // A4. phi of the global origin is in sector 4 : phiMin is (rMax, phiMin), phiMax is max of (rMin, phiMax) and (rMin, phiMin)
817  // wrap to phiMin + 2pi first, phiMin is the fixed one in this case (see 2 for argumentation)
818 
819  /*
820  /--------\
821  / \______/ \
822  / /\ 1 /\ \
823  / / \ / \ \
824  | | \/ | |
825  | | 2 /\ 4| |
826  \ \ / 3\ / /
827  \ \/____\/ /
828  \ / \ /
829  \--------/
830 */
831  // wrap phi of global origin to phiMin -- phiMin + 2pi
832  double phiGlobalOrigin = globalOriginInLocal[1];
833  while ( phiGlobalOrigin < localExtent[2] )
834  phiGlobalOrigin += 2*M_PI;
835  while ( phiGlobalOrigin > localExtent[2] + 2 *M_PI )
836  phiGlobalOrigin -= 2*M_PI;
837 
838  //A
839  if (localExtent[3] - localExtent[2] < M_PI)
840  {
841  if ( phiGlobalOrigin < localExtent[3] ) // A1
842  {
843  if ( globalOriginInLocal[0] <= localExtent[0] ) // A1a
844  {
845  if ( _zPosition > 0 )
846  {
847  phiMin = edges_global[0][1];
848  phiMax = edges_global[1][1];
849  }
850  else //negative half TPC. Due to the flip in x min and max are exchanged
851  {
852  phiMin = edges_global[1][1];
853  phiMax = edges_global[0][1];
854  }
855 
856  // due to the %2pi problem phiMax might be smaller than phiMin
857  // force phiMin to be smaller
858  while ( phiMin > phiMax)
859  phiMin -= 2*M_PI;
860 
861  // force to +-2pi
862  while (phiMax > 2*M_PI)
863  {
864  phiMin -= 2*M_PI;
865  phiMax -= 2*M_PI;
866  }
867  while (phiMin < -2*M_PI)
868  {
869  phiMin += 2*M_PI;
870  phiMax += 2*M_PI;
871  }
872  }
873  else //A1b
874  {
875  phiMin=0; phiMax=2*M_PI;
876  }
877  }
878  else if ( phiGlobalOrigin < localExtent[2] + M_PI) // A2
879  {
880 
881  // due to the many comparisons, which all change sign when
882  // inverting x, the code unfortunately has to be duplicated :-(
883  if ( _zPosition > 0 )
884  {
885  phiMax = edges_global[3][1];
886 
887  double phiMin1 = edges_global[0][1];
888  while ( phiMin1 < phiMax - 2*M_PI )
889  phiMin1 += 2*M_PI;
890  while ( phiMin1 > phiMax )
891  phiMin1 -= 2*M_PI;
892 
893  double phiMin2 = edges_global[1][1];
894  while ( phiMin2 < phiMax - 2*M_PI )
895  phiMin2 += 2*M_PI;
896  while ( phiMin2 > phiMax )
897  phiMin2 -= 2*M_PI;
898 
899  phiMin = (phiMin1 < phiMin2 ? phiMin1 : phiMin2);
900  }
901  else // negative half TPC
902  {
903  phiMin = edges_global[3][1];
904 
905  double phiMax1 = edges_global[0][1];
906  while ( phiMax1 > phiMin + 2*M_PI )
907  phiMax1 -= 2*M_PI;
908  while ( phiMax1 < phiMin )
909  phiMax1 += 2*M_PI;
910 
911  double phiMax2 = edges_global[1][1];
912  while ( phiMax2 > phiMin + 2*M_PI )
913  phiMax2 -= 2*M_PI;
914  while ( phiMax2 < phiMin )
915  phiMax2 += 2*M_PI;
916 
917  phiMax = (phiMax1 > phiMax2 ? phiMax1 : phiMax2);
918  }
919  }
920  else if ( phiGlobalOrigin < localExtent[3] + M_PI) // A3
921  {
922  if ( _zPosition > 0 )
923  {
924  phiMin = edges_global[2][1];
925  phiMax = edges_global[3][1];
926  }
927  else // negative half TPC
928  {
929  phiMin = edges_global[3][1];
930  phiMax = edges_global[2][1];
931  }
932 
933  // due to the %2pi problem phiMax might be smaller than phiMin
934  // force phiMin to be smaller
935  while ( phiMin > phiMax)
936  phiMin -= 2*M_PI;
937 
938  // force to +-2pi
939  while (phiMax > 2*M_PI)
940  {
941  phiMin -= 2*M_PI;
942  phiMax -= 2*M_PI;
943  }
944  while (phiMin < -2*M_PI)
945  {
946  phiMin += 2*M_PI;
947  phiMax += 2*M_PI;
948  }
949  }
950  else // A4
951  {
952  if ( _zPosition > 0 )
953  {
954  phiMin = edges_global[2][1];
955 
956  double phiMax1 = edges_global[0][1];
957  while ( phiMax1 < phiMin )
958  phiMax1 += 2*M_PI;
959  while ( phiMax1 > phiMin + 2*M_PI )
960  phiMax1 -= 2*M_PI;
961 
962  double phiMax2 = edges_global[1][1];
963  while ( phiMax2 < phiMin )
964  phiMax2 += 2*M_PI;
965  while ( phiMax2 > phiMin + 2*M_PI )
966  phiMax2 -= 2*M_PI;
967 
968  phiMax = (phiMax1 > phiMax2 ? phiMax1 : phiMax2);
969  }
970  else
971  {
972  phiMax = edges_global[2][1];
973 
974  double phiMin1 = edges_global[0][1];
975  while ( phiMin1 < phiMax - 2*M_PI )
976  phiMin1 += 2*M_PI;
977  while ( phiMin1 > phiMax )
978  phiMin1 -= 2*M_PI;
979 
980  double phiMin2 = edges_global[1][1];
981  while ( phiMin2 < phiMax - 2*M_PI )
982  phiMin2 += 2*M_PI;
983  while ( phiMin2 > phiMax )
984  phiMin2 -= 2*M_PI;
985 
986  phiMin = (phiMin1 < phiMin2 ? phiMin1 : phiMin2);
987  }
988  }// scan sectors
989  }
990  else //active area > pi
991  {// B
992  if ( phiGlobalOrigin > localExtent[3] ) // B4
993  {
994  if ( _zPosition > 0 )
995  {
996  phiMin = edges_global[2][1];
997  phiMax = edges_global[3][1];
998  }
999  else
1000  {
1001  phiMin = edges_global[3][1];
1002  phiMax = edges_global[2][1];
1003  }
1004  // due to the %2pi problem phiMax might be smaller than phiMin
1005  // force phiMin to be smaller
1006  while ( phiMin > phiMax)
1007  phiMin -= 2*M_PI;
1008 
1009  // force to +-2pi
1010  while (phiMax > 2*M_PI)
1011  {
1012  phiMin -= 2*M_PI;
1013  phiMax -= 2*M_PI;
1014  }
1015  while (phiMin < -2*M_PI)
1016  {
1017  phiMin += 2*M_PI;
1018  phiMax += 2*M_PI;
1019  }
1020  }
1021  else
1022  {
1023  if ( globalOriginInLocal[0] <= localExtent[0] ) // only perfrom further checks
1024  // if outside active area
1025  {
1026  if ( phiGlobalOrigin < localExtent[3] - M_PI ) // B1
1027  {
1028  if ( _zPosition > 0 )
1029  {
1030  phiMin = edges_global[0][1];
1031  phiMax = edges_global[3][1];
1032  }
1033  else
1034  {
1035  phiMin = edges_global[3][1];
1036  phiMax = edges_global[0][1];
1037  }
1038 
1039  // due to the %2pi problem phiMax might be smaller than phiMin
1040  // force phiMin to be smaller
1041  while ( phiMin > phiMax)
1042  phiMin -= 2*M_PI;
1043 
1044  // phiMax has to be more than pi larger than phiMin
1045  // there is a spechial case when there is no free line
1046  // of sight from the global origin to the outside of the
1047  // circle. In this case phiMax is a little bit more than
1048  // 2pi larger than phiMin, which in this case (%2pi) means
1049  // phiMax - phiMin < pi
1050  if ( phiMax - phiMin < M_PI )
1051  {
1052  phiMin = 0;
1053  phiMax = 2*M_PI;
1054  }
1055  else // force to +-2pi
1056  {
1057  while (phiMax > 2*M_PI)
1058  {
1059  phiMin -= 2*M_PI;
1060  phiMax -= 2*M_PI;
1061  }
1062  while (phiMin < -2*M_PI)
1063  {
1064  phiMin += 2*M_PI;
1065  phiMax += 2*M_PI;
1066  }
1067  }
1068  }
1069  else if ( phiGlobalOrigin < localExtent[2] + M_PI) // B2
1070  {
1071  if (_zPosition > 0 )
1072  {
1073  phiMin = edges_global[0][1];
1074  phiMax = edges_global[1][1];
1075  }
1076  else
1077  {
1078  phiMin = edges_global[1][1];
1079  phiMax = edges_global[0][1];
1080  }
1081  while ( phiMin > phiMax)
1082  phiMin -= 2*M_PI;
1083 
1084  // force to +-2pi
1085  while (phiMax > 2*M_PI)
1086  {
1087  phiMin -= 2*M_PI;
1088  phiMax -= 2*M_PI;
1089  }
1090  while (phiMin < -2*M_PI)
1091  {
1092  phiMin += 2*M_PI;
1093  phiMax += 2*M_PI;
1094  }
1095  }
1096  else if ( phiGlobalOrigin < localExtent[3] + M_PI) // B3
1097  {
1098  if ( _zPosition > 0 )
1099  {
1100  phiMin = edges_global[2][1];
1101  phiMax = edges_global[1][1];
1102  }
1103  else
1104  {
1105  phiMin = edges_global[1][1];
1106  phiMax = edges_global[2][1];
1107  }
1108  // due to the %2pi problem phiMax might be smaller than phiMin
1109  // force phiMin to be smaller
1110  while ( phiMin > phiMax)
1111  phiMin -= 2*M_PI;
1112 
1113  // phiMax has to be more than pi larger than phiMin
1114  // there is a spechial case when there is no free line
1115  // of sight from the global origin to the outside of the
1116  // circle. In this case phiMax is a little bit more than
1117  // 2pi larger than phiMin, which in this case (%2pi) means
1118  // phiMax - phiMin < pi
1119  if ( phiMax - phiMin < M_PI )
1120  {
1121  phiMin = 0;
1122  phiMax = 2*M_PI;
1123  }
1124  else // force to +-2pi
1125  {
1126  while (phiMax > 2*M_PI)
1127  {
1128  phiMin -= 2*M_PI;
1129  phiMax -= 2*M_PI;
1130  }
1131  while (phiMin < -2*M_PI)
1132  {
1133  phiMin += 2*M_PI;
1134  phiMax += 2*M_PI;
1135  }
1136  }
1137  }
1138  }
1139  else // in active area
1140  {
1141  phiMin = 0;
1142  phiMax = 2*M_PI;
1143  }
1144  }// else (not in open sector
1145 
1146  } // else active area > pi
1147 
1148  }// else (r < rMax)
1149 
1150 
1151  std::vector<double> globalExtent;
1152  globalExtent.push_back(rMin);
1153  globalExtent.push_back(rMax);
1154  globalExtent.push_back(phiMin);
1155  globalExtent.push_back(phiMax);
1156 
1157  //std::cout << "#global extent "<< rMin <<"\t" << rMax <<"\t"
1158  // << phiMin <<"\t" << phiMax <<std::endl;
1159 
1160  return globalExtent;
1161  }// else there is an offset
1162  }
1163 
1164  TPCModuleImpl::TPCModuleImpl(int moduleID, PadRowLayout2D *padRowLayout,int TPCCoordinateType,
1165  double readoutFrequency)
1166  {
1167  _moduleID = moduleID;
1168  _readoutFrequency= readoutFrequency;
1169  _padRowLayout= padRowLayout;
1170  _momsCoordinateType =TPCCoordinateType;
1171  _border= 0;
1172  // set correct sizes for extent vectors, so it's save to use extent[i]
1173  _planeExtent.resize(4);
1174  _moduleExtent.resize(4);
1175  _localModuleExtent.resize(4);
1176 
1177  // as no offsets, angle and border are applied, all extents are identical
1178  _planeExtent=_padRowLayout->getPlaneExtent();
1179  _moduleExtent = _planeExtent;
1180  _localModuleExtent = _moduleExtent;
1181 
1182  _offset[0]=0;
1183  _offset[1]=0;
1184  _offset_cartesian[0]=0;
1185  _offset_cartesian[1]=0;
1186  _zPosition=1.; // Set the z position to a positive value so no x-swapping
1187  // is done in the default case.
1188  // This value is not accessible from outside the class sice
1189  // an exceptions is thrown if it has not been overwritten.
1190  _angle =0 ;
1191  _cos_angle = 1;
1192  _sin_angle = 0;
1193 
1194  _zPositionIsSet = false;
1195 
1197  }
1198 
1200  {
1201  copy_and_assign( right);
1202  }
1203 
1205  {
1206  cleanup();
1207  copy_and_assign( right);
1208  return *this;
1209  }
1210 
1212  {
1213  _planeExtent = right._planeExtent;
1214  _moduleExtent = right._moduleExtent;
1216  _readoutFrequency = right._readoutFrequency;
1217  _offset = right._offset;
1219  _angle = right._angle;
1220  _cos_angle = right._cos_angle;
1221  _sin_angle = right._sin_angle;
1223  _moduleID = right._moduleID;
1224  _border = right._border;
1225  _localIsGlobal = right._localIsGlobal;
1226 
1227  _zPosition = right._zPosition;
1229 
1230  // test all knows possible instances of padRowLayout
1231  _padRowLayout = right._padRowLayout->clone();
1232  }
1233 
1234 
1236  cleanup();
1237  }
1238 
1240  {
1241  return new TPCModuleImpl(*this);
1242  }
1243 
1245  delete _padRowLayout;
1246  }
1247 
1248 
1250  Vector2D localCenter = _padRowLayout->getPadCenter(padIndex);
1251  return localToGlobal( localCenter[0], localCenter[1] );
1252  }
1253 
1255  {
1256 // std::cerr << "FixedDiskLayoutBase::getPadLayoutType() : Warning: " <<std::endl
1257 // << " This is deprecated (ambiguous for polar coordinate systems)"<< std::endl
1258 // << " Please use getCoordinateType() or getPadLayoutImplType() "<< std::endl;
1259  return getCoordinateType();
1260  }
1261 
1263  {
1264  return PadRowLayout2D::TPCMODULE;
1265  }
1266 
1268  {
1269  return _momsCoordinateType;
1270  }
1271 
1272  const std::vector<double>& TPCModuleImpl::getPlaneExtent() const {
1273  return _planeExtent;
1274  }
1275 
1276  int TPCModuleImpl::getNearestPad(double x, double y) const{
1277  Vector2D temp = globalToLocal(x,y);
1278  return _padRowLayout->getNearestPad(temp[0],temp[1]);
1279  }
1280 
1281  bool TPCModuleImpl::isInsidePad(double c0, double c1, int padIndex) const{
1282  Vector2D temp = globalToLocal(c0,c1);
1283  return _padRowLayout->isInsidePad(temp[0],temp[1],padIndex);
1284  }
1285 
1286  bool TPCModuleImpl::isInsidePad(double c0, double c1) const{
1287  Vector2D temp = globalToLocal(c0,c1);
1288 
1289  switch (_padRowLayout->getCoordinateType())
1290  {
1291  case PadRowLayout2D::CARTESIAN :
1292  // don't do anything
1293  break;
1294  case PadRowLayout2D::POLAR :
1295  while ( temp[1] < _localModuleExtent[2] )
1296  temp[1] += 2*M_PI;
1297  while ( temp[1] >= _localModuleExtent[2] + 2*M_PI )
1298  temp[1] -= 2*M_PI;
1299  }
1300 
1301  int nearestPad = _padRowLayout->getNearestPad(temp[0],temp[1]);
1302  return _padRowLayout->isInsidePad(temp[0],temp[1],nearestPad);
1303  }
1304 
1305  bool TPCModuleImpl::isInsideModule(double c0, double c1) const{
1306  // first convert to local coordinates
1307  Vector2D localC = globalToLocal(c0, c1);
1308 
1309  // wrap angle to phiMin -- phiMin + 2pi for polar coordinates
1310  switch (_padRowLayout->getCoordinateType())
1311  {
1312  case PadRowLayout2D::CARTESIAN :
1313  // don't do anything
1314  break;
1315  case PadRowLayout2D::POLAR :
1316  while ( localC[1] < _localModuleExtent[2] )
1317  localC[1] += 2*M_PI;
1318  while ( localC[1] >= _localModuleExtent[2] + 2*M_PI )
1319  localC[1] -= 2*M_PI;
1320  }
1321 
1322  // if inside the local module extent it is inside the module
1323  if (localC[0] >=_localModuleExtent[0] && localC[0] <=_localModuleExtent[1] &&
1324  localC[1] >=_localModuleExtent[2] && localC[1] <=_localModuleExtent[3] )
1325  {
1326  return true;
1327  }
1328  else
1329  return false;
1330  }
1331 
1332  double TPCModuleImpl::getDistanceToPad(double c0, double c1, int padIndex) const{
1333  Vector2D localCoordinates = globalToLocal(c0,c1);
1334  return _padRowLayout->getDistanceToPad(localCoordinates[0],localCoordinates[1], padIndex);
1335 
1336  }
1337 
1338  double TPCModuleImpl::getDistanceToModule(double c0, double c1) const{
1339  // first convert to local coordinates
1340  Vector2D localC = globalToLocal(c0, c1);
1341 
1342  // wrap angle to phiMin -- phiMin + 2pi for polar coordinates
1343  switch (_padRowLayout->getCoordinateType())
1344  {
1345  case PadRowLayout2D::CARTESIAN :
1346  // don't do anything
1347  break;
1348  case PadRowLayout2D::POLAR :
1349  while ( localC[1] < _localModuleExtent[2] )
1350  localC[1] += 2*M_PI;
1351  while ( localC[1] >= _localModuleExtent[2] + 2*M_PI )
1352  localC[1] -= 2*M_PI;
1353  }
1354 
1355  // The easy part which works for both polar and cartesian coordinates.
1356  // If localC[1] is in the active rage (y positon or sector) it is the distance in localC[0]
1357 
1358  if (localC[1] >= _localModuleExtent[2] && localC[1] <= _localModuleExtent[3])
1359  {
1360  if (localC[0] < _localModuleExtent[0])
1361  {
1362  return (_localModuleExtent[0] - localC[0]);
1363  }
1364  else if (localC[0] <= _localModuleExtent[1]) // inside the actice area
1365  {
1366  return 0.;
1367  }
1368  else
1369  {
1370  return (localC[0] - _localModuleExtent[1]);
1371  }
1372  }
1373  else switch (_padRowLayout->getCoordinateType())
1374  {
1375  case PadRowLayout2D::CARTESIAN :
1376  if (localC[1] < _localModuleExtent[2])
1377  {
1378  if (localC[0] < _localModuleExtent[0])
1379  {
1380  return sqrt( (_localModuleExtent[0] - localC[0]) * (_localModuleExtent[0] - localC[0]) +
1381  (_localModuleExtent[2] - localC[1]) * (_localModuleExtent[2] - localC[1]) );
1382  }
1383  else if (localC[0] <= _localModuleExtent[1]) // inside the actice area
1384  {
1385  return (_localModuleExtent[2] - localC[1]);
1386  }
1387  else
1388  {
1389  return sqrt( (localC[0] - _localModuleExtent[1]) * (localC[0] - _localModuleExtent[1]) +
1390  (_localModuleExtent[2] - localC[1]) * (_localModuleExtent[2] - localC[1]) );
1391  }
1392  }
1393  else // (localC[1] > _localModuleExtent[3])
1394  if (localC[0] < _localModuleExtent[0])
1395  {
1396  return sqrt( (_localModuleExtent[0] - localC[0]) * (_localModuleExtent[0] - localC[0]) +
1397  (localC[1] - _localModuleExtent[3]) * (localC[1] - _localModuleExtent[3]) );
1398  }
1399  else if (localC[0] <= _localModuleExtent[1]) // inside the actice area
1400  {
1401  return (localC[1] - _localModuleExtent[3]);
1402  }
1403  else
1404  {
1405  return sqrt( (localC[0] - _localModuleExtent[1]) * (localC[0] - _localModuleExtent[1]) +
1406  (localC[1] - _localModuleExtent[3]) * (localC[1] - _localModuleExtent[3]) );
1407  }
1408  break;
1409  case PadRowLayout2D::POLAR :
1410  {
1411  // calculate pca to straight line along radius with phi_min;
1412 
1413  // determine r_intersect for x = r_intersect * cos(_phiMin) = r* cos(phi) - m * sin(_phiMin)
1414  // y = r_intersect * sin(_phiMin) = r*sin(phi) + m * cos(_phiMin)
1415  // solve this to r_intersect and m
1416  double r_intersect_phiMin = localC[0] * (cos(localC[1])*cos(_localModuleExtent[2]) + sin(localC[1])*sin(_localModuleExtent[2]));
1417  double m_phiMin = localC[0] * (cos(localC[1])*sin(_localModuleExtent[2]) - sin(localC[1])*cos(_localModuleExtent[2]));
1418 
1419  double distance_phiMin;
1420  if ( r_intersect_phiMin < _localModuleExtent[0] )
1421  {
1422  // you can check this formula by calculaing sqrt( (x-x_min)^2 - (y-y_min)^2 )
1423  // where x_min = r_min cos(phi_min) etc.
1424  distance_phiMin = sqrt( localC[0]*localC[0] + _localModuleExtent[0]*_localModuleExtent[0] -2 * _localModuleExtent[0] * r_intersect_phiMin );
1425  }
1426  else
1427  if ( r_intersect_phiMin > _localModuleExtent[1] )
1428  {
1429  distance_phiMin = sqrt( localC[0]*localC[0] + _localModuleExtent[1]*_localModuleExtent[1]
1430  -2 * _localModuleExtent[1] * r_intersect_phiMin );
1431  }
1432  else
1433  distance_phiMin = fabs( m_phiMin );
1434 
1435 
1436  // now the same for _phiMax
1437  double r_intersect_phiMax = localC[0] * (cos(localC[1])*cos(_localModuleExtent[3]) + sin(localC[1])*sin(_localModuleExtent[3]));
1438  double m_phiMax = localC[0] * (cos(localC[1])*sin(_localModuleExtent[3]) - sin(localC[1])*cos(_localModuleExtent[3]));
1439 
1440  double distance_phiMax;
1441  if ( r_intersect_phiMax < _localModuleExtent[0] )
1442  {
1443  // you can check this formula by calculaing sqrt( (x-x_max)^2 - (y-y_max)^2 )
1444  // where x_max = r_min cos(phi_max) etc.
1445  distance_phiMax = sqrt( localC[0]*localC[0] + _localModuleExtent[0]*_localModuleExtent[0] -2 * _localModuleExtent[0] * r_intersect_phiMax );
1446  }
1447  else
1448  if ( r_intersect_phiMax > _localModuleExtent[1] )
1449  {
1450  distance_phiMax = sqrt( localC[0]*localC[0] + _localModuleExtent[1]*_localModuleExtent[1] -2 * _localModuleExtent[1] * r_intersect_phiMax );
1451  }
1452  else
1453  distance_phiMax = fabs( m_phiMax );
1454 
1455  return (distance_phiMin < distance_phiMax ? distance_phiMin : distance_phiMax);
1456  }
1457  break;
1458  default:
1459  throw gear::Exception("TPCModuleImpl::getDistanceToModule: unkown coorinate type");
1460  }
1461  return 0.;
1462  }
1463 
1464  bool TPCModuleImpl::isOverlapping(TPCModule * /*testThisModule*/) const {
1465  // I don't have the slightest idea how to test whether modules are overlapping
1466  throw gear::NotImplementedException("TPCModuleImpl::isOverlapping: This is currently not implemented.");
1467  return false;
1468  }
1469 
1470  void TPCModuleImpl::setBorderWidth(double border) {
1471  _border = border;
1472  // recalculate the plane extents
1474  }
1475 
1476  void TPCModuleImpl::setOffset(double x_r, double y_phi)
1477  {
1478  _offset[0] = x_r;
1479  _offset[1] = y_phi;
1480 
1481  switch (_momsCoordinateType)
1482  {
1483  case PadRowLayout2D::POLAR :
1484  {
1485  _offset_cartesian[0] = x_r * std::cos( y_phi );
1486  _offset_cartesian[1] = x_r * std::sin( y_phi );
1487  }
1488  break;
1489  case PadRowLayout2D::CARTESIAN :
1490  {
1491  _offset_cartesian[0] = x_r;
1492  _offset_cartesian[1] = y_phi;
1493  }
1494  break;
1495  default:
1496  throw gear::Exception("TPCModuleImpl::globalToLocal: unkown coorinate type");
1497  }
1498  // recalculate the plane extents
1501  }
1502 
1504  {
1505  _zPosition = z;
1506  _zPositionIsSet = true;
1507  }
1508 
1509  void TPCModuleImpl::setAngle(double angle)
1510  {
1511  _angle= angle;
1512  _cos_angle = std::cos( angle );
1513  _sin_angle = std::sin( angle );
1514  // recalculate the plane extents
1517  }
1518 
1519  void TPCModuleImpl::setReadoutFrequency(double frequency)
1520  {
1521 // std::cout << "TPCModuleImpl: Warning: "
1522 // << "deprecated use of setReadoutFreuqency()." << std::endl
1523 // << " Please define readout freuqency in constructor!"
1524 // << std::endl;
1525 
1526  _readoutFrequency = frequency;
1527  }
1528 
1530  {
1531  if ( (_momsCoordinateType == _padRowLayout->getCoordinateType())
1532  && (_angle == 0. )
1533  && ( _offset[0] == 0. )
1534  && ( _offset[1] == 0. )
1535  && ( _zPosition > 0 ) ) // not >= 0, 0 (prototype) is negative half TPC
1536  {
1537  _localIsGlobal = true;
1538  }
1539  else
1540  {
1541  _localIsGlobal = false;
1542  }
1543  }
1544 
1546 
1548 
1549  return _zPosition;
1550  }
1551 
1552 }// namespace gear
bool _zPositionIsSet
Flag to show whether the setZPosition() function had been called.
Definition: TPCModuleImpl.h:43
virtual bool isInsideModule(double c0, double c1) const
True if global coordinate (c0,c1) is within this modules area of amplification/interest.
virtual int getNearestPad(double x, double y) const
The index of the pad nearest to the given point in Global 2d coordinates (x,y,) or (r...
std::vector< double > calculateGlobalExtentPolarPolar(std::vector< double > localExtent)
Calculate the global extent for a given local extent if both local and global coordinate system are p...
void setOffset(double x_r, double y_phi)
Set the offset of the local pad plane wrt.
Abstract description of a planar subdetector with pads (cells) that are positioned in rows (circular ...
Base exception class for GEAR - all other exceptions extend this.
Definition: GEAR.h:41
virtual int getPadLayoutImplType() const
The type of the row layout implementation: PadRowLayout2D.TPCMODULE.
std::vector< double > _localModuleExtent
The module extend in the pad plane&#39;s coordinate system.
Definition: TPCModuleImpl.h:28
virtual bool isOverlapping(TPCModule *testThisModule) const
Returns True if this and The given module * overlap pad regions Note: overlaping sensitive regions is...
virtual int getPadLayoutType() const
virtual double getDistanceToPad(double c0, double c1, int index) const
Returns the distance from a global coodinate (c0,c1), to a given pad&#39;s nearest boundery; (c0...
virtual bool isInsidePad(double c0, double c1, int padIndex) const =0
True if coordinate (c0,c1) is within the given pad.
std::vector< double > calculateGlobalExtentCartesianPolar(std::vector< double > localExtent)
Calculate the global extent for a given local extent if the global coordinates are cartesian and the ...
void checkLocalIsGlobal()
Function to set the _localIsGlobal flag in case both coordinate systems are identical.
int _momsCoordinateType
AKA coordinate type of the TPC which contains this module.
Definition: TPCModuleImpl.h:37
gear::Vector2D _offset
The offset in cordinates described by _momsCoordinateType.
Definition: TPCModuleImpl.h:31
NotImplementedException used for features that are not implemented.
Definition: GEAR.h:81
TPCModuleImpl(int moduleID, PadRowLayout2D *padRowLayout, int TPCCoordinateType, double readoutFrequency=0)
Construct the empty RectangularPadRowLayout with the width and x position specified through xMin and ...
virtual int getCoordinateType() const =0
The type of the row layouts coordinate system: PadRowLayout2D.CARTESIAN or PadRowLayout2D.POLAR.
void setReadoutFrequency(double frequency)
kept for backward compatibility, please set readout frequency in constructor
void setZPosition(double z)
Set the z position of the module.
virtual double getZPosition() const
Returns the z position of the module.
PadRowLayout2D * clone() const
Returns a copy (clone) of this class.
double _sin_angle
For performance: cache the sine of the angle.
Definition: TPCModuleImpl.h:36
virtual const std::vector< double > & getPlaneExtent() const
Inherited from PadRowLayout2D.
TPCModuleImpl & operator=(const TPCModuleImpl &)
The assignment operator.
virtual ~TPCModuleImpl()
Destructor.
void cleanup()
function to delete all the objects pointed to and owned by the TPCModule.
void copy_and_assign(const TPCModuleImpl &)
function to copy all internal variables, incl.
double _cos_angle
For performance: cache the cosine of the angle.
Definition: TPCModuleImpl.h:35
gear::Vector2D localToGlobal(double c0, double c1) const
Returns the global coordinates for a point in local coordinates.
virtual gear::Vector2D getPadCenter(int padIndex) const
The center of the pad in mother&#39;s 2d coordinates, (x,y) or (r,phi).
double _angle
The angle wrt. the local coordinate system.
Definition: TPCModuleImpl.h:34
virtual double getDistanceToModule(double c0, double c1) const
Returns distastance from a global coodinate (c0,c1), to the module&#39;s nearest boundery; (c0...
void convertLocalPlaneToGlobalPlaneExtend(void)
Transforms the local planeExtend to a global planeExtend, global moduleExtend and localModuleExtend...
gear::Vector2D _offset_cartesian
The offset in cartesian cordinates.
Definition: TPCModuleImpl.h:32
double _zPosition
The z positon of the module.
Definition: TPCModuleImpl.h:33
virtual bool isInsidePad(double c0, double c1, int padIndex) const
True if coordinate (x,y) is within the given pad.
double _border
Area around a pad Plane to extend the amplification reagion so that the outmost pads don&#39;t loose elec...
Definition: TPCModuleImpl.h:39
virtual double getDistanceToPad(double c0, double c1, int padIndex) const =0
Returns the closest distance to the edge (outer border) of the pad.
std::vector< double > calculateGlobalExtentCartesianCartesian(std::vector< double > localExtent)
Calculate the global extent for a given local extent if both local and global coordinate system are c...
virtual PadRowLayout2D * clone() const =0
Returns a copy (clone) of this class.
virtual const std::vector< double > & getPlaneExtent() const =0
Extent of the sensitive plane - [xmin,xmax,ymin,ymax] CARTESIAN or [rmin,rmax,phimin,phimax] POLAR.
virtual int getNearestPad(double c0, double c1) const =0
The index of the pad nearest to the given point in 2d coordinates (x,y,) or (r,phi).
An exception that is special for the TPCModule.
Definition: TPCModule.h:48
A wrapper Class for PadRowLayout2D which converts between the actual pad layouts local coodinate syst...
Definition: TPCModule.h:41
A wrapper Class for PadRowLayout2D, allowing which converts between local and global coordinate syste...
Definition: TPCModuleImpl.h:23
gear::Vector2D globalToLocal(double c0, double c1) const
Returns the local coordinates for a point in global coordinates.
virtual Vector2D getPadCenter(int padIndex) const =0
The center of the pad in 2d coordinates, (x,y) or (r,phi).
virtual int getCoordinateType() const
Identical to getTPCCoordinateType(), because this is the type of coordinates which are returned...