11.08., 9:00 - 11:00: Due to updates GitLab will be unavailable for some minutes between 09:00 and 11:00.

Commit 7397e31a authored by David Frank's avatar David Frank Committed by Tobias Lasser

#63 Add DetectorDescriptor and PlanarDetectorDescriptor

- Add Abstract class DetectorDescriptor, which is derived from DataDescriptor (Support ray generation from a given pose and detector pixel and given pose and voxel)
- Add first derived class of DetectorDescriptor: PlanarDetectorDescriptor
- Add usage of DetectorDescriptor in Projectors (remove dependency to geometry, ray generation is only handled by DetectorDescriptor, adapt tests)
- Restructure tests of CUDA projectors to make failing tests more readable
parent f6e6f3d7
Pipeline #287374 failed with stages
in 3 minutes and 46 seconds
......@@ -13,6 +13,8 @@ set(MODULE_HEADERS
Descriptors/DataDescriptor.h
Descriptors/DescriptorUtils.h
Descriptors/VolumeDescriptor.h
Descriptors/DetectorDescriptor.h
Descriptors/PlanarDetectorDescriptor.h
Descriptors/BlockDescriptor.h
Descriptors/IdenticalBlocksDescriptor.h
Descriptors/PartitionDescriptor.h
......@@ -32,9 +34,11 @@ set(MODULE_HEADERS
set(MODULE_SOURCES
Descriptors/DataDescriptor.cpp
Descriptors/VolumeDescriptor.cpp
Descriptors/PlanarDetectorDescriptor.cpp
Descriptors/RandomBlocksDescriptor.cpp
Descriptors/DescriptorUtils.cpp
Descriptors/IdenticalBlocksDescriptor.cpp
Descriptors/DetectorDescriptor.cpp
Descriptors/PartitionDescriptor.cpp
DataContainer.cpp
Handlers/DataHandlerCPU.cpp
......
#include "DetectorDescriptor.h"
#include <iostream>
namespace elsa
{
DetectorDescriptor::DetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
const std::vector<Geometry>& geometryList)
: DataDescriptor(numOfCoeffsPerDim), _geometry(geometryList)
{
// TODO Clarify: What about empty geometryList? Do we want to support it, or throw an
// execption?
}
DetectorDescriptor::DetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
const RealVector_t& spacingPerDim,
const std::vector<Geometry>& geometryList)
: DataDescriptor(numOfCoeffsPerDim, spacingPerDim), _geometry(geometryList)
{
}
DetectorDescriptor::Ray
DetectorDescriptor::computeRayFromDetectorCoord(const index_t detectorIndex) const
{
// Return empty, if access out of bounds
assert(detectorIndex < getNumberOfCoefficients()
&& "PlanarDetectorDescriptor::computeRayToDetector(index_t): Assumption "
"detectorIndex smaller than number of coeffs, broken");
auto coord = getCoordinateFromIndex(detectorIndex);
return computeRayFromDetectorCoord(coord);
}
DetectorDescriptor::Ray
DetectorDescriptor::computeRayFromDetectorCoord(const IndexVector_t coord) const
{
// Assume all of the coordinates are inside of the volume
// auto tmp = (coord.array() < getNumberOfCoefficientsPerDimension().array());
// assert(tmp.all()
// && "DetectorDescriptor::computeRayToDetector(IndexVector_t): Assumption coord "
// "in bound wrong");
auto dim = getNumberOfDimensions();
// Cast to real_t and shift to center of pixel
auto detectorCoord = coord.head(dim - 1).template cast<real_t>().array() + 0.5;
// Last dimension is always the pose index
auto poseIndex = coord[dim - 1];
return computeRayFromDetectorCoord(detectorCoord, poseIndex);
}
index_t DetectorDescriptor::getNumberOfGeometryPoses() const { return _geometry.size(); }
std::optional<Geometry> DetectorDescriptor::getGeometryAt(const index_t index) const
{
if (_geometry.size() <= std::make_unsigned_t<std::size_t>(index))
return {};
return _geometry[index];
}
bool DetectorDescriptor::isEqual(const DataDescriptor& other) const
{
if (!DataDescriptor::isEqual(other))
return false;
// static cast as type checked in base comparison
auto otherBlock = static_cast<const DetectorDescriptor*>(&other);
if (getNumberOfGeometryPoses() != otherBlock->getNumberOfGeometryPoses())
return false;
return std::equal(std::cbegin(_geometry), std::cend(_geometry),
std::cbegin(otherBlock->_geometry));
}
} // namespace elsa
#pragma once
#include "elsaDefines.h"
#include "DataDescriptor.h"
#include "Geometry.h"
#include <optional>
#include "Eigen/Geometry"
namespace elsa
{
/**
* @brief Class representing metadata for lineraized n-dimensional signal stored in memory. It
* is a base class for different type signals caputred by some kind of detectors (i.e. a planar
* detector, curved or some other shaped detector). Is additionally stored information about the
* different poses of a trajectory.
*/
class DetectorDescriptor : public DataDescriptor
{
public:
using Ray = Eigen::ParametrizedLine<real_t, Eigen::Dynamic>;
public:
/// There is not default signal
DetectorDescriptor() = delete;
/// Default destructor
~DetectorDescriptor() override = default;
/**
* @brief Construct a DetectorDescriptor with a number of coefficients for each dimension
* and a list of geometry poses
*/
DetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
const std::vector<Geometry>& geometryList);
/**
* @brief Construct a DetectorDescriptor with a number of coefficients and spacing for each
* dimension and a list of geometry poses
*/
DetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
const RealVector_t& spacingPerDim,
const std::vector<Geometry>& geometryList);
/**
* @brief Overload of computeRayToDetector with a single detectorIndex. Compute the pose and
* coord index using getCoordinateFromIndex and call overload
*/
Ray computeRayFromDetectorCoord(const index_t detectorIndex) const;
/**
* @brief Overload of computeRayToDetector with a single coord vector. This vector encodes
* the pose index and the detector coordinate. So for a 1D detector, this will be 2D and the
* second dimension, will reference the pose index
*/
Ray computeRayFromDetectorCoord(const IndexVector_t coord) const;
/**
* @brief Compute a ray from the source from a pose to the given detector coordinate
*
* @param[in] detectorCoord Vector of size dim - 1, specifying the coordinate the ray should
* hit
* @param[in] poseIndex index into geometryList array, which pose to use for ray computation
*
*/
virtual Ray computeRayFromDetectorCoord(const RealVector_t& detectorCoord,
const index_t poseIndex) const = 0;
/**
* @brief Compute a ray from the source to trougth a pixel/voxel
*/
virtual RealVector_t computeDetectorCoordFromRay(const Ray& ray,
const index_t poseIndex) const = 0;
/// Get the number of poses used in the geometry
index_t getNumberOfGeometryPoses() const;
/// Get the i-th geometry in the trajectory.
std::optional<Geometry> getGeometryAt(const index_t index) const;
protected:
/// implement the polymorphic comparison operation
bool isEqual(const DataDescriptor& other) const override;
/// List of geometry poses
std::vector<Geometry> _geometry;
};
} // namespace elsa
#include "PlanarDetectorDescriptor.h"
#include <iostream>
namespace elsa
{
PlanarDetectorDescriptor::PlanarDetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
const std::vector<Geometry>& geometryList)
: DetectorDescriptor(numOfCoeffsPerDim, geometryList)
{
}
PlanarDetectorDescriptor::PlanarDetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
const RealVector_t& spacingPerDim,
const std::vector<Geometry>& geometryList)
: DetectorDescriptor(numOfCoeffsPerDim, spacingPerDim, geometryList)
{
}
DetectorDescriptor::Ray
PlanarDetectorDescriptor::computeRayFromDetectorCoord(const RealVector_t& detectorCoord,
const index_t poseIndex) const
{
// Assert that for all dimension of detectorCoord is in bounds and poseIndex can
// be index in the _geometry. If not the calculation will not be correct, but
// as this is the hot path, I don't want execptions and unpacking everything
// We'll just have to ensure, that we don't mess up in our hot path! :-)
assert((detectorCoord.block(0, 0, getNumberOfDimensions() - 1, 0).array()
< getNumberOfCoefficientsPerDimension()
.block(0, 0, getNumberOfDimensions() - 1, 0)
.template cast<real_t>()
.array())
.all()
&& "PlanarDetectorDescriptor::computeRayToDetector: Assumption detectorCoord in "
"bounds, wrong");
assert(std::make_unsigned_t<std::size_t>(poseIndex) < _geometry.size()
&& "PlanarDetectorDescriptor::computeRayToDetector: Assumption poseIndex smaller "
"than number of poses, wrong");
auto dim = getNumberOfDimensions();
// get the pose of trajectory
auto geometry = _geometry[std::make_unsigned_t<index_t>(poseIndex)];
auto projInvMatrix = geometry.getInverseProjectionMatrix();
// homogeneous coordinates [p;1], with p in detector space
RealVector_t homogeneousPixelCoord(dim);
homogeneousPixelCoord << detectorCoord, 1;
// Camera center is always the ray origin
auto ro = geometry.getCameraCenter();
auto rd = (projInvMatrix * homogeneousPixelCoord) // Matrix-Vector multiplication
.head(dim) // Transform to non-homogeneous
.normalized(); // normalize vector
return Ray(ro, rd);
}
RealVector_t
PlanarDetectorDescriptor::computeDetectorCoordFromRay(const Ray& ray,
const index_t poseIndex) const
{
auto dim = getNumberOfDimensions();
auto geometry = _geometry[(poseIndex)];
auto projMatrix = geometry.getProjectionMatrix();
// Only take the square matrix part
auto pixel = (projMatrix.block(0, 0, dim, dim) * ray.direction()).head(dim - 1);
return pixel;
}
bool PlanarDetectorDescriptor::isEqual(const DataDescriptor& other) const
{
// PlanarDetectorDescriptor has no data, so just deligate it to base class
return DetectorDescriptor::isEqual(other);
}
PlanarDetectorDescriptor* PlanarDetectorDescriptor::cloneImpl() const
{
return new PlanarDetectorDescriptor(getNumberOfCoefficientsPerDimension(),
getSpacingPerDimension(), _geometry);
}
} // namespace elsa
#pragma once
#include "DetectorDescriptor.h"
namespace elsa
{
/**
* @brief Class representing metadata for lineraized n-dimensional signal stored in memory. It
* specifically describes signals, which were captured by a planar detector and stores
* additional information such as different poses
*
* @author David Frank - initial code
*/
class PlanarDetectorDescriptor : public DetectorDescriptor
{
using DetectorDescriptor::Ray;
public:
PlanarDetectorDescriptor() = delete;
~PlanarDetectorDescriptor() = default;
/**
* @brief Construct a PlanatDetectorDescriptor with given number of coefficients and spacing
* per dimension and a list of geometry poses in the trajectory
*/
PlanarDetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
const RealVector_t& spacingPerDim,
const std::vector<Geometry>& geometryList);
/**
* @brief Construct a PlanatDetectorDescriptor with given number of coefficients
* per dimension and a list of geometry poses in the trajectory
*/
PlanarDetectorDescriptor(const IndexVector_t& numOfCoeffsPerDim,
const std::vector<Geometry>& geometryList);
using DetectorDescriptor::computeRayFromDetectorCoord;
/// Override function to compute rays for a planar detector
Ray computeRayFromDetectorCoord(const RealVector_t& detectorCoord,
const index_t poseIndex) const override;
RealVector_t computeDetectorCoordFromRay(const Ray& ray,
const index_t poseIndex) const override;
private:
PlanarDetectorDescriptor* cloneImpl() const override;
bool isEqual(const DataDescriptor& other) const override;
};
} // namespace elsa
......@@ -147,20 +147,6 @@ namespace elsa
buildMatrices();
}
std::pair<RealVector_t, RealVector_t> Geometry::computeRayTo(const RealVector_t& p) const
{
// the ray origin is always the camera center
RealVector_t ro = _C;
// homogeneous coordinates [p;1] - p is in detector space
RealVector_t homP(_objectDimension);
homP << p, 1;
// multiplication of inverse projection matrix and homogeneous detector coordinate
auto rd = (_Pinv * homP).normalized();
return std::make_pair(ro, rd.head(_objectDimension));
}
const RealMatrix_t& Geometry::getProjectionMatrix() const { return _P; }
const RealMatrix_t& Geometry::getInverseProjectionMatrix() const { return _Pinv; }
......
......@@ -109,18 +109,6 @@ namespace elsa
real_t centerOfRotationOffsetY = static_cast<real_t>(0.0),
real_t centerOfRotationOffsetZ = static_cast<real_t>(0.0));
/**
* @brief Compute a ray (ray origin and ray direction) that hits the specified point p on
* the detector
*
* @param[in] p point p on detector
*
* @returns pair of <ro, rd>, where ro = ray origin and rd = ray direction
*
* Computation are done using the projection matrix.
*/
std::pair<RealVector_t, RealVector_t> computeRayTo(const RealVector_t& p) const;
/**
* @brief Return the projection matrix
*
......
......@@ -248,9 +248,9 @@ namespace elsa
}
/// Access to gamma
constexpr Radian gamma() const { return operator[](0); }
constexpr Radian gamma() const { return operator[](0u); }
/// Access to beta
constexpr Radian beta() const { return operator[](1); }
constexpr Radian beta() const { return operator[](1u); }
/// Access to alpha
constexpr Radian alpha() const { return operator[](2); }
};
......@@ -689,4 +689,4 @@ namespace std
struct tuple_element<N, elsa::geometry::RotationAngles3D> {
using type = decltype(std::declval<elsa::geometry::RotationAngles3D>().get<N>());
};
} // namespace std
\ No newline at end of file
} // namespace std
......@@ -17,6 +17,7 @@ ELSA_TEST(LinearOperator)
ELSA_TEST(ExpressionTemplates)
ELSA_TEST(Geometry)
ELSA_TEST(StrongTypes)
ELSA_TEST(PlanarDetectorDescriptor)
if(ELSA_BENCHMARKS)
ELSA_TEST(BenchmarkExpressionTemplates)
......
......@@ -64,24 +64,6 @@ SCENARIO("Testing 2D geometries")
REQUIRE((c[0] - o[0]) == Approx(0));
REQUIRE((c[1] - o[1] + s2c) == Approx(0));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(1);
pixel << detPixel;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0));
real_t factor =
(std::abs(rd[0]) > 0) ? ((pixel[0] - ro[0]) / rd[0]) : (s2c + c2d);
real_t detCoordY = ro[1] + factor * rd[1];
REQUIRE(detCoordY == Approx(ddVol.getLocationOfOrigin()[1] + c2d));
}
}
}
WHEN("testing geometry without rotation but with principal point offset")
......@@ -123,25 +105,6 @@ SCENARIO("Testing 2D geometries")
REQUIRE((c[0] - o[0]) == Approx(0));
REQUIRE((c[1] - o[1] + s2c) == Approx(0));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(1);
pixel << detPixel;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0));
real_t factor = (std::abs(rd[0]) >= Approx(0.001))
? ((pixel[0] - ro[0] - px) / rd[0])
: (s2c + c2d);
real_t detCoordY = ro[1] + factor * rd[1];
REQUIRE(detCoordY == Approx(ddVol.getLocationOfOrigin()[1] + c2d));
}
}
}
WHEN("testing geometry with 90 degree rotation and no offsets")
......@@ -181,24 +144,6 @@ SCENARIO("Testing 2D geometries")
REQUIRE((c[0] - o[0] + s2c) == Approx(0));
REQUIRE((c[1] - o[1]) == Approx(0).margin(0.000001));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(1);
pixel << detPixel;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0));
real_t factor =
(std::abs(rd[1]) > 0.0000001) ? ((ro[1] - pixel[0]) / rd[1]) : (s2c + c2d);
real_t detCoordX = ro[0] + factor * rd[0];
REQUIRE(detCoordX == Approx(ddVol.getLocationOfOrigin()[0] + c2d));
}
}
}
WHEN("testing geometry with 45 degree rotation and offset center of rotation")
......@@ -249,30 +194,6 @@ SCENARIO("Testing 2D geometries")
REQUIRE((c[0] - newX) == Approx(0).margin(0.000001));
REQUIRE((c[1] - newY) == Approx(0).margin(0.000001));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(1);
pixel << detPixel;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0.0));
auto o = ddVol.getLocationOfOrigin();
RealVector_t detCoordWorld(2);
detCoordWorld << detPixel - o[0], c2d;
RealVector_t rotD = g.getRotationMatrix().transpose() * detCoordWorld;
rotD[0] += o[0] + cx;
rotD[1] += o[1] + cy;
real_t factor = (rotD[0] - ro[0]) / rd[0]; // rd[0] won't be 0 here!
real_t detCoord = ro[1] + factor * rd[1];
REQUIRE(detCoord == Approx(rotD[1]));
}
}
}
}
}
......@@ -331,37 +252,6 @@ SCENARIO("Testing 3D geometries")
REQUIRE((c[1] - o[1]) == Approx(0));
REQUIRE((c[2] - o[2] + s2c) == Approx(0));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel1 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
for (real_t detPixel2 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(2);
pixel << detPixel1, detPixel2;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0));
auto o = ddVol.getLocationOfOrigin();
RealVector_t detCoordWorld(3);
detCoordWorld << detPixel1 - o[0], detPixel2 - o[1], c2d;
RealVector_t rotD = g.getRotationMatrix().transpose() * detCoordWorld + o;
real_t factor = 0;
if (std::abs(rd[0]) > 0)
factor = (rotD[0] - ro[0]) / rd[0];
else if (std::abs(rd[1]) > 0)
factor = (rotD[1] - ro[1]) / rd[1];
else if (std::abs(rd[2]) > 0)
factor = (rotD[2] - ro[2] / rd[2]);
REQUIRE((ro[0] + factor * rd[0]) == Approx(rotD[0]));
REQUIRE((ro[1] + factor * rd[1]) == Approx(rotD[1]));
REQUIRE((ro[2] + factor * rd[2]) == Approx(rotD[2]));
}
}
}
}
WHEN("testing geometry without rotation but with principal point offsets")
......@@ -406,37 +296,6 @@ SCENARIO("Testing 3D geometries")
REQUIRE((c[1] - o[1]) == Approx(0));
REQUIRE((c[2] - o[2] + s2c) == Approx(0));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel1 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
for (real_t detPixel2 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(2);
pixel << detPixel1, detPixel2;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0));
auto o = ddVol.getLocationOfOrigin();
RealVector_t detCoordWorld(3);
detCoordWorld << detPixel1 - o[0] - px, detPixel2 - o[1] - py, c2d;
RealVector_t rotD = g.getRotationMatrix().transpose() * detCoordWorld + o;
real_t factor = 0;
if (std::abs(rd[0]) > 0)
factor = (rotD[0] - ro[0]) / rd[0];
else if (std::abs(rd[1]) > 0)
factor = (rotD[1] - ro[1]) / rd[1];
else if (std::abs(rd[2]) > 0)
factor = (rotD[2] - ro[2] / rd[2]);
REQUIRE((ro[0] + factor * rd[0]) == Approx(rotD[0]));
REQUIRE((ro[1] + factor * rd[1]) == Approx(rotD[1]));
REQUIRE((ro[2] + factor * rd[2]) == Approx(rotD[2]));
}
}
}
}
WHEN("testing geometry with 90 degree rotation and no offsets")
......@@ -481,37 +340,6 @@ SCENARIO("Testing 3D geometries")
REQUIRE((c[1] - o[1]) == Approx(0).margin(0.000001));
REQUIRE((c[2] - o[2]) == Approx(0).margin(0.000001));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel1 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
for (real_t detPixel2 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(2);
pixel << detPixel1, detPixel2;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0));
auto o = ddVol.getLocationOfOrigin();
RealVector_t detCoordWorld(3);
detCoordWorld << detPixel1 - o[0], detPixel2 - o[1], c2d;
RealVector_t rotD = g.getRotationMatrix().transpose() * detCoordWorld + o;
real_t factor = 0;
if (std::abs(rd[0]) > 0)
factor = (rotD[0] - ro[0]) / rd[0];
else if (std::abs(rd[1]) > 0)
factor = (rotD[1] - ro[1]) / rd[1];
else if (std::abs(rd[2]) > 0)
factor = (rotD[2] - ro[2] / rd[2]);
REQUIRE((ro[0] + factor * rd[0]) == Approx(rotD[0]));
REQUIRE((ro[1] + factor * rd[1]) == Approx(rotD[1]));
REQUIRE((ro[2] + factor * rd[2]) == Approx(rotD[2]));
}
}
}
}
WHEN("testing geometry with 45/22.5 degree rotation and offset center of rotation")
......@@ -567,38 +395,6 @@ SCENARIO("Testing 3D geometries")
REQUIRE((rotSrc - c).sum() == Approx(0).margin(0.000001));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel1 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
for (real_t detPixel2 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(2);
pixel << detPixel1, detPixel2;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0));
auto o = ddVol.getLocationOfOrigin();
RealVector_t detCoordWorld(3);
detCoordWorld << detPixel1 - o[0], detPixel2 - o[1], c2d;
RealVector_t rotD =
g.getRotationMatrix().transpose() * detCoordWorld + o + offset;
real_t factor = 0;
if (std::abs(rd[0]) > 0.000001)
factor = (rotD[0] - ro[0]) / rd[0];
else if (std::abs(rd[1]) > 0.000001)
factor = (rotD[1] - ro[1]) / rd[1];
else if (std::abs(rd[2]) > 0.000001)
factor = (rotD[2] - ro[2] / rd[2]);
REQUIRE((ro[0] + factor * rd[0]) == Approx(rotD[0]));
REQUIRE((ro[1] + factor * rd[1]) == Approx(rotD[1]));
REQUIRE((ro[2] + factor * rd[2]) == Approx(rotD[2]));
}
}
}
}
WHEN("testing geometry with 45/22.5/12.25 degree rotation as a rotation matrix")
......@@ -654,37 +450,6 @@ SCENARIO("Testing 3D geometries")
REQUIRE((rotSrc - c).sum() == Approx(0).margin(0.00001));
}
THEN("rays make sense")
{
// test outer + central pixels
for (real_t detPixel1 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
for (real_t detPixel2 : std::initializer_list<real_t>{0.5, 2.5, 4.5}) {
RealVector_t pixel(2);
pixel << detPixel1, detPixel2;
auto [ro, rd] = g.computeRayTo(pixel);
auto c = g.getCameraCenter();
REQUIRE((ro - c).sum() == Approx(0));
auto o = ddVol.getLocationOfOrigin();
RealVector_t detCoordWorld(3);
detCoordWorld << detPixel1 - o[0], detPixel2 - o[1], c2d;
RealVector_t rotD = g.getRotationMatrix().transpose() * detCoordWorld + o;
real_t factor = 0;