** Purpose: Classes for CT scanner
** Programmer: Kevin Rosenberg
** Date Started: 1984
**
** This is part of the CTSim program
** Purpose: Classes for CT scanner
** Programmer: Kevin Rosenberg
** Date Started: 1984
**
** This is part of the CTSim program
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License (version 2) as
const int Scanner::GEOMETRY_PARALLEL = 0;
const int Scanner::GEOMETRY_EQUIANGULAR = 1;
const int Scanner::GEOMETRY_EQUILINEAR = 2;
const int Scanner::GEOMETRY_PARALLEL = 0;
const int Scanner::GEOMETRY_EQUIANGULAR = 1;
const int Scanner::GEOMETRY_EQUILINEAR = 2;
*
* SYNOPSIS
* Scanner (phm, nDet, nView, nSample)
*
* SYNOPSIS
* Scanner (phm, nDet, nView, nSample)
-* int nDet Number of detector along detector array
-* int nView Number of rotated views
-* int nSample Number of rays per detector
+* int nDet Number of detector along detector array
+* int nView Number of rotated views
+* int nSample Number of rays per detector
-Scanner::Scanner (const Phantom& phm, const char* const geometryName,
- int nDet, int nView, int offsetView,
- int nSample, const double rot_anglen,
- const double dFocalLengthRatio,
- const double dCenterDetectorRatio,
+Scanner::Scanner (const Phantom& phm, const char* const geometryName,
+ int nDet, int nView, int offsetView,
+ int nSample, const double rot_anglen,
+ const double dFocalLengthRatio,
+ const double dCenterDetectorRatio,
m_dCenterDetectorLength = (m_dViewDiameter / 2) * m_dCenterDetectorRatio;
m_dSourceDetectorLength = m_dFocalLength + m_dCenterDetectorLength;
m_dScanDiameter = m_dViewDiameter * m_dScanRatio;
m_dCenterDetectorLength = (m_dViewDiameter / 2) * m_dCenterDetectorRatio;
m_dSourceDetectorLength = m_dFocalLength + m_dCenterDetectorLength;
m_dScanDiameter = m_dViewDiameter * m_dScanRatio;
m_dXCenter = phm.xmin() + (phm.xmax() - phm.xmin()) / 2;
m_dYCenter = phm.ymin() + (phm.ymax() - phm.ymin()) / 2;
m_rotLen = rot_anglen;
m_dXCenter = phm.xmin() + (phm.xmax() - phm.xmin()) / 2;
m_dYCenter = phm.ymin() + (phm.ymax() - phm.ymin()) / 2;
m_rotLen = rot_anglen;
const double dAngle = asin ((m_dScanDiameter / 2) / m_dFocalLength);
const double dHalfDetLen = m_dSourceDetectorLength * tan (dAngle);
const double dAngle = asin ((m_dScanDiameter / 2) / m_dFocalLength);
const double dHalfDetLen = m_dSourceDetectorLength * tan (dAngle);
m_detLen = dHalfDetLen * 2;
m_detStart = -dHalfDetLen;
m_detInc = m_detLen / m_nDet;
m_detLen = dHalfDetLen * 2;
m_detStart = -dHalfDetLen;
m_detInc = m_detLen / m_nDet;
m_dFanBeamAngle = dAngle * 2;
m_initPos.xs1 = m_dXCenter;
m_initPos.ys1 = m_dYCenter + m_dFocalLength;
m_dFanBeamAngle = dAngle * 2;
m_initPos.xs1 = m_dXCenter;
m_initPos.ys1 = m_dYCenter + m_dFocalLength;
m_dAngularDetLen = dAngularScale * (m_detLen + dDetectorArrayEndOffset);
m_dAngularDetIncrement = dAngularScale * m_detInc;
m_initPos.dAngularDet = -m_dAngularDetLen / 2;
m_dAngularDetLen = dAngularScale * (m_detLen + dDetectorArrayEndOffset);
m_dAngularDetIncrement = dAngularScale * m_detInc;
m_initPos.dAngularDet = -m_dAngularDetLen / 2;
m_dFanBeamAngle = dAngle * 2;
m_initPos.angle = m_iOffsetView * m_rotInc;
m_initPos.xs1 = m_dXCenter;
m_dFanBeamAngle = dAngle * 2;
m_initPos.angle = m_iOffsetView * m_rotInc;
m_initPos.xs1 = m_dXCenter;
GRFMTX_2D temp;
xlat_mtx2 (m_rotmtxIncrement, -m_dXCenter, -m_dYCenter);
rot_mtx2 (temp, m_rotInc);
mult_mtx2 (m_rotmtxIncrement, temp, m_rotmtxIncrement);
xlat_mtx2 (temp, m_dXCenter, m_dYCenter);
mult_mtx2 (m_rotmtxIncrement, temp, m_rotmtxIncrement);
GRFMTX_2D temp;
xlat_mtx2 (m_rotmtxIncrement, -m_dXCenter, -m_dYCenter);
rot_mtx2 (temp, m_rotInc);
mult_mtx2 (m_rotmtxIncrement, temp, m_rotmtxIncrement);
xlat_mtx2 (temp, m_dXCenter, m_dYCenter);
mult_mtx2 (m_rotmtxIncrement, temp, m_rotmtxIncrement);
for (int i = 0; i < s_iGeometryCount; i++)
if (strcasecmp (geomName, s_aszGeometryName[i]) == 0) {
id = i;
break;
}
for (int i = 0; i < s_iGeometryCount; i++)
if (strcasecmp (geomName, s_aszGeometryName[i]) == 0) {
id = i;
break;
}
*
* SYNOPSIS
* collectProjections (proj, phm, start_view, nView, bStoreViewPos, trace)
* Projectrions& proj Projection storage
*
* SYNOPSIS
* collectProjections (proj, phm, start_view, nView, bStoreViewPos, trace)
* Projectrions& proj Projection storage
-Scanner::collectProjections (Projections& proj, const Phantom& phm, const int iStartView,
- const int iNumViews, const int iOffsetView, bool bStoreAtViewPosition,
+Scanner::collectProjections (Projections& proj, const Phantom& phm, const int iStartView,
+ const int iNumViews, const int iOffsetView, bool bStoreAtViewPosition,
const int trace, SGP* pSGP)
{
int iStorageOffset = (bStoreAtViewPosition ? iStartView : 0);
const int trace, SGP* pSGP)
{
int iStorageOffset = (bStoreAtViewPosition ? iStartView : 0);
-Scanner::collectProjections (Projections& proj, const Phantom& phm, const int iStartView,
- const int iNumViews, const int iOffsetView, int iStorageOffset,
+Scanner::collectProjections (Projections& proj, const Phantom& phm, const int iStartView,
+ const int iNumViews, const int iOffsetView, int iStorageOffset,
const int trace, SGP* pSGP)
{
m_trace = trace;
double start_angle = (iStartView + iOffsetView) * proj.rotInc();
const int trace, SGP* pSGP)
{
m_trace = trace;
double start_angle = (iStartView + iOffsetView) * proj.rotInc();
GRFMTX_2D rotmtx_initial, temp;
xlat_mtx2 (rotmtx_initial, -m_dXCenter, -m_dYCenter);
rot_mtx2 (temp, start_angle);
mult_mtx2 (rotmtx_initial, temp, rotmtx_initial);
xlat_mtx2 (temp, m_dXCenter, m_dYCenter);
mult_mtx2 (rotmtx_initial, temp, rotmtx_initial);
GRFMTX_2D rotmtx_initial, temp;
xlat_mtx2 (rotmtx_initial, -m_dXCenter, -m_dYCenter);
rot_mtx2 (temp, start_angle);
mult_mtx2 (rotmtx_initial, temp, rotmtx_initial);
xlat_mtx2 (temp, m_dXCenter, m_dYCenter);
mult_mtx2 (rotmtx_initial, temp, rotmtx_initial);
double xd1=0, yd1=0, xd2=0, yd2=0;
if (m_idGeometry != GEOMETRY_EQUIANGULAR) {
xd1 = m_initPos.xd1;
yd1 = m_initPos.yd1;
xd2 = m_initPos.xd2;
yd2 = m_initPos.yd2;
double xd1=0, yd1=0, xd2=0, yd2=0;
if (m_idGeometry != GEOMETRY_EQUIANGULAR) {
xd1 = m_initPos.xd1;
yd1 = m_initPos.yd1;
xd2 = m_initPos.xd2;
yd2 = m_initPos.yd2;
- xform_mtx2 (rotmtx_initial, xd1, yd1); // rotate detector endpoints
- xform_mtx2 (rotmtx_initial, xd2, yd2); // to initial view_angle
+ xform_mtx2 (rotmtx_initial, xd1, yd1); // rotate detector endpoints
+ xform_mtx2 (rotmtx_initial, xd2, yd2); // to initial view_angle
double xs1 = m_initPos.xs1;
double ys1 = m_initPos.ys1;
double xs2 = m_initPos.xs2;
double ys2 = m_initPos.ys2;
xform_mtx2 (rotmtx_initial, xs1, ys1); // rotate source endpoints to
xform_mtx2 (rotmtx_initial, xs2, ys2); // initial view angle
double xs1 = m_initPos.xs1;
double ys1 = m_initPos.ys1;
double xs2 = m_initPos.xs2;
double ys2 = m_initPos.ys2;
xform_mtx2 (rotmtx_initial, xs1, ys1); // rotate source endpoints to
xform_mtx2 (rotmtx_initial, xs2, ys2); // initial view angle
int iView;
double viewAngle;
for (iView = 0, viewAngle = start_angle; iView < iNumViews; iView++, viewAngle += proj.rotInc()) {
int iStoragePosition = iView + iStorageOffset;
DetectorArray& detArray = proj.getDetectorArray( iStoragePosition );
int iView;
double viewAngle;
for (iView = 0, viewAngle = start_angle; iView < iNumViews; iView++, viewAngle += proj.rotInc()) {
int iStoragePosition = iView + iStorageOffset;
DetectorArray& detArray = proj.getDetectorArray( iStoragePosition );
if (pSGP && m_trace >= Trace::TRACE_PHANTOM) {
m_pSGP = pSGP;
double dWindowSize = dmax (m_detLen, m_dSourceDetectorLength) * 2;
if (pSGP && m_trace >= Trace::TRACE_PHANTOM) {
m_pSGP = pSGP;
double dWindowSize = dmax (m_detLen, m_dSourceDetectorLength) * 2;
m_dXMaxWin = m_dXCenter + dHalfWindowSize;
m_dYMinWin = m_dYCenter - dHalfWindowSize;
m_dYMaxWin = m_dYCenter + dHalfWindowSize;
m_dXMaxWin = m_dXCenter + dHalfWindowSize;
m_dYMinWin = m_dYCenter - dHalfWindowSize;
m_dYMaxWin = m_dYCenter + dHalfWindowSize;
m_pSGP->setWindow (m_dXMinWin, m_dYMinWin, m_dXMaxWin, m_dYMaxWin);
m_pSGP->setRasterOp (RO_COPY);
m_pSGP->setWindow (m_dXMinWin, m_dYMinWin, m_dXMaxWin, m_dYMaxWin);
m_pSGP->setRasterOp (RO_COPY);
m_pSGP->setColor (C_GREEN);
m_pSGP->drawCircle (m_dFocalLength);
m_pSGP->setColor (C_BLUE);
m_pSGP->setColor (C_GREEN);
m_pSGP->drawCircle (m_dFocalLength);
m_pSGP->setColor (C_BLUE);
traceShowParam ("Phantom:", "%s", PROJECTION_TRACE_ROW_PHANT_ID, C_BLACK, phm.name().c_str());
traceShowParam ("Geometry:", "%s", PROJECTION_TRACE_ROW_GEOMETRY, C_BLUE, convertGeometryIDToName(m_idGeometry));
traceShowParam ("Focal Length Ratio:", "%.2f", PROJECTION_TRACE_ROW_FOCAL_LENGTH, C_BLUE, m_dFocalLengthRatio);
traceShowParam ("Phantom:", "%s", PROJECTION_TRACE_ROW_PHANT_ID, C_BLACK, phm.name().c_str());
traceShowParam ("Geometry:", "%s", PROJECTION_TRACE_ROW_GEOMETRY, C_BLUE, convertGeometryIDToName(m_idGeometry));
traceShowParam ("Focal Length Ratio:", "%.2f", PROJECTION_TRACE_ROW_FOCAL_LENGTH, C_BLUE, m_dFocalLengthRatio);
-// traceShowParam ("Field Of View Ratio:", "%.2f", PROJECTION_TRACE_ROW_FIELD_OF_VIEW, C_BLUE, m_dFieldOfViewRatio);
+ // traceShowParam ("Field Of View Ratio:", "%.2f", PROJECTION_TRACE_ROW_FIELD_OF_VIEW, C_BLUE, m_dFieldOfViewRatio);
traceShowParam ("Num Detectors:", "%d", PROJECTION_TRACE_ROW_NDET, C_BLUE, proj.nDet());
traceShowParam ("Num Views:", "%d", PROJECTION_TRACE_ROW_NVIEW, C_BLUE, proj.nView());
traceShowParam ("Samples / Ray:", "%d", PROJECTION_TRACE_ROW_SAMPLES, C_BLUE, m_nSample);
traceShowParam ("Num Detectors:", "%d", PROJECTION_TRACE_ROW_NDET, C_BLUE, proj.nDet());
traceShowParam ("Num Views:", "%d", PROJECTION_TRACE_ROW_NVIEW, C_BLUE, proj.nView());
traceShowParam ("Samples / Ray:", "%d", PROJECTION_TRACE_ROW_SAMPLES, C_BLUE, m_nSample);
m_pSGP->lineAbs (xs2, ys2);
m_pSGP->moveAbs (xd1, yd1);
m_pSGP->lineAbs (xd2, yd2);
m_pSGP->lineAbs (xs2, ys2);
m_pSGP->moveAbs (xd1, yd1);
m_pSGP->lineAbs (xd2, yd2);
m_pSGP->setPenWidth (4);
m_pSGP->moveAbs (xs1, ys1);
m_pSGP->lineAbs (xs2, ys2);
m_pSGP->setPenWidth (4);
m_pSGP->moveAbs (xs1, ys1);
m_pSGP->lineAbs (xs2, ys2);
projectSingleView (phm, detArray, xd1, yd1, xd2, yd2, xs1, ys1, xs2, ys2, viewAngle + 3 * HALFPI);
detArray.setViewAngle (viewAngle);
projectSingleView (phm, detArray, xd1, yd1, xd2, yd2, xs1, ys1, xs2, ys2, viewAngle + 3 * HALFPI);
detArray.setViewAngle (viewAngle);
- // rs_plot (detArray, xd1, yd1, dXCenter, dYCenter, theta);
+ // rs_plot (detArray, xd1, yd1, dXCenter, dYCenter, theta);
}
#endif
xform_mtx2 (m_rotmtxIncrement, xs1, ys1);
xform_mtx2 (m_rotmtxIncrement, xs2, ys2);
if (m_idGeometry != GEOMETRY_EQUIANGULAR) {
}
#endif
xform_mtx2 (m_rotmtxIncrement, xs1, ys1);
xform_mtx2 (m_rotmtxIncrement, xs2, ys2);
if (m_idGeometry != GEOMETRY_EQUIANGULAR) {
*
* SYNOPSIS
* rayview (phm, detArray, xd1, nSample, yd1, xd2, yd2, xs1, ys1, xs2, ys2)
*
* SYNOPSIS
* rayview (phm, detArray, xd1, nSample, yd1, xd2, yd2, xs1, ys1, xs2, ys2)
-* Phantom& phm Phantom to scan
-* DETARRAY *detArray Storage of values for detector array
-* Scanner& det Scanner parameters
-* double xd1, yd1, xd2, yd2 Beginning & ending detector positions
-* double xs1, ys1, xs2, ys2 Beginning & ending source positions
+* Phantom& phm Phantom to scan
+* DETARRAY *detArray Storage of values for detector array
+* Scanner& det Scanner parameters
+* double xd1, yd1, xd2, yd2 Beginning & ending detector positions
+* double xs1, ys1, xs2, ys2 Beginning & ending source positions
Scanner::projectSingleView (const Phantom& phm, DetectorArray& detArray, const double xd1, const double yd1, const double xd2, const double yd2, const double xs1, const double ys1, const double xs2, const double ys2, const double dDetAngle)
{
Scanner::projectSingleView (const Phantom& phm, DetectorArray& detArray, const double xd1, const double yd1, const double xd2, const double yd2, const double xs1, const double ys1, const double xs2, const double ys2, const double dDetAngle)
{
double ddx=0, ddy=0, ddx2=0, ddy2=0, ddx2_ofs=0, ddy2_ofs=0, xd_maj=0, yd_maj=0;
double dAngleInc=0, dAngleSampleInc=0, dAngleSampleOffset=0, dAngleMajor=0;
if (m_idGeometry == GEOMETRY_EQUIANGULAR) {
double ddx=0, ddy=0, ddx2=0, ddy2=0, ddx2_ofs=0, ddy2_ofs=0, xd_maj=0, yd_maj=0;
double dAngleInc=0, dAngleSampleInc=0, dAngleSampleOffset=0, dAngleMajor=0;
if (m_idGeometry == GEOMETRY_EQUIANGULAR) {
dAngleSampleOffset = dAngleSampleInc / 2;
dAngleMajor = dDetAngle - (m_dAngularDetLen/2) + dAngleSampleOffset;
} else {
dAngleSampleOffset = dAngleSampleInc / 2;
dAngleMajor = dDetAngle - (m_dAngularDetLen/2) + dAngleSampleOffset;
} else {
- ddx2 = ddx / m_nSample; // Incr. between rays with detector cell
- ddy2 = ddy / m_nSample; // Doesn't include detector endpoints
+ ddx2 = ddx / m_nSample; // Incr. between rays with detector cell
+ ddy2 = ddy / m_nSample; // Doesn't include detector endpoints
if (phm.getComposition() == P_UNIT_PULSE) { // put unit pulse in center of view
for (int d = 0; d < detArray.nDet(); d++)
detval[d] = 0;
if (phm.getComposition() == P_UNIT_PULSE) { // put unit pulse in center of view
for (int d = 0; d < detArray.nDet(); d++)
detval[d] = 0;
sum += projectSingleLine (phm, xd, yd, xs, ys);
sum += projectSingleLine (phm, xd, yd, xs, ys);
- // if (m_trace >= Trace::TRACE_CLIPPING) {
- // traceShowParam ("Attenuation:", "%s", PROJECTION_TRACE_ROW_ATTEN, C_LTMAGENTA, " ");
- // traceShowParam ("Attenuation:", "%.3f", PROJECTION_TRACE_ROW_ATTEN, C_LTMAGENTA, sum);
- // }
+ // if (m_trace >= Trace::TRACE_CLIPPING) {
+ // traceShowParam ("Attenuation:", "%s", PROJECTION_TRACE_ROW_ATTEN, C_LTMAGENTA, " ");
+ // traceShowParam ("Attenuation:", "%.3f", PROJECTION_TRACE_ROW_ATTEN, C_LTMAGENTA, sum);
+ // }
Scanner::traceShowParam (const char *szLabel, const char *fmt, int row, int color, ...)
Scanner::traceShowParam (const char *szLabel, const char *fmt, int row, int color, ...)
va_list arg;
va_start(arg, color);
#ifdef HAVE_SGP
traceShowParamRasterOp (RO_COPY, szLabel, fmt, row, color, arg);
#else
traceShowParamRasterOp (0, szLabel, fmt, row, color, arg);
va_list arg;
va_start(arg, color);
#ifdef HAVE_SGP
traceShowParamRasterOp (RO_COPY, szLabel, fmt, row, color, arg);
#else
traceShowParamRasterOp (0, szLabel, fmt, row, color, arg);
Scanner::traceShowParamXOR (const char *szLabel, const char *fmt, int row, int color, ...)
Scanner::traceShowParamXOR (const char *szLabel, const char *fmt, int row, int color, ...)
Scanner::traceShowParamRasterOp (int iRasterOp, const char *szLabel, const char *fmt, int row, int color, va_list args)
Scanner::traceShowParamRasterOp (int iRasterOp, const char *szLabel, const char *fmt, int row, int color, va_list args)
vsnprintf (szValue, sizeof(szValue), fmt, args);
vsnprintf (szValue, sizeof(szValue), fmt, args);
m_pSGP->moveAbs (dXPos + dValueOffset, dYPos);
m_pSGP->drawText (szValue);
}
m_pSGP->moveAbs (dXPos + dValueOffset, dYPos);
m_pSGP->drawText (szValue);
}
*
* SYNOPSIS
* rsum = phm_ray_attenuation (phm, x1, y1, x2, y2)
*
* SYNOPSIS
* rsum = phm_ray_attenuation (phm, x1, y1, x2, y2)
-* double rsum Ray sum of Phantom along given line
-* Phantom& phm; Phantom from which to calculate raysum
-* double *x1, *y1, *x2, y2 Endpoints of ray path (in Phantom coords)
+* double rsum Ray sum of Phantom along given line
+* Phantom& phm; Phantom from which to calculate raysum
+* double *x1, *y1, *x2, y2 Endpoints of ray path (in Phantom coords)
Scanner::projectSingleLine (const Phantom& phm, const double x1, const double y1, const double x2, const double y2)
{
Scanner::projectSingleLine (const Phantom& phm, const double x1, const double y1, const double x2, const double y2)
{
double rsum = 0.0;
for (PElemConstIterator i = phm.listPElem().begin(); i != phm.listPElem().end(); i++)
rsum += projectLineAgainstPElem (**i, x1, y1, x2, y2);
double rsum = 0.0;
for (PElemConstIterator i = phm.listPElem().begin(); i != phm.listPElem().end(); i++)
rsum += projectLineAgainstPElem (**i, x1, y1, x2, y2);
*
* SYNOPSIS
* rsum = pelem_ray_attenuation (pelem, x1, y1, x2, y2)
*
* SYNOPSIS
* rsum = pelem_ray_attenuation (pelem, x1, y1, x2, y2)
-* double rsum Computed raysum
-* PhantomElement& pelem Pelem to scan
-* double x1, y1, x2, y2 Endpoints of raysum line
+* double rsum Computed raysum
+* PhantomElement& pelem Pelem to scan
+* double x1, y1, x2, y2 Endpoints of raysum line
Scanner::projectLineAgainstPElem (const PhantomElement& pelem, double x1, double y1, double x2, double y2)
{
if (! pelem.clipLineWorldCoords (x1, y1, x2, y2)) {
Scanner::projectLineAgainstPElem (const PhantomElement& pelem, double x1, double y1, double x2, double y2)
{
if (! pelem.clipLineWorldCoords (x1, y1, x2, y2)) {
double len = lineLength (x1, y1, x2, y2);
return (len * pelem.atten());
}
double len = lineLength (x1, y1, x2, y2);
return (len * pelem.atten());
}