Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Corryvreckan
Corryvreckan
Commits
374016b3
Commit
374016b3
authored
Mar 30, 2020
by
Jin Zhang
Browse files
add PixelDetector file
parent
272a6ab0
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/core/detector/PixelDetector.cpp
0 → 100644
View file @
374016b3
/** @file
* @brief Implementation of the detector model
* @copyright Copyright (c) 2017-2020 CERN and the Corryvreckan authors.
* This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
* In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
* Intergovernmental Organization or submit itself to any jurisdiction.
*/
#include
<fstream>
#include
<map>
#include
<string>
#include
"Math/RotationX.h"
#include
"Math/RotationY.h"
#include
"Math/RotationZ.h"
#include
"Math/RotationZYX.h"
#include
"PixelDetector.hpp"
#include
"core/utils/log.h"
#include
"exceptions.h"
using
namespace
ROOT
::
Math
;
using
namespace
corryvreckan
;
PixelDetector
::
PixelDetector
(
const
Configuration
&
config
)
:
Detector
(
config
)
{
// Set detector position and direction from configuration file
SetPostionAndOrientation
(
config
);
// intialize transform
this
->
initialise
();
// Auxiliary devices don't have: number_of_pixels, pixel_pitch, spatial_resolution, mask_file, region-of-interest
if
(
!
isAuxiliary
())
{
buildAxes
(
config
);
}
}
void
PixelDetector
::
buildAxes
(
const
Configuration
&
config
)
{
m_nPixels
=
config
.
get
<
ROOT
::
Math
::
DisplacementVector2D
<
Cartesian2D
<
int
>>>
(
"number_of_pixels"
);
// Size of the pixels:
m_pitch
=
config
.
get
<
ROOT
::
Math
::
XYVector
>
(
"pixel_pitch"
);
LOG
(
TRACE
)
<<
"Initialized
\"
"
<<
m_detectorType
<<
"
\"
: "
<<
m_nPixels
.
X
()
<<
"x"
<<
m_nPixels
.
Y
()
<<
" px, pitch of "
<<
Units
::
display
(
m_pitch
,
{
"mm"
,
"um"
});
if
(
Units
::
convert
(
m_pitch
.
X
(),
"mm"
)
>=
1
or
Units
::
convert
(
m_pitch
.
Y
(),
"mm"
)
>=
1
or
Units
::
convert
(
m_pitch
.
X
(),
"um"
)
<=
1
or
Units
::
convert
(
m_pitch
.
Y
(),
"um"
)
<=
1
)
{
LOG
(
WARNING
)
<<
"Pixel pitch unphysical for detector "
<<
m_detectorName
<<
": "
<<
std
::
endl
<<
Units
::
display
(
m_pitch
,
{
"nm"
,
"um"
,
"mm"
});
}
// Intrinsic spatial resolution, defaults to pitch/sqrt(12):
m_spatial_resolution
=
config
.
get
<
ROOT
::
Math
::
XYVector
>
(
"spatial_resolution"
,
m_pitch
/
std
::
sqrt
(
12
));
if
(
!
config
.
has
(
"spatial_resolution"
))
{
LOG
(
WARNING
)
<<
"Spatial resolution for detector '"
<<
m_detectorName
<<
"' not set."
<<
std
::
endl
<<
"Using pitch/sqrt(12) as default"
;
}
// region of interest:
m_roi
=
config
.
getMatrix
<
int
>
(
"roi"
,
std
::
vector
<
std
::
vector
<
int
>>
());
if
(
config
.
has
(
"mask_file"
))
{
m_maskfile_name
=
config
.
get
<
std
::
string
>
(
"mask_file"
);
std
::
string
mask_file
=
config
.
getPath
(
"mask_file"
);
LOG
(
DEBUG
)
<<
"Adding mask to detector
\"
"
<<
config
.
getName
()
<<
"
\"
, reading from "
<<
mask_file
;
setMaskFile
(
mask_file
);
processMaskFile
();
}
}
void
PixelDetector
::
SetPostionAndOrientation
(
const
Configuration
&
config
)
{
// Detector position and orientation
m_displacement
=
config
.
get
<
ROOT
::
Math
::
XYZPoint
>
(
"position"
,
ROOT
::
Math
::
XYZPoint
());
m_orientation
=
config
.
get
<
ROOT
::
Math
::
XYZVector
>
(
"orientation"
,
ROOT
::
Math
::
XYZVector
());
m_orientation_mode
=
config
.
get
<
std
::
string
>
(
"orientation_mode"
,
"xyz"
);
if
(
m_orientation_mode
!=
"xyz"
&&
m_orientation_mode
!=
"zyx"
)
{
throw
InvalidValueError
(
config
,
"orientation_mode"
,
"Invalid detector orientation mode"
);
}
LOG
(
TRACE
)
<<
" Position: "
<<
Units
::
display
(
m_displacement
,
{
"mm"
,
"um"
});
LOG
(
TRACE
)
<<
" Orientation: "
<<
Units
::
display
(
m_orientation
,
{
"deg"
})
<<
" ("
<<
m_orientation_mode
<<
")"
;
}
void
PixelDetector
::
processMaskFile
()
{
// Open the file with masked pixels
std
::
ifstream
inputMaskFile
(
m_maskfile
,
std
::
ios
::
in
);
if
(
!
inputMaskFile
.
is_open
())
{
LOG
(
WARNING
)
<<
"Could not open mask file "
<<
m_maskfile
;
}
else
{
int
row
=
0
,
col
=
0
;
std
::
string
id
;
// loop over all lines and apply masks
while
(
inputMaskFile
>>
id
)
{
if
(
id
==
"c"
)
{
inputMaskFile
>>
col
;
if
(
col
>
nPixels
().
X
()
-
1
)
{
LOG
(
WARNING
)
<<
"Column "
<<
col
<<
" outside of pixel matrix, chip has only "
<<
nPixels
().
X
()
<<
" columns!"
;
}
LOG
(
TRACE
)
<<
"Masking column "
<<
col
;
for
(
int
r
=
0
;
r
<
nPixels
().
Y
();
r
++
)
{
maskChannel
(
col
,
r
);
}
}
else
if
(
id
==
"r"
)
{
inputMaskFile
>>
row
;
if
(
row
>
nPixels
().
Y
()
-
1
)
{
LOG
(
WARNING
)
<<
"Row "
<<
col
<<
" outside of pixel matrix, chip has only "
<<
nPixels
().
Y
()
<<
" rows!"
;
}
LOG
(
TRACE
)
<<
"Masking row "
<<
row
;
for
(
int
c
=
0
;
c
<
nPixels
().
X
();
c
++
)
{
maskChannel
(
c
,
row
);
}
}
else
if
(
id
==
"p"
)
{
inputMaskFile
>>
col
>>
row
;
if
(
col
>
nPixels
().
X
()
-
1
||
row
>
nPixels
().
Y
()
-
1
)
{
LOG
(
WARNING
)
<<
"Pixel "
<<
col
<<
" "
<<
row
<<
" outside of pixel matrix, chip has only "
<<
nPixels
().
X
()
<<
" x "
<<
nPixels
().
Y
()
<<
" pixels!"
;
}
LOG
(
TRACE
)
<<
"Masking pixel "
<<
col
<<
" "
<<
row
;
maskChannel
(
col
,
row
);
// Flag to mask a pixel
}
else
{
LOG
(
WARNING
)
<<
"Could not parse mask entry (id
\"
"
<<
id
<<
"
\"
)"
;
}
}
LOG
(
INFO
)
<<
m_masked
.
size
()
<<
" masked pixels"
;
}
}
void
PixelDetector
::
maskChannel
(
int
chX
,
int
chY
)
{
int
channelID
=
chX
+
m_nPixels
.
X
()
*
chY
;
m_masked
[
channelID
]
=
true
;
}
bool
PixelDetector
::
masked
(
int
chX
,
int
chY
)
const
{
int
channelID
=
chX
+
m_nPixels
.
X
()
*
chY
;
if
(
m_masked
.
count
(
channelID
)
>
0
)
return
true
;
return
false
;
}
// Function to initialise transforms
void
PixelDetector
::
initialise
()
{
// Make the local to global transform, built from a displacement and
// rotation
Translation3D
translations
=
Translation3D
(
m_displacement
.
X
(),
m_displacement
.
Y
(),
m_displacement
.
Z
());
Rotation3D
rotations
;
if
(
m_orientation_mode
==
"xyz"
)
{
rotations
=
RotationZ
(
m_orientation
.
Z
())
*
RotationY
(
m_orientation
.
Y
())
*
RotationX
(
m_orientation
.
X
());
}
else
if
(
m_orientation_mode
==
"zyx"
)
{
rotations
=
RotationZYX
(
m_orientation
.
x
(),
m_orientation
.
y
(),
m_orientation
.
x
());
}
m_localToGlobal
=
Transform3D
(
rotations
,
translations
);
m_globalToLocal
=
m_localToGlobal
.
Inverse
();
// Find the normal to the detector surface. Build two points, the origin and a unit step in z,
// transform these points to the global co-ordinate frame and then make a vector pointing between them
m_origin
=
PositionVector3D
<
Cartesian3D
<
double
>>
(
0.
,
0.
,
0.
);
m_origin
=
m_localToGlobal
*
m_origin
;
PositionVector3D
<
Cartesian3D
<
double
>>
localZ
(
0.
,
0.
,
1.
);
localZ
=
m_localToGlobal
*
localZ
;
m_normal
=
PositionVector3D
<
Cartesian3D
<
double
>>
(
localZ
.
X
()
-
m_origin
.
X
(),
localZ
.
Y
()
-
m_origin
.
Y
(),
localZ
.
Z
()
-
m_origin
.
Z
());
}
// Only if detector is not auxiliary
void
PixelDetector
::
configureDetector
(
Configuration
&
config
)
const
{
// Number of pixels
config
.
set
(
"number_of_pixels"
,
m_nPixels
);
// Size of the pixels
config
.
set
(
"pixel_pitch"
,
m_pitch
,
{
"um"
});
// Intrinsic resolution:
config
.
set
(
"spatial_resolution"
,
m_spatial_resolution
,
{
"um"
});
// Pixel mask file:
if
(
!
m_maskfile_name
.
empty
())
{
config
.
set
(
"mask_file"
,
m_maskfile_name
);
}
// Region-of-interest:
config
.
setMatrix
(
"roi"
,
m_roi
);
}
void
PixelDetector
::
configurePosAndOrientation
(
Configuration
&
config
)
const
{
config
.
set
(
"position"
,
m_displacement
,
{
"um"
,
"mm"
});
config
.
set
(
"orientation_mode"
,
m_orientation_mode
);
config
.
set
(
"orientation"
,
m_orientation
,
{
"deg"
});
}
// Function to get global intercept with a track
PositionVector3D
<
Cartesian3D
<
double
>>
PixelDetector
::
getIntercept
(
const
Track
*
track
)
const
{
// FIXME: this is else statement can only be temporary
if
(
track
->
getType
()
==
"gbl"
)
{
return
track
->
state
(
name
());
}
else
{
// Get the distance from the plane to the track initial state
double
distance
=
(
m_origin
.
X
()
-
track
->
state
(
m_detectorName
).
X
())
*
m_normal
.
X
();
distance
+=
(
m_origin
.
Y
()
-
track
->
state
(
m_detectorName
).
Y
())
*
m_normal
.
Y
();
distance
+=
(
m_origin
.
Z
()
-
track
->
state
(
m_detectorName
).
Z
())
*
m_normal
.
Z
();
distance
/=
(
track
->
direction
(
m_detectorName
).
X
()
*
m_normal
.
X
()
+
track
->
direction
(
m_detectorName
).
Y
()
*
m_normal
.
Y
()
+
track
->
direction
(
m_detectorName
).
Z
()
*
m_normal
.
Z
());
// Propagate the track
PositionVector3D
<
Cartesian3D
<
double
>>
globalIntercept
(
track
->
state
(
m_detectorName
).
X
()
+
distance
*
track
->
direction
(
m_detectorName
).
X
(),
track
->
state
(
m_detectorName
).
Y
()
+
distance
*
track
->
direction
(
m_detectorName
).
Y
(),
track
->
state
(
m_detectorName
).
Z
()
+
distance
*
track
->
direction
(
m_detectorName
).
Z
());
return
globalIntercept
;
}
}
PositionVector3D
<
Cartesian3D
<
double
>>
PixelDetector
::
getLocalIntercept
(
const
Track
*
track
)
const
{
return
globalToLocal
(
getIntercept
(
track
));
}
// Function to check if a track intercepts with a plane
bool
PixelDetector
::
hasIntercept
(
const
Track
*
track
,
double
pixelTolerance
)
const
{
// First, get the track intercept in global co-ordinates with the plane
PositionVector3D
<
Cartesian3D
<
double
>>
globalIntercept
=
this
->
getIntercept
(
track
);
// Convert to local co-ordinates
PositionVector3D
<
Cartesian3D
<
double
>>
localIntercept
=
this
->
m_globalToLocal
*
globalIntercept
;
// Get the row and column numbers
double
row
=
this
->
getRow
(
localIntercept
);
double
column
=
this
->
getColumn
(
localIntercept
);
// Check if the row and column are outside of the chip
// Chip reaches from -0.5 to nPixels-0.5
bool
intercept
=
true
;
if
(
row
<
pixelTolerance
-
0.5
||
row
>
(
this
->
m_nPixels
.
Y
()
-
pixelTolerance
-
0.5
)
||
column
<
pixelTolerance
-
0.5
||
column
>
(
this
->
m_nPixels
.
X
()
-
pixelTolerance
-
0.5
))
intercept
=
false
;
return
intercept
;
}
// Function to check if a track goes through/near a masked pixel
bool
PixelDetector
::
hitMasked
(
Track
*
track
,
int
tolerance
)
const
{
// First, get the track intercept in global co-ordinates with the plane
PositionVector3D
<
Cartesian3D
<
double
>>
globalIntercept
=
this
->
getIntercept
(
track
);
// Convert to local co-ordinates
PositionVector3D
<
Cartesian3D
<
double
>>
localIntercept
=
this
->
m_globalToLocal
*
globalIntercept
;
// Get the row and column numbers
int
row
=
static_cast
<
int
>
(
floor
(
this
->
getRow
(
localIntercept
)
+
0.5
));
int
column
=
static_cast
<
int
>
(
floor
(
this
->
getColumn
(
localIntercept
)
+
0.5
));
// Check if the pixels around this pixel are masked
bool
hitmasked
=
false
;
for
(
int
r
=
(
row
-
tolerance
);
r
<=
(
row
+
tolerance
);
r
++
)
{
for
(
int
c
=
(
column
-
tolerance
);
c
<=
(
column
+
tolerance
);
c
++
)
{
if
(
this
->
masked
(
c
,
r
))
hitmasked
=
true
;
}
}
return
hitmasked
;
}
// Functions to get row and column from local position
double
PixelDetector
::
getRow
(
const
PositionVector3D
<
Cartesian3D
<
double
>>
localPosition
)
const
{
// (1-m_nPixelsX%2)/2. --> add 1/2 pixel pitch if even number of rows
double
row
=
localPosition
.
Y
()
/
m_pitch
.
Y
()
+
static_cast
<
double
>
(
m_nPixels
.
Y
())
/
2.
+
(
1
-
m_nPixels
.
Y
()
%
2
)
/
2.
;
return
row
;
}
double
PixelDetector
::
getColumn
(
const
PositionVector3D
<
Cartesian3D
<
double
>>
localPosition
)
const
{
// (1-m_nPixelsX%2)/2. --> add 1/2 pixel pitch if even number of columns
double
column
=
localPosition
.
X
()
/
m_pitch
.
X
()
+
static_cast
<
double
>
(
m_nPixels
.
X
())
/
2.
+
(
1
-
m_nPixels
.
X
()
%
2
)
/
2.
;
return
column
;
}
// Function to get local position from row and column
PositionVector3D
<
Cartesian3D
<
double
>>
PixelDetector
::
getLocalPosition
(
double
column
,
double
row
)
const
{
return
PositionVector3D
<
Cartesian3D
<
double
>>
(
m_pitch
.
X
()
*
(
column
-
m_nPixels
.
X
()
/
2
),
m_pitch
.
Y
()
*
(
row
-
m_nPixels
.
Y
()
/
2
),
0.
);
}
// Function to get in-pixel position
ROOT
::
Math
::
XYVector
PixelDetector
::
inPixel
(
const
double
column
,
const
double
row
)
const
{
// a pixel ranges from (col-0.5) to (col+0.5)
return
XYVector
(
m_pitch
.
X
()
*
(
column
-
floor
(
column
)
-
0.5
),
m_pitch
.
Y
()
*
(
row
-
floor
(
row
)
-
0.5
));
}
ROOT
::
Math
::
XYVector
PixelDetector
::
inPixel
(
const
PositionVector3D
<
Cartesian3D
<
double
>>
localPosition
)
const
{
double
column
=
getColumn
(
localPosition
);
double
row
=
getRow
(
localPosition
);
return
inPixel
(
column
,
row
);
}
// Check if track position is within ROI:
bool
PixelDetector
::
isWithinROI
(
const
Track
*
track
)
const
{
// Empty region of interest:
if
(
m_roi
.
empty
())
{
return
true
;
}
// Check that track is within region of interest using winding number algorithm
auto
localIntercept
=
this
->
getLocalIntercept
(
track
);
auto
coordinates
=
std
::
make_pair
(
this
->
getColumn
(
localIntercept
),
this
->
getRow
(
localIntercept
));
if
(
winding_number
(
coordinates
,
m_roi
)
!=
0
)
{
return
true
;
}
// Outside ROI:
return
false
;
}
// Check if cluster is within ROI and/or touches ROI border:
bool
PixelDetector
::
isWithinROI
(
Cluster
*
cluster
)
const
{
// Empty region of interest:
if
(
m_roi
.
empty
())
{
return
true
;
}
// Loop over all pixels of the cluster
for
(
auto
&
pixel
:
cluster
->
pixels
())
{
if
(
winding_number
(
pixel
->
coordinates
(),
m_roi
)
==
0
)
{
return
false
;
}
}
return
true
;
}
XYVector
PixelDetector
::
size
()
const
{
return
XYVector
(
m_pitch
.
X
()
*
m_nPixels
.
X
(),
m_pitch
.
Y
()
*
m_nPixels
.
Y
());
}
/* Winding number test for a point in a polygon
* via: http://geomalgorithms.com/a03-_inclusion.html
* Input: x, y = a point,
* polygon = vector of vertex points of a polygon V[n+1] with V[n]=V[0]
* Return: wn = the winding number (=0 only when P is outside)
*/
int
PixelDetector
::
winding_number
(
std
::
pair
<
int
,
int
>
probe
,
std
::
vector
<
std
::
vector
<
int
>>
polygon
)
{
// Two points don't make an area
if
(
polygon
.
size
()
<
3
)
{
LOG
(
DEBUG
)
<<
"No ROI given."
;
return
0
;
}
int
wn
=
0
;
// the winding number counter
// loop through all edges of the polygon
// edge from V[i] to V[i+1]
for
(
size_t
i
=
0
;
i
<
polygon
.
size
();
i
++
)
{
auto
point_this
=
std
::
make_pair
(
polygon
.
at
(
i
).
at
(
0
),
polygon
.
at
(
i
).
at
(
1
));
auto
point_next
=
(
i
+
1
<
polygon
.
size
()
?
std
::
make_pair
(
polygon
.
at
(
i
+
1
).
at
(
0
),
polygon
.
at
(
i
+
1
).
at
(
1
))
:
std
::
make_pair
(
polygon
.
at
(
0
).
at
(
0
),
polygon
.
at
(
0
).
at
(
1
)));
// start y <= P.y
if
(
point_this
.
second
<=
probe
.
second
)
{
// an upward crossing
if
(
point_next
.
second
>
probe
.
second
)
{
// P left of edge
if
(
isLeft
(
point_this
,
point_next
,
probe
)
>
0
)
{
// have a valid up intersect
++
wn
;
}
}
}
else
{
// start y > P.y (no test needed)
// a downward crossing
if
(
point_next
.
second
<=
probe
.
second
)
{
// P right of edge
if
(
isLeft
(
point_this
,
point_next
,
probe
)
<
0
)
{
// have a valid down intersect
--
wn
;
}
}
}
}
return
wn
;
}
/* isLeft(): tests if a point is Left|On|Right of an infinite line.
* via: http://geomalgorithms.com/a03-_inclusion.html
* Input: three points P0, P1, and P2
* Return: >0 for P2 left of the line through P0 and P1
* =0 for P2 on the line
* <0 for P2 right of the line
* See: Algorithm 1 "Area of Triangles and Polygons"
*/
int
PixelDetector
::
isLeft
(
std
::
pair
<
int
,
int
>
pt0
,
std
::
pair
<
int
,
int
>
pt1
,
std
::
pair
<
int
,
int
>
pt2
)
{
return
((
pt1
.
first
-
pt0
.
first
)
*
(
pt2
.
second
-
pt0
.
second
)
-
(
pt2
.
first
-
pt0
.
first
)
*
(
pt1
.
second
-
pt0
.
second
));
}
src/core/detector/PixelDetector.hpp
0 → 100644
View file @
374016b3
/** @file
* @brief Detector model class
* @copyright Copyright (c) 2017-2020 CERN and the Corryvreckan authors.
* This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
* In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
* Intergovernmental Organization or submit itself to any jurisdiction.
*/
#ifndef CORRYVRECKAN_PLANARDETECTOR_H
#define CORRYVRECKAN_PLANARDETECTOR_H
#include
<fstream>
#include
<map>
#include
<string>
#include
<Math/DisplacementVector2D.h>
#include
<Math/Vector2D.h>
#include
<Math/Vector3D.h>
#include
"Math/Transform3D.h"
#include
"Math/Vector3D.h"
#include
"Detector.hpp"
#include
"core/config/Configuration.hpp"
#include
"core/utils/ROOT.h"
#include
"core/utils/log.h"
#include
"objects/Track.hpp"
namespace
corryvreckan
{
/**
* @brief PixelDetector representation derived from Detector interface in the reconstruction chain
*
* Contains the PixelDetector with all its properties such as position and orientation, pitch, spatial resolution
* etc.
*/
class
PixelDetector
:
public
Detector
{
public:
/**
* Delete default constructor
*/
PixelDetector
()
=
delete
;
/**
* Default destructor
*/
~
PixelDetector
()
=
default
;
/**
* @brief Constructs a detector in the geometry
* @param config Configuration object describing the detector
*/
PixelDetector
(
const
Configuration
&
config
);
/**
* @brief Set position and orientation from configuration file
*/
void
SetPostionAndOrientation
(
const
Configuration
&
config
);
/**
* @brief Update detector position in the world
* @param displacement Vector with three position coordinates
*/
void
displacement
(
XYZPoint
displacement
)
override
{
m_displacement
=
displacement
;
}
/**
* @brief Get position in the world
* @return Global position in Cartesian coordinates
*/
XYZPoint
displacement
()
const
override
{
return
m_displacement
;
}
/**
* @brief Get orientation in the world
* @return Vector with three rotation angles
*/
XYZVector
rotation
()
const
override
{
return
m_orientation
;
}
/**
* @brief Update detector orientation in the world
* @param rotation Vector with three rotation angles
*/
void
rotation
(
XYZVector
rotation
)
override
{
m_orientation
=
rotation
;
}
/**
* @brief Mark a detector channel as masked
* @param chX X coordinate of the pixel to be masked
* @param chY Y coordinate of the pixel to be masked
*/
void
maskChannel
(
int
chX
,
int
chY
)
override
;
/**
* @brief Check if a detector channel is masked
* @param chX X coordinate of the pixel to check
* @param chY Y coordinate of the pixel to check
* @return Mask status of the pixel in question
*/
bool
masked
(
int
chX
,
int
chY
)
const
override
;
// Function to get global intercept with a track
PositionVector3D
<
Cartesian3D
<
double
>>
getIntercept
(
const
Track
*
track
)
const
override
;
// Function to get local intercept with a track
PositionVector3D
<
Cartesian3D
<
double
>>
getLocalIntercept
(
const
Track
*
track
)
const
override
;
// Function to check if a track intercepts with a plane
bool
hasIntercept
(
const
Track
*
track
,
double
pixelTolerance
=
0.
)
const
override
;
// Function to check if a track goes through/near a masked pixel
bool
hitMasked
(
Track
*
track
,
int
tolerance
=
0.
)
const
override
;
// Functions to get row and column from local position
double
getRow
(
PositionVector3D
<
Cartesian3D
<
double
>>
localPosition
)
const
override
;
double
getColumn
(
PositionVector3D
<
Cartesian3D
<
double
>>
localPosition
)
const
override
;
// Function to get local position from column (x) and row (y) coordinates
PositionVector3D
<
Cartesian3D
<
double
>>
getLocalPosition
(
double
column
,
double
row
)
const
override
;
/**
* Transformation from local (sensor) coordinates to in-pixel coordinates
* @param column Column address ranging from int_column-0.5*pitch to int_column+0.5*pitch
* @param row Row address ranging from int_column-0.5*pitch to int_column+0.5*pitch
* @return Position within a single pixel cell, given in units of length
*/
XYVector
inPixel
(
const
double
column
,
const
double
row
)
const
override
;
/**
* Transformation from local (sensor) coordinates to in-pixel coordinates
* @param localPosition Local position on the sensor
* @return Position within a single pixel cell, given in units of length
*/
XYVector
inPixel
(
PositionVector3D
<
Cartesian3D
<
double
>>
localPosition
)
const
override
;
/**
* @brief Check whether given track is within the detector's region-of-interest
* @param track The track to be checked
* @return Boolean indicating cluster affiliation with region-of-interest
*/
bool
isWithinROI
(
const
Track
*
track
)
const
override
;
/**
* @brief Check whether given cluster is within the detector's region-of-interest
* @param cluster The cluster to be checked
* @return Boolean indicating cluster affiliation with region-of-interest
*/
bool
isWithinROI
(
Cluster
*
cluster
)
const
override
;
/**
* @brief Get the total size of the active matrix, i.e. pitch * number of pixels in both dimensions
* @return 2D vector with the dimensions of the pixle matrix in X and Y
*/
XYVector
size
()
const
override
;
/**
* @brief Get pitch of a single pixel
* @return Pitch of a pixel
*/
XYVector
pitch
()
const
override
{
return
m_pitch
;
}
/**
* @brief Get intrinsic spatial resolution of the detector
* @return Intrinsic spatial resolution in X and Y
*/
XYVector
getSpatialResolution
()
const
override
{
return
m_spatial_resolution
;
}
/*
* @brief Get number of pixels in x and y
* @return Number of two dimensional pixels
*/
ROOT
::
Math
::
DisplacementVector2D
<
ROOT
::
Math
::
Cartesian2D
<
int
>>
nPixels
()
const
override
{
return
m_nPixels
;
}
private:
// Initialize coordinate transformations
void
initialise
()
override
;
// Build axis, for devices which are not auxiliary
// Different in Pixel/Strip Detector
void
buildAxes
(
const
Configuration
&
config
)
override
;
// Config detector, for devices which are not auxiliary
// Different in Pixel/Strip Detector
void
configureDetector
(
Configuration
&
config
)
const
override
;
// Config position, orientation, mode of detector
// Different in Pixel/Strip Detector
void
configurePosAndOrientation
(
Configuration
&
config
)
const
override
;
// Functions to set and check channel masking
void
processMaskFile
()
override
;
// Seems to be used in other coordinate
inline
static
int
isLeft
(
std
::
pair
<
int
,
int
>
pt0
,
std
::
pair
<
int
,
int
>
pt1
,
std
::
pair
<
int
,
int
>
pt2
);
static
int
winding_number
(
std
::
pair
<
int
,
int
>
probe
,
std
::
vector
<
std
::
vector
<
int
>>
polygon
);
// For planar detector
XYVector
m_pitch
{};