GEAR  1.9.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Friends Pages
RectangularPadRowLayout.cc
1 #include "gearimpl/RectangularPadRowLayout.h"
2 
3 #include <cmath>
4 #include <math.h>
5 #include <iostream>
6 #include <stdexcept>
7 #include <sstream>
8 #include <assert.h>
9 #include <cstdlib>
10 
11 namespace gear {
12 
13 
14 
15  RectangularPadRowLayout::RectangularPadRowLayout( double xMin, double xMax , double yMin ) :
16 
17  _nRow(0) ,
18  _nPad(0),
19  _repeatRows(0) {
20 
21  _extent.resize(4) ;
22  _extent[0] = xMin ;
23  _extent[1] = xMax ;
24  _extent[2] = yMin ;
25  _extent[3] = yMin ;
26 
27  }
28 
30  {
31  copy_and_assign(right);
32  }
33 
35  {
36  _nRow = right._nRow;
37  _nPad = right._nPad;
38  _repeatRows = right._repeatRows;
39  _rows = right._rows;
40  _extent = right._extent;
41  _nRows = right._nRows;
42 
43  // just set the _padIndices to an vector of empty entries.
44  // In every instance, also the copied ones, it is filled only at first
45  // usage to save memory
46  // just like in the constructor
47  _padIndices.resize( _nRow ) ;
48  for (std::vector< std::vector<int>* >::iterator rowIter = _padIndices.begin() ;
49  rowIter < _padIndices.end(); rowIter++)
50  {
51  *rowIter=0;
52  }
53  }
54 
56  {
57  return new RectangularPadRowLayout(*this);
58  }
59 
60  void RectangularPadRowLayout::addRow( int nRow, int nPad , double padWidth , double padHeight ,
61  double rowHeight , double leftOffset,
62  double rightOffset ) {
63 
64 
65  // a few sanity checks:
66  assert( nRow > 0 ) ;
67  assert( nPad > 0 ) ;
68  assert( ! ( padWidth < 0. ) ) ;
69  assert( ! ( padHeight < 0. ) ) ;
70  assert( ! ( rowHeight < 0. ) ) ;
71  assert( ! ( leftOffset < 0. ) ) ;
72  assert( ! ( rightOffset < 0. ) ) ;
73 
74 
75  double xMin = _extent[0] + leftOffset ;
76  double xMax = _extent[1] - rightOffset ;
77 
78  double rowWidth = xMax - xMin ;
79 
80  if( nPad * padWidth > rowWidth ) {
81 
82  std::stringstream sstr ;
83  sstr << "RectangularPadRowLayout::addRow: can't fit "
84  << nPad << " pads in row with width " << rowWidth
85  << " ( offsets left/right: " << leftOffset << " / " << rightOffset << " ) " ;
86 
87  throw Exception( sstr.str() ) ;
88  }
89 
90  Row row ;
91 
92  _nPad += abs( nRow ) * abs( nPad ) ;
93 
94  row.WidthPerPad = rowWidth / nPad ;
95 
96  if( rowHeight == 0.0 )
97  rowHeight = padHeight ;
98 
99  if( rowHeight < padHeight ){
100 
101  std::stringstream sstr ;
102  sstr << "RectangularPadRowLayout::addRow: row height ( "
103  << rowHeight << " ) can't be smaller than pad height ( " << padHeight << " ) !" ;
104 
105  throw Exception( sstr.str() ) ;
106  }
107 
108 
109  row.NPad = nPad ;
110  row.PadWidth = padWidth ;
111  row.PadHeight = padHeight ;
112 
113  row.Height = rowHeight ;
114 
115  row.LeftOffset = leftOffset ;
116  row.RightOffset = rightOffset ;
117 
118 
119  for( int i = 0 ; i < nRow ; i++ ) {
120 
121  row.Center = _extent[3] + rowHeight / 2. ;
122 
123  _extent[3]+= rowHeight ;
124 
125  _rows.push_back( row ) ;
126 
127  _padIndices.push_back( 0 ) ;
128  }
129 
130  _nRows.push_back( nRow ) ; // keep track of nRows as they are added
131 
132  }
133 
134  void RectangularPadRowLayout::repeatRows(unsigned count) {
135 
136  if( _repeatRows > 0 ) // ignore all but first call
137  return ;
138 
139  _repeatRows = count ;
140 
141  int nRow = _rows.size() ;
142 
143  for(unsigned i=0 ; i< count-1 ; ++i ){
144  for(int j=0 ; j< nRow; ++j ){
145 
146  const Row& r = _rows[j] ;
147 
148  addRow( 1 , r.NPad , r.PadWidth ,r.PadHeight ,
149  r.Height , r.LeftOffset, r.RightOffset ) ;
150 
151  }
152  }
153  }
154 
156  return _rows.size() ;
157  }
158 
159  double RectangularPadRowLayout::getRowHeight(int rowNumber) const {
160  return _rows.at(rowNumber).Height ;
161  }
162 
163  double RectangularPadRowLayout::getPadHeight(int padIndex) const {
164 
165  int rowNum = getRowNumber( padIndex ) ;
166 
167  return _rows[rowNum].PadHeight ;
168  }
169 
170 
171  double RectangularPadRowLayout::getPadWidth(int padIndex) const {
172 
173  int rowNum = getRowNumber( padIndex ) ;
174 
175  return _rows[rowNum].PadWidth ;
176  }
177 
178  double RectangularPadRowLayout::getPadPitch(int padIndex) const {
179 
180  int rowNum = getRowNumber( padIndex ) ;
181 
182  return _rows[rowNum].WidthPerPad ;
183  }
184 
185 
187 
188  int rowNum = getRowNumber( padIndex ) ;
189  int padNum = getPadNumber( padIndex ) ;
190 
191  const Row& row = _rows[ rowNum ] ;
192 
193  double x = _extent[0] + row.LeftOffset + padNum * row.WidthPerPad + row.WidthPerPad / 2. ;
194 
195  double y = row.Center ;
196 
197  return Vector2D( x , y ) ;
198  }
199 
201  {
202 // std::cerr << "FixedDiskLayoutBase::getPadLayoutType() : Warning: " <<std::endl
203 // << " This is deprecated (ambiguous for polar coordinate systems)"<< std::endl
204 // << " Please use getCoordinateType() or getPadLayoutImplType() "<< std::endl;
205  return getCoordinateType();
206  }
207 
209  {
210  cleanup();
211  }
212 
214  {
215  cleanup();
216  copy_and_assign(right);
217  return *this;
218  }
219 
221  {
222  for( unsigned i=0; i<_padIndices.size(); ++i ){
223  delete _padIndices[i] ;
224  }
225  }
226 
227  const std::vector<int>& RectangularPadRowLayout::getPadsInRow(int rowNumber) const {
228 
229  static std::vector<int> empty ;
230 
231  try {
232 
233  if( _padIndices.at(rowNumber ) == 0 ) {
234 
235  int nPad = _rows.at(rowNumber).NPad ;
236 
237  _padIndices[ rowNumber ] = new std::vector<int>( nPad ) ;
238 
239  for(int i = 0 ; i < nPad ; i++){
240 
241  _padIndices[rowNumber]->operator[](i) = getPadIndex( rowNumber , i ) ;
242  }
243 
244  }
245  } catch( std::out_of_range& r) {
246 
247  // std::cout << " RectangularPadRowLayout::getPadsInRow : no row " << rowNumber << std::endl ;
248  return empty ;
249 
250  }
251 
252  return *_padIndices[ rowNumber ] ;
253  }
254 
255 
256  int RectangularPadRowLayout::getRowNumber(int padIndex) const {
257 
258  int rn = ( 0xffff0000 & padIndex ) >> 16 ;
259 
260  if( rn < 0 || rn > int(_rows.size() - 1) ){
261 
262  std::stringstream sstr ;
263 
264  sstr << "RectangularPadRowLayout::getRowNumber: illegal rownumber: "
265  << rn << " for padIndex 0x" << std::hex << padIndex << " nRows: " << _rows.size() << std::dec ;
266 
267  throw Exception( sstr.str() ) ;
268  }
269 
270  return rn ;
271  }
272 
273 
274  int RectangularPadRowLayout::getPadIndex(int rowNum, int padNum) const {
275 
276 
277  if( (unsigned) rowNum > _rows.size() - 1 ) {
278 
279  throw std::out_of_range(" RectangularPadRowLayout::getPadIndex row number too large !");
280  }
281 
282  if( padNum > _rows[rowNum].NPad - 1 ) {
283 
284  std::stringstream sstr ;
285 
286  sstr << "RectangularPadRowLayout::getPadIndex: pad number too large: "
287  << padNum << " only " << _rows[rowNum].NPad << " pads in row " << rowNum ;
288 
289  throw std::out_of_range( sstr.str() );
290  }
291 
292  return (rowNum << 16 ) | ( 0x0000ffff & padNum ) ;
293 
294  }
295 
296 int RectangularPadRowLayout::getNearestPadOld(double x, double y) const {
297 
298  // move from outside of pad plane to edge of pad plane
299  if( x < _extent[0] ) x = _extent[0] ;
300  if( x > _extent[1] ) x = _extent[1] ;
301  if( y < _extent[2] ) y = _extent[2] ;
302  if( y > _extent[3] ) y = _extent[3] ;
303 
304  int rowNum = 0 ;
305 
306  double dMin = 2. * ( _extent[3] - _extent[2] ) ;
307 
308  // find closest row - NB row heights might vary and rows can have offsets !
309  // thus we need to loop over all rows
310 
311  for( unsigned i=0 ; i < _rows.size() ; ++i ) {
312 
313  const Row& row = _rows[i] ;
314 
315  double xmin = _extent[0] + row.LeftOffset ;
316  double xmax = _extent[1] - row.RightOffset ;
317  double ymin = row.Center - row.PadHeight / 2. ;
318  double ymax = row.Center + row.PadHeight / 2. ;
319 
320  Vector2D p( x, y ) ;
321 
322  double d ;
323 
324  if( ( d = distanceToBox( p , xmin, ymin, xmax, ymax ) ) < dMin ){
325 
326  dMin = d ;
327  rowNum = i ;
328 
329 
330  if( dMin < 0.0 ) break ; // if distance is negative we are already inside a pad
331  }
332  }
333 
334  int padNum = 0 ;
335 
336  // now that we have the row we need the closest pad
337  const Row& row = _rows[rowNum] ;
338 
339  if( x < ( _extent[0] + row.LeftOffset ) ){
340 
341  padNum = 0 ;
342 
343  } else if( x >= ( _extent[1] - row.RightOffset ) ) {
344 
345  padNum = row.NPad - 1 ;
346 
347  } else {
348 
349  padNum = (int) ( ( x - ( _extent[0] + row.LeftOffset ) ) / row.WidthPerPad ) ;
350 
351  }
352 
353  return getPadIndex( rowNum , padNum ) ;
354  }
355 
356 
357 int RectangularPadRowLayout::getNearestPad(double x, double y) const {
358 
359  // move from outside of pad plane to edge of pad plane
360  if( x < _extent[0] ) x = _extent[0] ;
361  if( x > _extent[1] ) x = _extent[1] ;
362  if( y < _extent[2] ) y = _extent[2] ;
363  if( y > _extent[3] ) y = _extent[3] ;
364 
365  // make a best guess at the starting row by assuming all rows are the same height
366  int row_number = (int)( round( (_rows.size() - 1) * (y - _extent[2]) / (_extent[3] - _extent[2]) ) );
367 
368  // do a binary search for the nearest row
369  while( true ) {
370 
371  const Row &row = _rows[row_number];
372  const double y_displacement = y - row.Center;
373 
374  //std::cout << "Checking row " << row_number << ", centre: " << row.Center << ", displacement: " << y_displacement << "mm" << std::endl;
375 
376  if( fabs(y_displacement) <= (row.PadHeight/2) ) {
377 
378  // this is the correct row
379  break;
380  }
381  else if( fabs(y_displacement) <= (row.Height/2) ) {
382 
383  // check the next row of pads, it could be closer to them then this row
384  const int next_row_number = (y_displacement < 0)? row_number - 1: row_number + 1;
385  const Row &next_row = _rows[next_row_number];
386 
387  const double y_distance_from_pads = fabs(y_displacement) - (row.PadHeight/2);
388  const double y_distance_from_next_pads = fabs(y - next_row.Center) - (next_row.PadHeight/2);
389 
390  row_number = (y_distance_from_next_pads < y_distance_from_pads)? next_row_number: row_number;
391  break;
392  }
393  else {
394  // it wasn't in this row... find the next best guess
395  int remaining_rows;
396  double remaining_distance;
397  double offset;
398 
399  if( y_displacement < 0 ) {
400 
401  remaining_rows = row_number;
402  remaining_distance = row.Center - _extent[2] - (row.Height/2.);
403  offset = y_displacement + (row.Height/2);
404  }
405  else {
406 
407  remaining_rows = _rows.size() - row_number - 1;
408  remaining_distance = _extent[3] - row.Center - (row.Height/2.);
409  offset = y_displacement - (row.Height/2);
410  }
411 
412  const double param = remaining_rows * (offset / remaining_distance);
413  const int delta_row = (int)((param < 0)? floor(param): ceil(param));
414 
415  if (delta_row==0)
416  {
417  // hm, something went wrong in the logic. The next best guess should not be the
418  // same row. This can happen due to rounding errors. So within numerical precision
419  // we already found the nearest row. Breaking here avouids an endless loop.
420  std::cout << "delta_row is 0, breaking loop" << std::endl;
421  break;
422  }
423 
424  row_number += delta_row;
425  }
426 
427  /*std::cout << "Hit Enter to continue... \n";
428  std::cin.get();*/
429  }
430 
431  // we have the row number... find the pad number
432  int pad_number = 0 ;
433 
434  // now that we have the row we need the closest pad
435  const Row& row = _rows[row_number] ;
436 
437  if( x <= ( _extent[0] + row.LeftOffset ) ) {
438 
439  pad_number = 0 ;
440 
441  } else if( x >= ( _extent[1] - row.RightOffset ) ) {
442 
443  pad_number = row.NPad - 1;
444 
445  } else {
446 
447  pad_number = (int) ( ( x - ( _extent[0] + row.LeftOffset ) ) / row.WidthPerPad ) ;
448 
449  }
450 
451  return getPadIndex( row_number , pad_number ) ;
452  }
453 
454 
456 
457  int pn = getPadNumber( padIndex ) + 1 ;
458  int rn = getRowNumber( padIndex) ;
459 
460  int nPad = _rows.at(rn).NPad ;
461 
462  if( pn > nPad-1 ){
463  throw Exception("RectangularPadRowLayout::getRightNeighbour: no right neighbour pad !");
464 // throw std::out_of_range("RectangularPadRowLayout::getRightNeighbour: no right neighbour pad !");
465  }
466 
467  return getPadIndex( rn , pn ) ;
468  }
469 
471 
472  int pn = getPadNumber( padIndex ) - 1 ;
473  int rn = getRowNumber( padIndex) ;
474 
475  if( pn < 0 ){
476 // std::cerr << " hgoing top throw exception: getLeftNeighbour: no left neighbour pad !" << std::endl ;
477  throw Exception("RectangularPadRowLayout::getLeftNeighbour: no left neighbour pad !");
478 // throw std::out_of_range("RectangularPadRowLayout::getLeftNeighbour: no left neighbour pad !");
479  }
480 
481  return getPadIndex( rn , pn ) ;
482  }
483 
484 
485  bool RectangularPadRowLayout::isInsidePad(double x, double y, int padIndex) const {
486 
487  int pn = getPadNumber( padIndex ) ;
488  int rn = getRowNumber( padIndex) ;
489 
490  const Row& row = _rows[rn] ;
491 
492  // --- ---- insensitive gap --------
493  double pXMin = _extent[0] + row.LeftOffset + pn * row.WidthPerPad + ( row.WidthPerPad - row.PadWidth )/ 2.;
494  double pXMax = _extent[0] + row.LeftOffset + (pn+1) * row.WidthPerPad - ( row.WidthPerPad - row.PadWidth )/ 2.;
495  double pYMin = row.Center - row.PadHeight / 2. ;
496  double pYMax = row.Center + row.PadHeight / 2. ;
497 
498  return ( pXMin <= x && x <= pXMax &&
499  pYMin <= y && y <= pYMax ) ;
500  }
501 
502  bool RectangularPadRowLayout::isInsidePad(double x, double y) const {
503 
504  // outside of pad plane
505  if( x < _extent[0] || x > _extent[1] ||
506  y < _extent[2] || y > _extent[3] )
507 
508  return false ;
509 
510  return isInsidePad( x , y , getNearestPad( x, y ) ) ;
511  }
512 
514  double xmin, double ymin,
515  double xmax, double ymax ) const {
516 
517  // depending on the points position wrt. the box
518  // the distance is computed in a different way:
519  // xmin xmax
520  // x | x | x
521  // ------|===========|--------- ymax
522  // x || || x
523  // ------|===========|--------- ymin
524  // x | x | x
525 
526 
527  double x = p[0] ;
528  double y = p[1] ;
529 
530  double d ;
531 
532  if( x < xmin ){
533 
534  if( y < ymin ) {
535 
536  d = sqrt( (xmin-x) * (xmin-x) + (ymin-y) * (ymin-y) ) ;
537 
538  } else if ( y > ymax ) {
539 
540  d = sqrt( (xmin-x) * (xmin-x) + (ymax-y) * (ymax-y) ) ;
541 
542  } else { // ( ymin <= y && y <= ymax )
543 
544  d = xmin - x ;
545  }
546 
547  } else if( x > xmax ) {
548 
549  if( y < ymin ) {
550 
551  d = sqrt( (xmax-x) * (xmax-x) + (ymin-y) * (ymin-y) ) ;
552 
553  } else if ( y > ymax ) {
554 
555  d = sqrt( (xmax-x) * (xmax-x) + (ymax-y) * (ymax-y) ) ;
556 
557  } else { // ( ymin <= y && y <= ymax )
558 
559  d = x - xmax ;
560  }
561 
562  } else { // ( xmin <= x && x <= xmax )
563 
564  if( y < ymin ) {
565 
566  d = ymin - y ;
567 
568  } else if ( y > ymax ) {
569 
570  d = y - ymax ;
571 
572  } else { // ( ymin <= y && y <= ymax )
573 
574  d = - 1. ; // inside the box !
575  }
576  }
577  return d ;
578  }
579 
580  double RectangularPadRowLayout::getDistanceToPad(double c0, double c1, int padIndex) const
581  {
582  // calculate xMin, xMax, yMin, yMax from pad coordinates
583  Vector2D padCentre = getPadCenter(padIndex);
584 
585 // int rowNumber = getRowNumber(padIndex);
586  double padHeight = getPadHeight(padIndex);
587  double padWidth = getPadWidth(padIndex);
588 
589  Vector2D testCoordinates;
590  testCoordinates[0]=c0; testCoordinates[1]=c1;
591 
592  double distance = distanceToBox( testCoordinates, padCentre[0] - padWidth*0.5,//xmin
593  padCentre[1] - padHeight*0.5,//ymin
594  padCentre[0] + padWidth*0.5,//xmax
595  padCentre[1] + padHeight*0.5);//ymax
596 
597  return (distance < 0. ? 0. : distance);
598  }
599 } // namespace
600 
double distanceToBox(const Vector2D &p, double xMin, double yMin, double xMax, double yMax) const
Helper function for finding the nearest pad - returns the distance for points outside the box and -1...
virtual double getDistanceToPad(double c0, double c1, int padIndex) const
Returns the closest distance to the edge (outer border) of the pad.
virtual int getRowNumber(int padIndex) const
The number of the row that contains the pad at padIndex - numbering starts at y==0 (bottom)...
Abstract description of a planar subdetector with pads (cells) that are positioned in rows (circular ...
virtual double getPadPitch(int padIndex) const
The pitch (i.
Base exception class for GEAR - all other exceptions extend this.
Definition: GEAR.h:41
virtual int getNearestPad(double x, double y) const
The index of the pad nearest to the given point in 2d coordinates (x,y,) or (r,phi).
PadRowLayout2D * clone() const
Returns a copy (clone) of this class.
virtual int getPadIndex(int rowNum, int padNum) const
Create a padIndex for the given row and pad ( column ) number.
virtual ~RectangularPadRowLayout()
Destructor.
virtual const std::vector< int > & getPadsInRow(int rowNumber) const
Indices of all pads in row rowNumber (row indices start from 0 at the bottom (CARTESIAN) or at the ce...
virtual double getPadWidth(int padIndex) const
The width of the pad at padIndex in mm.
virtual Vector2D getPadCenter(int padIndex) const
The center of the pad in 2d coordinates, (x,y) or (r,phi).
RectangularPadRowLayout(double xMin, double xMax, double yMin=0.0)
Construct the empty RectangularPadRowLayout with the width and x position specified through xMin and ...
virtual void addRow(int nRow, int nPad, double padWidth, double padHeight, double rowHeight=0.0, double leftOffset=0.0, double rightOffset=0.0)
Add nRow rows with the given parameters.
virtual int getPadNumber(int padIndex) const
The pad number (column) within the row - numbering starts at x==0 (left).
RectangularPadRowLayout & operator=(const RectangularPadRowLayout &)
The assignment operator.
virtual double getRowHeight(int rowNumber) const
The row height in mm.
virtual bool isInsidePad(double x, double y, int padIndex) const
True if coordinate (x,y) is within the given pad.
void cleanup()
function to delete all the objects pointed to and owned by the GearMgr.
virtual int getRightNeighbour(int padIndex) const
The index of the right neighbour pad.
virtual double getPadHeight(int padIndex) const
The height of the pad in mm.
void copy_and_assign(const RectangularPadRowLayout &)
function to copy all internal variables, incl.
virtual void repeatRows(unsigned count)
Repeat the current rows &#39;count&#39; times - this allows to easily repeat a pattern of several rows...
virtual int getLeftNeighbour(int padIndex) const
The index of the left neighbour pad.
virtual int getCoordinateType() const
The type of the row layouts coordinate system: PadRowLayout2D.CARTESIAN.
Implementation of PadRowLayout2D for a rectangular row based layout where all pads in a given row are...
Internal helper class for RectangularPadRowLayout.
virtual int getNRows() const
The number of rows.