ctsim-7.0.0/ 0000755 0001750 0001750 00000000000 15253770310 011652 5 ustar kevin kevin ctsim-7.0.0/include/ 0000755 0001750 0001750 00000000000 15253702131 013271 5 ustar kevin kevin ctsim-7.0.0/include/backprojectors.h 0000644 0001750 0001750 00000016644 15253543770 016504 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: backproject.h
** Purpose: Backprojection classes
** Programmer: Kevin Rosenberg
** Date Started: June 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef __BACKPROJECTORS_H
#define __BACKPROJECTORS_H
#include
#include
#include
#include "imagefile.h"
class Backproject;
class ImageFile;
class Projections;
struct ReconstructionROI;
class Backprojector
{
public:
static const int BPROJ_INVALID;
static const int BPROJ_TRIG;
static const int BPROJ_TABLE;
static const int BPROJ_DIFF;
static const int BPROJ_IDIFF;
static const int INTERP_INVALID;
static const int INTERP_NEAREST;
static const int INTERP_LINEAR;
static const int INTERP_CUBIC;
static const int INTERP_FREQ_PREINTERPOLATION;
Backprojector (const Projections& proj, ImageFile& im, std::string_view backprojName,
std::string_view interpName, const int interpFactor, const ReconstructionROI* pROI);
~Backprojector ();
void BackprojectView (const double* const viewData, const double viewAngle);
void PostProcessing();
bool fail() const {return m_fail;}
const std::string& failMessage() const {return m_failMessage;}
static int getBackprojectCount() {return s_iBackprojectCount;}
static const char* const* getBackprojectNameArray() {return s_aszBackprojectName;}
static const char* const* getBackprojectTitleArray() {return s_aszBackprojectTitle;}
static int convertBackprojectNameToID (std::string_view name);
static std::string_view convertBackprojectIDToName (const int bprojID);
static const char* convertBackprojectIDToTitle (const int bprojID);
static int getInterpCount() {return s_iInterpCount;}
static const char* const * getInterpNameArray() {return s_aszInterpName;}
static const char* const * getInterpTitleArray() {return s_aszInterpTitle;}
static int convertInterpNameToID (std::string_view name);
static std::string_view convertInterpIDToName (const int interpID);
static const char* convertInterpIDToTitle (const int interpID);
private:
std::string m_nameBackproject;
std::string m_nameInterpolation;
int m_idBackproject;
int m_idInterpolation;
Backproject* m_pBackprojectImplem;
bool m_fail;
std::string m_failMessage;
static const char* const s_aszBackprojectName[];
static const char* const s_aszBackprojectTitle[];
static const int s_iBackprojectCount;
static const char* const s_aszInterpName[];
static const char* const s_aszInterpTitle[];
static const int s_iInterpCount;
bool initBackprojector (const Projections& proj, ImageFile& im, std::string_view backprojName,
std::string_view interpName, const int interpFactor, const ReconstructionROI* pROI);
};
class Backproject
{
public:
Backproject (const Projections& proj, ImageFile& im, int interpID, const int interpFactor,
const ReconstructionROI* pROI);
virtual ~Backproject ();
virtual void BackprojectView (const double* const viewData, const double viewAngle) = 0;
virtual void PostProcessing (); // call after backprojecting all views
protected:
void ScaleImageByRotIncrement ();
void errorIndexOutsideDetector (int ix, int iy, double theta, double r, double phi, double L, int ni);
void errorIndexOutsideDetector (int ix, int iy, double theta, double L, int ni);
const Projections& proj;
ImageFile& im;
int interpType;
ImageFileArray v; // reference to the image's pixel storage (bound in the constructor)
kint32 nx;
kint32 ny;
double detInc;
double rotScale;
int iDetCenter; // index refering to L=0 projection
int nDet;
double xMin, xMax, yMin, yMax; // Retangular coords of phantom
double xInc, yInc; // size of cells
int m_interpFactor;
double m_dFocalLength;
double m_dSourceDetectorLength;
bool m_bPostProcessingDone;
private:
Backproject (const Backproject& rhs);
Backproject& operator= (const Backproject& rhs);
};
class BackprojectTrig : public Backproject
{
public:
BackprojectTrig (const Projections& proj, ImageFile& im, int interpID, const int interpFactor, const ReconstructionROI* pROI)
: Backproject (proj, im, interpID, interpFactor, pROI)
{}
void BackprojectView (const double* const t, const double view_angle);
};
class BackprojectTable : public Backproject
{
public:
BackprojectTable (const Projections& proj, ImageFile& im, int interpID, const int interpFactor, const ReconstructionROI* pROI);
virtual ~BackprojectTable ();
virtual void BackprojectView (const double* const t, const double view_angle);
virtual void PostProcessing (); // call after backprojecting all views
protected:
Array2d arrayR;
Array2d arrayPhi;
kfloat64** r;
kfloat64** phi;
};
class BackprojectDiff : public Backproject
{
public:
BackprojectDiff (const Projections& proj, ImageFile& im, int interpID, const int interpFactor, const ReconstructionROI* pROI);
~BackprojectDiff ();
virtual void BackprojectView (const double* const t, const double view_angle);
virtual void PostProcessing (); // call after backprojecting all views
protected:
double start_r;
double start_phi;
double im_xinc, im_yinc;
// The per-detector differences for linear interpolation, kept across
// views: BackprojectView is called once per view -- two thousand times in
// a large reconstruction -- and this was allocated and freed each time.
std::vector m_vecDelta;
};
class BackprojectIntDiff : public BackprojectDiff
{
public:
BackprojectIntDiff (const Projections& proj, ImageFile& im, int interpID, const int interpFactor, const ReconstructionROI* pROI)
: BackprojectDiff (proj, im, interpID, interpFactor, pROI)
{}
void BackprojectView (const double* const t, const double view_angle);
};
class BackprojectEquilinear : public BackprojectTable
{
public:
BackprojectEquilinear (const Projections& proj, ImageFile& im, int interpID, const int interpFactor, const ReconstructionROI* pROI)
: BackprojectTable (proj, im, interpID, interpFactor, pROI)
{}
void BackprojectView (const double* const t, const double view_angle);
virtual ~BackprojectEquilinear()
{}
};
class BackprojectEquiangular : public BackprojectTable
{
public:
BackprojectEquiangular (const Projections& proj, ImageFile& im, int interpID, const int interpFactor, const ReconstructionROI* pROI)
: BackprojectTable (proj, im, interpID, interpFactor, pROI)
{}
void BackprojectView (const double* const t, const double view_angle);
virtual ~BackprojectEquiangular()
{}
};
#endif
ctsim-7.0.0/include/timeformat.h 0000644 0001750 0001750 00000002634 15253543770 015632 0 ustar kevin kevin /*****************************************************************************
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef TIMEFORMAT_H
#define TIMEFORMAT_H
#include
// A computation time, in seconds, as text. Chooses the unit so the number
// sits between 1 and 1000 -- nanoseconds up to minutes -- and always gives
// three decimals: 0.15 -> "150.000 ms", 2.5e-6 -> "2.500 us", 90 -> "1 min
// 30.000 s". Zero or negative gives "0 s". Shared by the command-line
// tools and the interface so a duration reads the same everywhere.
std::string formatCalcTimeStd (double dSeconds);
#endif
ctsim-7.0.0/include/fourier.h 0000644 0001750 0001750 00000007430 15253543770 015135 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: fourier.h
** Purpose: Header for Fourier transform functions
** Programmer: Kevin Rosenberg
** Date Started: Dec 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#include
#include
#ifdef HAVE_FFTW
#include
#endif
class ImageFile;
class Fourier {
public:
static void shuffleFourierToNaturalOrder (ImageFile& im);
static void shuffleNaturalToFourierOrder (ImageFile& im);
#ifdef HAVE_FFTW
static void shuffleFourierToNaturalOrder (fftw_complex* pc, const int n);
static void shuffleNaturalToFourierOrder (fftw_complex* pc, const int n);
#endif
// Odd Number of Points
// Natural Frequency Order: -(n-1)/2...-1,0,1...(n-1)/2
// Fourier Frequency Order: 0, 1..(n-1)/2,-(n-1)/2...-1
// Even Number of Points
// Natural Frequency Order: -n/2...-1,0,1...((n/2)-1)
// Fourier Frequency Order: 0,1...((n/2)-1),-n/2...-1
template
static void shuffleNaturalToFourierOrder (T* pVector, const int n)
{
std::vector vecTemp (n);
T* pTemp = vecTemp.data();
int i;
if (isOdd(n)) { // Odd
int iHalfN = (n - 1) / 2;
pTemp[0] = pVector[iHalfN];
for (i = 0; i < iHalfN; i++)
pTemp[i + 1] = pVector[i + 1 + iHalfN];
for (i = 0; i < iHalfN; i++)
pTemp[i + iHalfN + 1] = pVector[i];
} else { // Even
int iHalfN = n / 2;
pTemp[0] = pVector[iHalfN];
for (i = 0; i < iHalfN - 1; i++)
pTemp[i + 1] = pVector[i + iHalfN + 1];
for (i = 0; i < iHalfN; i++)
pTemp[i + iHalfN] = pVector[i];
}
for (i = 0; i < n; i++)
pVector[i] = pTemp[i];
}
template
static void shuffleFourierToNaturalOrder (T* pVector, const int n)
{
std::vector vecTemp (n);
T* pTemp = vecTemp.data();
int i;
if (isOdd(n)) { // Odd
int iHalfN = (n - 1) / 2;
pTemp[iHalfN] = pVector[0];
for (i = 0; i < iHalfN; i++)
pTemp[i + 1 + iHalfN] = pVector[i + 1];
for (i = 0; i < iHalfN; i++)
pTemp[i] = pVector[i + iHalfN + 1];
} else { // Even
int iHalfN = n / 2;
pTemp[iHalfN] = pVector[0];
for (i = 0; i < iHalfN; i++)
pTemp[i] = pVector[i + iHalfN];
for (i = 0; i < iHalfN - 1; i++)
pTemp[i + iHalfN + 1] = pVector[i+1];
}
for (i = 0; i < n; i++)
pVector[i] = pTemp[i];
}
#if 0
static void shuffleNaturalToFourierOrder (float* pdVector, const int n);
static void shuffleNaturalToFourierOrder (double* pdVector, const int n);
static void shuffleNaturalToFourierOrder (std::complex* pdVector, const int n);
static void shuffleFourierToNaturalOrder (float* pdVector, const int n);
static void shuffleFourierToNaturalOrder (double* pdVector, const int n);
static void shuffleFourierToNaturalOrder (std::complex* pdVector, const int n);
#endif
};
ctsim-7.0.0/include/dicom.h 0000644 0001750 0001750 00000006015 15253543770 014553 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: dicom.h
** Purpose: DICOM import and export, through DCMTK
** Programmer: Kevin Rosenberg
** Date Started: March 2001
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef CTSIM_DICOM_H
#define CTSIM_DICOM_H
#include
#include
#if HAVE_DCMTK
#include
#include
#include
#ifdef GCCSUNOS
#include
#endif
#include "ctsupport.h"
// DCMTK replaces the CTN library as of 6.3.0.
#include "dcmtk/config/osconfig.h"
#include "dcmtk/dcmdata/dctk.h"
#include
class ImageFile;
class Projections;
class DicomImporter {
private:
std::string m_strFilename;
bool m_bFail;
std::string m_strFailMessage;
int m_iContents;
ImageFile* m_pImageFile;
Projections* m_pProjections;
DcmFileFormat* m_pFile;
void loadImage(unsigned short iNRows, unsigned short iNCols, unsigned short iBitsAllocated,
unsigned short iBitsStored, unsigned short iHighBit, unsigned short iPixRep);
void loadProjections();
enum {
TAG_GROUP_SOMATOM = 0x7fe1,
TAG_MEMBER_SOMATOM_DATA = 0x1000,
};
public:
enum {
DICOM_CONTENTS_INVALID = -1,
DICOM_CONTENTS_IMAGE,
DICOM_CONTENTS_PROJECTIONS,
};
DicomImporter (std::string_view svFile);
~DicomImporter();
bool testImage() const {return m_iContents == DICOM_CONTENTS_IMAGE;}
bool testProjections() const {return m_iContents == DICOM_CONTENTS_PROJECTIONS;}
bool fail() const {return m_bFail;}
const std::string& failMessage() const {return m_strFailMessage;}
ImageFile* getImageFile() const {return m_pImageFile;}
Projections* getProjections() const {return m_pProjections;}
};
class DicomExporter {
private:
const ImageFile* m_pImageFile;
std::string m_strFilename;
bool m_bFail;
std::string m_strFailMessage;
DcmFileFormat* m_pObject;
bool createDicomObject();
public:
DicomExporter (ImageFile* pImageFile);
~DicomExporter();
bool writeFile (std::string_view svFilename);
bool fail() const {return m_bFail;}
const std::string& failMessage() const {return m_strFailMessage;}
};
#endif // HAVE_DCMTK
#endif // CTSIM_DICOM_H
ctsim-7.0.0/include/phantom.h 0000644 0001750 0001750 00000026216 15253666241 015132 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: phantom.h
** Purpose: Header file for Phantom objects
** Programmer: Kevin Rosenberg
** Date Started: July 1, 1984
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef PHANTOM_H
#define PHANTOM_H
#include
#include
#include
#include
#include "ctsupport.h"
enum PhmElemType {
PELEM_INVALID,
PELEM_RECTANGLE,
PELEM_TRIANGLE,
PELEM_ELLIPSE,
PELEM_SECTOR,
PELEM_SEGMENT,
PELEM_RASTER // pixels from a PNG image
};
/* Codes for Coordinate Types */
/* Defines coords for isPointInside() */
enum CoordType {
PELEM_COORD, /* Normalized PElem Coordinates */
PHM_COORD /* World phantom Coordinates */
};
class PhantomElement
{
public:
PhantomElement (std::string_view type, const double cx, const double cy, const double u, const double v, const double rot, const double atten);
// raster element. The PNG's grayscale range [0,1] is mapped to
// [attenMin, attenMax]; (u,v) are half-extents like every other element,
// so the image spans cx +/- u, cy +/- v before rotation by rot degrees.
PhantomElement (std::string_view pngFilename, const double cx, const double cy,
const double u, const double v, const double rot,
const double attenMin, const double attenMax);
bool isRaster() const { return m_type == PELEM_RASTER; }
bool fail() const { return m_bFail; }
const std::string& failMessage() const { return m_strFailMessage; }
// Attenuation contributed at world point (x,y): 0 outside the element.
double attenuationAt (double x, double y) const;
// Exact integral of attenuation along the world segment (x1,y1)-(x2,y2).
double lineIntegral (double x1, double y1, double x2, double y2) const;
~PhantomElement ();
bool isPointInside (double x, double y, const CoordType coord_type) const;
bool clipLineNormalizedCoords (double& x1, double& y1, double& x2, double& y2) const;
bool clipLineWorldCoords (double& x1, double& y1, double& x2, double& y2) const;
int nOutlinePoints() const {return m_nPoints;}
double* rectLimits() {return m_rectLimits;}
const double* xOutline() {return m_vXOutline.data();}
const double* yOutline() {return m_vYOutline.data();}
const double* xOutline () const {return m_vXOutline.data();}
const double* yOutline () const {return m_vYOutline.data();}
double atten() const {return m_atten;}
const std::string& rasterFilename() const {return m_strRasterFile;}
// The raster pixels as attenuation, column-major with y upward, for
// drawing the element rather than only its outline.
void setRasterFilename (std::string_view str) { m_strRasterFile = str; }
int rasterWidth() const {return m_nRasterX;}
int rasterHeight() const {return m_nRasterY;}
double rasterAtten (int ix, int iy) const
{ return m_vRasterAtten[static_cast(ix) * m_nRasterY + iy]; }
double rasterAttenMin() const {return m_dRasterAttenMin;}
double rasterAttenMax() const {return m_dRasterAttenMax;}
double xmin() const {return m_xmin;}
double xmax() const {return m_xmax;}
double ymin() const {return m_ymin;}
double ymax() const {return m_ymax;}
double rot() const {return m_rot;}
double cx() const {return m_cx;}
double cy() const {return m_cy;}
double u() const {return m_u;}
double v() const {return m_v;}
static PhmElemType convertNameToType (std::string_view name);
void printDefinition (std::ostream& os) const;
void printDefinition (std::ostringstream& os) const;
private:
PhmElemType m_type; // pelem type (box, ellipse, etc)
double m_cx, m_cy; // center of pelem
double m_u, m_v; // size of pelem
double m_atten;
// 6.1.0 raster element state (empty for geometric elements)
std::vector m_vRasterAtten; // column-major, m_vRasterAtten[ix * m_nRasterY + iy], y increasing upward
int m_nRasterX = 0;
int m_nRasterY = 0;
double m_dRasterAttenMin = 0.;
double m_dRasterAttenMax = 0.;
std::string m_strRasterFile;
bool m_bFail = false;
std::string m_strFailMessage;
void initCommon ();
bool loadRasterPNG (std::string_view filename); // X-ray attenuation coefficient
double m_rot; // pelem rotation angle (in radians)
double *m_x, *m_y; // ptr to array of points in obj world coord
int m_nPoints; // number of points in outline arrays
double m_xmin, m_xmax, m_ymin, m_ymax; // pelem limits
GRFMTX_2D m_xformPhmToObj; // map from phantom to normalized pelem coords
GRFMTX_2D m_xformObjToPhm; // map from normalized pelem coords to phantom coords
std::vector m_vXOutline;
std::vector m_vYOutline;
double m_rectLimits[4];
static const int POINTS_PER_CIRCLE;
static const double SCALE_PELEM_EXTENT; // increase pelem limits by 0.5%
static const char* convertTypeToName (PhmElemType iType);
void makeTransformMatrices ();
void makeVectorOutline ();
void calcArcPoints (double x[], double y[], const int pts, const double xcent, const double ycent, const double r, const double start, const double stop);
void calcEllipsePoints (double x[], double y[], const int pts, const double u, const double v);
static int numCirclePoints (double theta);
PhantomElement (const PhantomElement& rhs); // copy constructor
PhantomElement& operator= (const PhantomElement&); // assignment operator
};
enum PhantomComposition {
P_PELEMS, // Phantom made of PElems
P_UNIT_PULSE, // Special phantom, not made of pelems
P_FILTER // defined only by this type
};
//////////////////////////////////////////////////////
// Phantom Class Declaration
//////////////////////////////////////////////////////
class SGP;
class ImageFile;
class Phantom
{
public:
static const int PHM_INVALID;
static const int PHM_HERMAN;
static const int PHM_SHEPP_LOGAN;
static const int PHM_UNITPULSE;
Phantom ();
Phantom (std::string_view phmName);
~Phantom ();
void setComposition (PhantomComposition composition)
{ m_composition = composition; }
PhantomComposition getComposition () const
{ return m_composition; }
bool createFromPhantom (std::string_view phmName);
bool createFromPhantom (const int phmid);
bool createFromFile (std::string_view fname);
bool fileWrite (std::string_view fname);
void addPElem (const PhantomElement& pelem);
void addPElem (std::string_view composition, const double cx, const double cy, const double u, const double v, const double rot, const double atten);
// add a raster (PNG) element; returns false and sets fail() on error.
// A phantom that is one PNG image: centred on the origin, one world unit
// per pixel, black at 0 and full-scale white at attenuation 1. Colour
// images are taken as their luminance. The name recorded in the
// definition (and so written to a .phm file) is pszReferenceName if
// given, else the path -- a tool writing a .phm beside the image records
// just the file name, so the pair can be moved together.
bool createFromPNG (std::string_view pngFilename,
std::string_view svReferenceName = {});
bool addRasterPElem (std::string_view pngFilename, const double cx, const double cy,
const double u, const double v, const double rot,
const double attenMin, const double attenMax);
void convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsample, const int trace) const;
void convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsample, const int trace,
const int colStart, const int colCount, bool bStoreAtColumnPos) const;
void convertToImagefile (ImageFile& im, int iNX, double dViewRatio, const int in_nsample, const int trace,
const int colStart, const int colCount, int iStorageOffset) const;
void printDefinitions (std::ostream& os) const;
void printDefinitions (std::ostringstream& os) const;
bool fail() const {return m_fail;}
const std::string& failMessage() const {return m_failMessage;}
const std::string& name() const {return m_name;}
int id() const {return m_id;}
#ifdef HAVE_SGP
void show () const;
void show (SGP& sgp) const;
void draw (SGP& sgp) const;
#endif
void addStdHerman ();
void addStdSheppLogan ();
void print (std::ostream& os) const;
void print (std::ostringstream& os) const;
double maxAxisLength () const
{ return maxValue (m_xmax - m_xmin, m_ymax - m_ymin); }
double getDiameterBoundaryCircle() const
{ return SQRT2 * maxAxisLength(); }
double xmin() const {return m_xmin;}
double xmax() const {return m_xmax;}
double ymin() const {return m_ymin;}
double ymax() const {return m_ymax;}
std::list& listPElem() {return m_listPElem;}
const std::list& listPElem() const {return m_listPElem;}
int nPElem() const {return m_nPElem;}
static int getPhantomCount() {return s_iPhantomCount;}
static const char** getPhantomNameArray() {return s_aszPhantomName;}
static const char** getPhantomTitleArray() {return s_aszPhantomTitle;}
static int convertNameToPhantomID (std::string_view phmName);
static const char* convertPhantomIDToName (const int phmID);
static const char* convertPhantomIDToTitle (const int phmID);
private:
PhantomComposition m_composition;
int m_nPElem; // number of pelems in phantom
double m_xmin, m_xmax, m_ymin, m_ymax; // extent of pelems in pelem coordinates
mutable std::list m_listPElem; // pelem lists
std::string m_name;
int m_id;
bool m_fail;
std::string m_failMessage;
static const char* s_aszPhantomName[];
static const char* s_aszPhantomTitle[];
static const int s_iPhantomCount;
void init();
Phantom (const Phantom& rhs); // copy constructor
Phantom& operator= (const Phantom&); // assignment operator
};
using PElemIterator = std::list::iterator;
using PElemConstIterator = std::list::const_iterator;
#endif
ctsim-7.0.0/include/transformmatrix.h 0000644 0001750 0001750 00000003640 15253543770 016721 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: sgp.h
** Purpose: Header file for Simple Graphics Package
** Author: Kevin Rosenberg
** Date Started: 1984
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef __H_TRANSFORMMATRIX
#define __H_TRANSFORMMATRIX
#include
class TransformationMatrix2D {
public:
double mtx[3][3];
TransformationMatrix2D () {};
TransformationMatrix2D (double m[3][3]);
void setIdentity();
void setTranslate (double x, double y);
void setScale (double sx, double sy);
void setShear (double shrx, double shry);
void setRotate (double theta);
double determinant () const;
const TransformationMatrix2D invert () const;
void transformPoint (double *pX, double *pY) const;
void print (std::ostream& ostr) const;
friend const TransformationMatrix2D operator* (const TransformationMatrix2D& lhs, const TransformationMatrix2D& rhs);
};
const TransformationMatrix2D operator* (const TransformationMatrix2D& lhs, const TransformationMatrix2D& rhs);
#endif
ctsim-7.0.0/include/plotfile.h 0000644 0001750 0001750 00000014472 15253543770 015304 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: plotfile.h
** Purpose: PlotFile class header
** Programmer: Kevin Rosenberg
** Date Started: Dec 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef PLOTFILE_H
#define PLOTFILE_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "array2dfile.h"
#include "ctsupport.h"
#include "plotfile.h"
// Plotfile structure:
// 1. Lines that begin with # are comments
// 2. ASCII file format
// 3. Header lines begin with and end with
// 4. Valid headers
// (signifies beginning of plotfile)
// (beginning of description lines)
// (signifies beginning of ezset commands)
// Beginning of data columns
// 5. Data is ASCII file format, one record per line
// Number of columns is variable and is set by ncolumns header
class PlotFile
{
private:
std::string m_strFilename;
std::string m_strDate;
std::vector m_vecStrDescriptions;
std::vector m_vecStrEzsetCommands;
std::vector m_vecCurves;
int m_iNumColumns;
int m_iNumRecords;
bool m_bScatterPlot;
// Optional display range for the y axis: the levels the plot was being
// shown at when it was saved, so it opens the same way. Only the HDF5
// format stores these; the text format has no field for them.
bool m_bHasYRange;
double m_dYMin;
double m_dYMax;
// History, as images and projections carry it: the operations that produced
// this plot and, before them, the history of the data they were made from.
// HDF5 only.
std::vector m_vecLabels;
bool writeHDF5 (std::string_view filename);
bool readHDF5 (std::string_view filename);
bool headerRead (std::iostream& os);
bool headerWrite (std::iostream& os);
bool columnsRead (std::iostream& os);
bool columnsWrite (std::iostream& os);
void initHeaders ();
PlotFile (const PlotFile& rhs); // copy constructor
PlotFile& operator= (const PlotFile&); // assignment operator
public:
PlotFile (int iNColumns, int iNRecords);
PlotFile (void);
~PlotFile ();
void setCurveSize (int iNCurves, int iNRecords, bool bScatterPlot = false);
void addDescription (std::string_view desc)
{ m_vecStrDescriptions.emplace_back (desc); }
void addEzsetCommand (std::string_view cmd)
{ m_vecStrEzsetCommands.emplace_back (cmd); }
// A span rather than a bare pointer: the column has to hold at least
// nRecords values, and with a pointer there was no way to say so or to
// check it. A std::vector converts on its own; a raw pointer that is
// still the only thing available says its length: {p, n}.
bool addColumn (int iCol, std::span column);
bool addColumn (int iCol, std::span column);
void getColumn (int iCol, double *pdColumnData) const;
const std::string& getDate () const
{ return m_strDate; }
int getNumColumns () const
{ return m_iNumColumns; }
int getNumRecords () const
{ return m_iNumRecords; }
bool getIsScatterPlot() const
{ return m_bScatterPlot; }
bool getMinMax (int startingCol, double& min, double& max) const;
bool statistics (int startingCol, double& min, double& max, double& mean, double& mode, double& median, double &stddev) const;
unsigned int getNumDescriptions (void) const
{ return m_vecStrDescriptions.size(); }
const std::string& getDescription (int iDescIndex) const
{ return m_vecStrDescriptions[iDescIndex]; }
unsigned int getNumEzsetCommands (void) const
{ return m_vecStrEzsetCommands.size(); }
const std::string& getEzsetCommand (int iIndex) const
{ return m_vecStrEzsetCommands[iIndex]; }
// Reads either format, told apart by content.
bool fileRead (std::string_view filename);
// Writes in the default format (HDF5 unless ctsimSetDefaultFileFormat says
// otherwise); the legacy text format is always available via fileWriteText.
bool fileWrite (std::string_view filename);
bool fileWriteText (std::string_view filename);
// Y-axis display range.
bool hasYRange () const { return m_bHasYRange; }
double yMin () const { return m_dYMin; }
double yMax () const { return m_dYMax; }
void setYRange (double dMin, double dMax)
{ m_bHasYRange = true; m_dYMin = dMin; m_dYMax = dMax; }
void clearYRange () { m_bHasYRange = false; }
// History.
void addHistory (std::string_view operation, const HistoryParams& params,
double dCalcTime = 0.);
void labelAdd (const Array2dFileLabel& label) { m_vecLabels.push_back (label); }
// Appends every label of an image or projection set, so a plot made from
// it carries the same past.
void labelsCopyFrom (const Array2dFile& rFile);
void labelsCopyFrom (const Array2dFileLabel& rLabel);
unsigned int nLabels () const { return m_vecLabels.size(); }
const Array2dFileLabel& labelGet (unsigned int i) const { return m_vecLabels[i]; }
const std::vector& labels () const { return m_vecLabels; }
std::vector& labels () { return m_vecLabels; }
const std::string& getFilename (void) const
{ return m_strFilename; }
void printHeaders (std::ostream& os) const;
void printHeaders (std::ostringstream& os) const;
void printHeadersBrief (std::ostream& os) const;
void printHeadersBrief (std::ostringstream& os) const;
};
#endif
ctsim-7.0.0/include/ct.h 0000644 0001750 0001750 00000005373 15253543770 014074 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: ct.h
** Purpose: Master header file for CTSim
** Programmer: Kevin Rosenberg
** Date Started: Aug 1984
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef CT_H
#define CT_H
#define NO_MAIN 1 // filter out all old main blocks
#if defined(__cplusplus) && __cplusplus < 202002L
#error "CTSim 6.1.0 and later require a C++20 compiler (use -std=c++20)"
#endif
#ifdef HAVE_CONFIG_H
#include
#endif
#ifdef _DEBUG
#undef DEBUG
#define DEBUG 1
#endif
// The standard library. These were once behind HAVE_ANSI_CPP, with a
// second set of -style includes for a compiler that had no C++
// library; CTSim has required C++20 since 6.1.0, so that branch was dead
// and the probes that chose between them answered a question nobody asks.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_PNG
#include "png.h"
#endif
#if defined(HAVE_GETOPT_H) || defined(HAVE_GETOPT_LONG)
#include
#endif
#ifdef HAVE_FFTW
#include
#endif
#include "ctsupport.h"
#include "fnetorderstream.h"
#ifdef HAVE_SGP
#include "ezplot.h"
#include "sgp.h"
#endif
#include "array2d.h"
#include "array2dfile.h"
#include "fnetorderstream.h"
#include "imagefile.h"
#include "phantom.h"
#include "scanner.h"
#include "backprojectors.h"
#include "filter.h"
#include "fourier.h"
#include "procsignal.h"
#include "projections.h"
#include "reconstruct.h"
#include "plotfile.h"
#include "trace.h"
#include "ctglobals.h"
// Macro to remove compiler warnings about unused variables
#define UNUSED(expr) do { (void)(expr); } while (0)
#endif
ctsim-7.0.0/include/ctshell.h 0000644 0001750 0001750 00000002676 15253543770 015127 0 ustar kevin kevin /*****************************************************************************
** ctshell.h
**
** The command-line functions -- phm2if, pjrec and the rest -- and the shell
** that dispatches them. One implementation, used by every binary that
** offers them: ctsim, ctsim-nogui, and each function alias.
*****************************************************************************/
#ifndef CTSHELL_H
#define CTSHELL_H
#include
// True where the string names one of the functions the shell offers. A
// caller asks this before doing anything expensive: ctsim consults it to
// decide whether it was asked for a function or for its interface, and must
// decide before constructing a QApplication so that a text invocation works
// on a machine with no display.
bool ctsimIsFunctionName (const char* pszName);
// Run the shell: dispatch one function named by argv, or read functions
// from a prompt where none was named. Returns the exit code.
int ctsimShellMain (int argc, char* argv[]);
// Run one command line and return everything it printed. For a caller
// that offers the shell without a terminal -- the graphical shell window --
// so that what it does and what the prompt does cannot drift apart.
int ctsimShellCommand (const char* pszLine, std::string& strOutput);
// The same, wrapped in the FFTW wisdom cache and a catch-all for
// exceptions. This is what a binary's main() calls.
int ctsimShellRun (int argc, char* argv[]);
#endif
ctsim-7.0.0/include/pol.h 0000644 0001750 0001750 00000015765 15253543770 014266 0 ustar kevin kevin /*****************************************************************************
** Name: pol.h
** Purpose: Header file for Problem Oriented Language Class
** Programmer: Kevin Rosenberg
** Date Started: 1984
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef __H_POL
#define __H_POL
#include
#include "hashtable.h"
#include
#include
#include
class POL {
public:
// codes for pol_usefile
enum {
P_USE_STR = 1, // use string as input source
P_USE_FILE, // use file as input source
};
POL();
~POL();
void init ();
void addSkipWord (std::string_view w);
void addSkipChar (int c);
void addKeyword (std::string_view str, int code);
bool readWord (std::string_view search, int nlet);
bool readUserToken (std::string& rString, int* code);
bool readString (std::string& rString);
bool readInteger (int *n, int typecode, bool boundcode, int bb1, int bb2);
bool readFloat (double *n, double typecode, bool boundcode, double bb1, double bb2);
bool skipTokens ();
void reader ();
bool readText (char *str, int lim); // lim is the size of the buffer
bool readText (std::string& rString); // the whole of it, however long
void usefile (int source, std::string_view fn);
void closefile ();
int lookchar ();
int inchar ();
void ungetch (int c);
int get_inputline (FILE *fp);
void set_inputline (std::string_view line);
enum {
MAXIDENT = 20,
MAXSKIPWORD = 20,
MAXSKIPCHAR = 20,
};
// token types
enum {
TT_STRING = 1, // string token
TT_INT, // integer token
TT_REAL, // floating point token
TT_ALPHA, // alphabetic token
TT_ALPNUM, // alphanumeric token
TT_NUMALPHA,
TT_SPECLCHAR,
TT_EOF, // end of file reached
TT_ERROR, // error in token, caused by call to wrong type of token reader
TT_BLANK, // white space token. pol_tok() skips these
TT_USERTOK, // user defined token
};
private:
// codes for pol_int and pol_float
// if in reject catagory, get new number from terminal
enum {
P_FLTINT = 1, // get a real or integer number
P_BFLTINT, // get a real or integer number, clip against bounds
P_CBFLTINT, // get real or int, reject if outside bounds
P_FLT, // get a real number
P_BFLT, // get a real, clip against bounds
P_CBFLT, // get a floating, reject if outside bounds
P_INT, // get a integer number
P_BINT, // get a integer, clip against bounds
P_CBINT, // get a integer, reject if outside bounds
};
#define LETTER 'a'
#define DIGIT '0'
// typedef std::map KeywordCodeList;
public:
struct token_st {
int ready; // TRUE if token is ready
// The token's text. It was a fixed 201-character array, and a longer
// token was reported as an error and truncated.
std::string tokstr;
int type; // type of token 'TT_'
int code; // holds code for user defined tokens
double fnum; // real value of token
int inum; // integer value of token
};
using TOKEN = struct token_st;
struct token_st token; // current token
// Tables words stored with install() & found with lookup()
KeywordCodeHashTable skiptable; // words to ignore and skip
KeywordCodeHashTable cmdtable; // pol parameter commands
KeywordCodeHashTable usertable; // user defined symbols
struct metachar {
char eoc; /* end of command character */
char str; /* string delimiter */
char com; /* comment character */
char cmd; /* pol parameter command character */
char prg; /* program load character */
char con; /* continuation across newline character */
char out; /* character that delimits output to terminal */
char ter; /* character indicates insertion of input from terminal */
char inb; /* input from graphics device */
} meta;
std::string m_strSkipChars; // characters to skip
bool m_bTrace;
bool m_bNewlineIsEOC;
struct KeywordCodeList {
const char *keyword;
int code;
};
static const struct KeywordCodeList cmdlist[];
static const unsigned int NUMCMD;
// Internal codes for pol commands
enum {
PC_EOC = 1,
PC_STR,
PC_COM,
PC_CMD,
PC_PRG,
PC_CON,
PC_OUT,
PC_TER,
PC_INB,
PC_NL_EOC,
PC_NL_NEOC,
PC_TRON,
PC_TROFF,
PC_FILE,
PC_DUMP,
};
enum {
INPUT_STREAM = 1,
INPUT_FILE,
INPUT_STRING,
};
// The stack of inputs being read, innermost last. It was two fixed
// arrays of eight with an index into them; the name array was filled with
// strdup and never read or freed.
struct InputSource {
FILE* fp = nullptr; // nullptr when the input is a string
std::string strName; // the file it came from, for messages
};
std::vector m_vecSources;
// The line being read, and how far into it the reader has got. It was a
// fixed 1024-character array: a longer line was silently truncated, and
// the limit was arbitrary.
std::string inputline;
std::size_t lineptr = 0;
std::stack m_stackPushBackInput;
bool skipSingleToken (char term[]);
int tok (struct token_st *token);
void dumptok (struct token_st *token);
int getpol_tok (struct token_st *token);
int getcmd ();
int gettok (TOKEN *tok);
// Each fills the string it is given, growing it as far as the input
// needs; none of them has a limit to be passed or exceeded.
void getblank (std::string& s);
int getalpha (std::string& s);
void getquote (std::string& qs);
void getescape (std::string& s, int delim);
int getnumber (std::string& str, double* fnum, int* inum);
void eatline ();
int type (int c);
int getch (FILE *fp);
};
#endif
ctsim-7.0.0/include/sgp.h 0000644 0001750 0001750 00000024656 15253666241 014263 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: sgp.h
** Purpose: Header file for Simple Graphics Package
** Author: Kevin Rosenberg
** Date Started: 1984
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef __H_SGP
#define __H_SGP
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "transformmatrix.h"
#include
#include
#ifdef HAVE_QT
// Forward declarations only: sgp.h is included by libctsim, which must not
// need the Qt include path. The Qt types live behind pointers.
class QPainter;
class QPen;
class QFont;
#endif
class SGPDriver {
private:
int m_iPhysicalXSize;
int m_iPhysicalYSize;
std::string m_sWindowTitle;
int m_idDriver;
#ifdef HAVE_QT
QPainter* m_pPainter;
#endif
int m_idG2;
public:
enum {
SGPDRIVER_WXWINDOWS = 1,
SGPDRIVER_G2 = 2,
SGPDRIVER_OPENGL = 4,
SGPDRIVER_QT = 8,
};
#ifdef HAVE_QT
// The Qt backend. The painter must outlive the driver; the caller
// owns it (a widget's paintEvent, a QImage, a QPrinter).
SGPDriver (QPainter* pPainter, int xsize, int ysize);
#endif
SGPDriver (std::string_view svWinTitle = "", int xsize = 640, int ysize = 480);
~SGPDriver ();
int getPhysicalXSize () const
{ return m_iPhysicalXSize; }
int getPhysicalYSize () const
{ return m_iPhysicalYSize; }
const std::string& getWindowTitle () const
{ return m_sWindowTitle; }
bool isWX () const
{ return (m_idDriver & SGPDRIVER_WXWINDOWS ? true : false); }
bool isG2 () const
{ return (m_idDriver & SGPDRIVER_G2 ? true : false); }
bool isQt () const
{ return (m_idDriver & SGPDRIVER_QT ? true : false); }
int idG2 () const
{ return m_idG2; }
#ifdef HAVE_QT
QPainter* idQt () const
{ return m_pPainter; }
void setPainter (QPainter* p)
{ m_pPainter = p; }
#endif
};
class SGP_RGBColor;
class SGP {
private:
int m_iPhysicalXSize; // Physical Window size
int m_iPhysicalYSize;
SGPDriver m_driver;
double xw_min; // Window extents
double yw_min;
double xw_max;
double yw_max;
double xv_min; // Viewport extents
double yv_min;
double xv_max;
double yv_max;
double viewNDC[4]; // Viewport array for clip_rect()
int m_iCurrentPhysicalX;
int m_iCurrentPhysicalY;
double m_dCurrentWorldX;
double m_dCurrentWorldY;
double m_dTextAngle;
int m_iTextPointSize;
bool m_bRecalcTransform;
double m_dPointsPerPixel; // points (72pt/in) per screen pixel;
int m_iLinestyle;
int m_iMarker;
// Master coordinates are coordinates before CTM transformation
// World coordinates are coordinates defined by setWindow()
// Normalized device coordinates range from 0. to 1. in both axes
TransformationMatrix2D wc_to_ndc; // World coord to NDC matrix
TransformationMatrix2D mc_to_ndc; // Master to NDC
TransformationMatrix2D ndc_to_mc; // NDC to Master
TransformationMatrix2D m_ctm; // Current transfromation matrix
void calc_transform ();
#if HAVE_QT
QPen* m_pQtPen;
QFont* m_pQtFont;
void initFromPainter (QPainter* pPainter);
void qtRelease ();
// The Qt side of each drawing primitive, implemented in sgp_qt.cpp so the
// Qt headers are confined to that one file.
void qtLine (int x1, int y1, int x2, int y2);
void qtPoint (int x, int y);
void qtEraseWindow ();
void qtSetTextColor (int iFG, int iBG);
void qtSetColor (int icol);
void qtSetPenWidth (int iWidth);
void qtSetRasterOp (int ro);
void qtSetLineStyle (int style);
void qtDrawText (std::string_view message);
void qtSetFontPointSize (double dPoints);
void qtGetTextExtent (std::string_view text, int* piW, int* piH);
int qtCharHeight ();
int qtCharWidth ();
void qtSetTextBold (bool bBold);
int qtTextWidth (const char* pszText);
#endif
public:
// The colour table is plain data; the Qt backend maps it to QColor.
static SGP_RGBColor s_aRGBColor[];
static int s_iRGBColorCount;
private:
public:
enum { // linestyles
LS_NOLINE = 0,
LS_SOLID = 0xffff,
LS_DASH1 = 0xff00,
LS_DASH2 = 0xf0f0,
LS_DASH3 = 0xcccc,
LS_DASH4 = 0xff3e,
LS_DOTTED = 0xaaaa,
};
enum { // Codes for marker symbols
MARKER_POINT = 0, // small dot
MARKER_SQUARE = 1, // empty square
MARKER_FSQUARE = 2, // filled square
MARKER_DIAMOND = 3, // empty diamond
MARKER_FDIAMOND = 4, // filled diamond
MARKER_CROSS = 5, // cross
MARKER_XCROSS = 6, // x
MARKER_CIRCLE = 7, // open circle
MARKER_FCIRCLE = 8, // filled circle
MARKER_BSQUARE = 9, // big open square
MARKER_BDIAMOND = 10, // big open diamond
};
enum { MARK_COUNT = 11, };
static const unsigned char MARKER_BITMAP[MARK_COUNT][5];
SGP (const SGPDriver& driver);
~SGP();
void drawCircle (const double r);
void drawArc (const double r, double start, double stop);
void drawRect (double xmin, double ymin, double xmax, double ymax);
void lineAbs(double x, double y);
void moveAbs(double x, double y);
void lineRel(double x, double y);
void moveRel(double x, double y);
void drawText (std::string_view message);
void polylineAbs(double x[], double y[], int n);
void markerAbs (double x, double y);
void markerRel(double x, double y);
void pointAbs(double x, double y);
void pointRel(double x, double y);
void eraseWindow ();
void setWindow (double xmin, double ymin, double xmax, double ymax);
void setViewport (double xmin, double ymin, double xmax, double ymax);
void frameViewport();
void setColor (int icol);
void setLineStyle (int style);
void setTextSize (double height);
void setTextNDCSize (double height);
void setTextPointSize (double height);
// Bold, for text that has to be read at a small size: a legend entry
// names a curve and is usually the smallest text on a plot.
void setTextBold (bool bBold);
// The width this string actually occupies, in world coordinates. An
// average character width is not enough to size a box around text: a
// proportional font makes "reconstruct" much wider than eleven averages.
double getTextWidth (const char* pszText);
// A width in device pixels as a width in world coordinates. Margins that
// should look the same whatever the window is are stated in pixels and
// converted here; getTextWidth is this applied to a measured string.
double deviceToWorldWidth (double dPixels);
void setTextAngle (double angle);
void setTextColor (int iFGcolor, int iBGcolor);
void setPenWidth (int width);
void setMarker (int idMarker);
void setRasterOp (int ro);
void getWindow (double& xmin, double& ymin, double& xmax, double& ymax);
void getViewport (double& xmin, double& ymin, double& xmax, double& ymax);
void getTextExtent (std::string_view text, double* x, double* y);
double getCharHeight ();
double getCharWidth ();
SGPDriver& getDriver() {return m_driver;}
const SGPDriver& getDriver() const {return m_driver;}
void ctmClear ();
void ctmSet (const TransformationMatrix2D& m);
void preTranslate (double x, double y);
void postTranslate (double x, double y);
void preScale (double sx, double sy);
void postScale (double sx, double sy);
void preRotate (double theta);
void postRotate (double theta);
void preShear (double shrx, double shry);
void postShear (double shrx, double shry);
void transformNDCtoMC (double* x, double* y);
void transformMCtoNDC (double* x, double* y);
void transformMCtoNDC (double xIn, double yIn, double* xOut, double* yOut);
void stylusNDC (double x, double y, bool beam);
void pointNDC (double x, double y);
void markerNDC (double x, double y);
#if HAVE_QT
void setPainter (QPainter* pPainter);
#endif
};
enum {
C_BLACK = 0, // color codes
C_BLUE = 1,
C_GREEN = 2,
C_CYAN = 3,
C_RED = 4,
C_MAGENTA = 5,
C_BROWN = 6,
C_GRAY = 7,
C_LTGRAY = 8,
C_LTBLUE = 9,
C_LTGREEN = 10,
C_LTCYAN = 11,
C_LTRED = 12,
C_LTMAGENTA = 13,
C_YELLOW = 14,
C_WHITE = 15,
// Curve colours, for plots with several lines on white. The sixteen
// above are the old fixed palette and are used for titles, axes and
// labels, so they are left as they are; these are added rather than
// redefined. They are the Okabe-Ito qualitative set, which was chosen
// for its separation under the common forms of colour blindness, less
// its yellow, which is illegible on white. Every one is dark enough to
// read as a thin line on a white page.
C_CURVE_1 = 16, // blue
C_CURVE_2 = 17, // vermillion
C_CURVE_3 = 18, // bluish green
C_CURVE_4 = 19, // reddish purple
C_CURVE_5 = 20, // orange
C_CURVE_6 = 21, // dark magenta
C_CURVE_7 = 22, // black
C_CURVE_8 = 23, // olive
};
// The curve colours in order, for a caller assigning one per curve.
constexpr int kCurveColorCount = 8;
constexpr int kCurveColor[kCurveColorCount] = {
C_CURVE_1, C_CURVE_2, C_CURVE_3, C_CURVE_4,
C_CURVE_5, C_CURVE_6, C_CURVE_7, C_CURVE_8
};
enum RasterOp {
RO_AND = 1,
RO_AND_INVERT,
RO_AND_REVERSE,
RO_CLEAR,
RO_COPY,
RO_EQUIV,
RO_INVERT,
RO_NAND,
RO_NOR,
RO_NO_OP,
RO_OR,
RO_OR_INVERT,
RO_OR_REVERSE,
RO_SET,
RO_SRC_INVERT,
RO_XOR,
};
class SGP_RGBColor {
private:
short int r;
short int g;
short int b;
public:
SGP_RGBColor (int r, int g, int b)
: r(r), g(g), b(b)
{}
int getRed () const
{ return r; }
int getGreen () const
{ return g; }
int getBlue () const
{ return b; }
};
#endif
ctsim-7.0.0/include/filter.h 0000644 0001750 0001750 00000014611 15253666241 014745 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: filter.h
** Purpose: Signal filter header file
** Programmer: Kevin Rosenberg
** Date Started: June 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef FILTER_H
#define FILTER_H
#include
#include
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_FFTW
#include
#include
#include
#endif
// CLASS IDENTIFICATION
// SignalFilter A filter used to process signals
//
// CONTAINS
// signal vector
//
// Can create either a time/spatial waveform or a frequency signal
// Waveforms can be created either by direct calculation or by inverse fourier transform
class SignalFilter {
public:
static const int FILTER_INVALID;
static const int FILTER_ABS_BANDLIMIT; // filter times |x|
static const int FILTER_ABS_SINC;
static const int FILTER_ABS_G_HAMMING;
static const int FILTER_ABS_HANNING;
static const int FILTER_ABS_COSINE;
static const int FILTER_BANDLIMIT;
static const int FILTER_SINC;
static const int FILTER_G_HAMMING;
static const int FILTER_HANNING;
static const int FILTER_COSINE;
static const int FILTER_TRIANGLE;
static const int DOMAIN_INVALID;
static const int DOMAIN_FREQUENCY;
static const int DOMAIN_SPATIAL;
SignalFilter (const char* szFilterName, double dFilterMinimum, double dFilterMaximum, int nFilterPoints, double dBandwidth, double dFilterParam, const char* szDomainName);
SignalFilter (const int idFilter, double dFilterMinimum, double dFilterMaximum, int nFilterPoints, double dBandwidth, double dFilterParam, const int idDomain);
SignalFilter (const char* szFilterName, const char* szDomainName, double dBandwidth, double dFilterParam);
~SignalFilter (void);
// The filter table, with its length. A span rather than a double*, so a
// const method cannot hand out a writable pointer.
std::span getFilter (void) const { return m_vecFilter; }
bool fail(void) const {return m_fail;}
const std::string& failMessage(void) const {return m_failMessage;}
const std::string& nameFilter(void) const { return m_nameFilter;}
const std::string& nameDomain(void) const { return m_nameDomain;}
int idFilter(void) const { return m_idFilter;}
int idDomain(void) const { return m_idDomain;}
int getNFilterPoints (void) const { return m_nFilterPoints; }
double getFilterMin(void) const {return m_dFilterMin;}
double getFilterMax(void) const {return m_dFilterMax;}
double getFilterIncrement(void) const {return m_dFilterInc;}
void copyFilterData(double *pdFilter, const int iStart, const int nPoints) const;
double response (double x);
static double spatialResponse (int fType, double bw, double x, double param);
static double frequencyResponse (int fType, double bw, double u, double param);
static double spatialResponseAnalytic (int fType, double bw, double x, double param);
static double spatialResponseCalc (int fType, double bw, double x, double param, int nIntegral);
static void setNumIntegral(int nIntegral) {N_INTEGRAL = nIntegral;}
static int getFilterCount() {return s_iFilterCount;}
static int getReconstructFilterCount() { return s_iReconstructFilterCount; }
static const char* const* getFilterNameArray() {return s_aszFilterName;}
static const char* const* getFilterTitleArray() {return s_aszFilterTitle;}
static int convertFilterNameToID (std::string_view name);
static const char* convertFilterIDToName (const int idFilter);
static const char* convertFilterIDToTitle (const int idFilter);
static int getDomainCount() {return s_iDomainCount;}
static const char* const* getDomainNameArray() {return s_aszDomainName;}
static const char* const* getDomainTitleArray() {return s_aszDomainTitle;}
static int convertDomainNameToID (std::string_view name);
static const char* convertDomainIDToName (const int idDomain);
static const char* convertDomainIDToTitle (const int idDomain);
static double sinc (double x)
{ return (fabs(x) > F_EPSILON ? (sin (x) / x) : 1.0); }
static double sinc (double x, double mult)
{ return (fabs(x) > F_EPSILON ? (sin (x * mult) / x) : 1.0); }
private:
int m_nFilterPoints;
double m_dBandwidth;
double m_dFilterParam;
double m_dFilterInc;
double m_dFilterMin;
double m_dFilterMax;
std::vector m_vecFilter;
std::string m_nameFilter;
std::string m_nameDomain;
int m_idFilter;
int m_idDomain;
bool m_fail;
std::string m_failMessage;
static const char* const s_aszFilterName[];
static const char* const s_aszFilterTitle[];
static const int s_iFilterCount;
static const int s_iReconstructFilterCount;
static const char* const s_aszDomainName[];
static const char* const s_aszDomainTitle[];
static const int s_iDomainCount;
static int N_INTEGRAL;
static bool haveAnalyticSpatial (const int filterID);
void init (const int idFilter, double dFilterMin, double dFilterMax, int nFilterPoints, double dBandwidth, double dFilterParam, const int idDomain);
void createFrequencyFilter (double* x) const;
void createSpatialFilter (double* x) const;
double spatialResponseCalc (double x) const;
double spatialResponseAnalytic (double x) const;
double frequencyResponse (double u) const;
static double integral_abscos (double u, double w)
{ return (fabs (u) > F_EPSILON ? (cos (u * w) - 1) / (u * u) + w / u * sin (u * w) : (w * w / 2)); }
};
#endif
ctsim-7.0.0/include/hashtable.h 0000644 0001750 0001750 00000004414 15253543770 015414 0 ustar kevin kevin /* FILE IDENTIFICATION
**
** File Name: hashtable.h
** Author: Kevin Rosenberg
** Purpose: Header file for hash table library
** Date Started: Dec. 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include
#include
#include
#include
class KeywordCodeEntry
{
private:
std::string m_strKeyword;
int m_iCode;
public:
KeywordCodeEntry (std::string_view svKeyword, int iCode);
const char* getKeyword() const
{ return m_strKeyword.c_str(); }
bool matchesKeyword (std::string_view svMatch) const;
int getCode () const
{ return m_iCode; }
void setCode (int iCode)
{ m_iCode = iCode; }
};
class KeywordCodeHashTable {
public:
enum {
HASHSIZE = 100,
};
KeywordCodeHashTable()
{ initTable(); }
~KeywordCodeHashTable()
{ freeTable(); }
void installKeywordCode (std::string_view svKeyword, int iCode);
KeywordCodeEntry* lookup (std::string_view svKeyword);
private:
// Each bucket owns its entries. It was a chain of raw pointers linked
// through the entries themselves, walked and deleted by hand; a pointer
// handed out by lookup() stays valid because the entry lives on the heap
// and the vector holds only the handle to it.
std::vector>> m_vecBuckets;
int hash (std::string_view s);
void initTable ();
void freeTable ();
};
#endif
ctsim-7.0.0/include/ctglobals.h 0000644 0001750 0001750 00000002461 15253666241 015432 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: ctglobals.h
** Purpose: Global variables for CTSim
** Programmer: Kevin Rosenberg
** Date Started: Jan 2001
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef __CTGLOBALS_H
#define __CTGLOBALS_H
// g_bRunningWXWindows moved to the graphical program (src/ctsim.h).
// Libraries no longer branch on which GUI is linked; see ctsupport_hooks.h.
#endif
ctsim-7.0.0/include/imagefile.h 0000644 0001750 0001750 00000023353 15253543770 015406 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: imagefile.h
** Purpose: imagefile class header
** Programmer: Kevin Rosenberg
** Date Started: June 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef IMAGEFILE_H
#define IMAGEFILE_H
#include
#include
#include
#include
#include
#include
#include "ctsupport.h"
#include "fnetorderstream.h"
#include "array2dfile.h"
class F32Image : public Array2dFile
{
public:
F32Image (int nx, int ny, int dataType = Array2dFile::DATA_TYPE_REAL);
F32Image (void);
// Pixels are double whatever the on-disk sample size; the planes are
// views onto one contiguous buffer (7.0.0~m8).
Array2dPlane getArray (void)
{ return realPlane(); }
Array2dPlaneConst getArray (void) const
{ return realPlane(); }
Array2dPlane getImaginaryArray (void)
{ return imagPlane(); }
Array2dPlaneConst getImaginaryArray (void) const
{ return imagPlane(); }
private:
F32Image (const F32Image& rhs);
F32Image& operator= (const F32Image& rhs);
};
class F64Image : public Array2dFile
{
public:
F64Image (int nx, int ny, int dataType = Array2dFile::DATA_TYPE_REAL);
F64Image (void);
Array2dPlane getArray (void)
{ return realPlane(); }
Array2dPlaneConst getArray (void) const
{ return realPlane(); }
Array2dPlane getImaginaryArray (void)
{ return imagPlane(); }
Array2dPlaneConst getImaginaryArray (void) const
{ return imagPlane(); }
private:
F64Image (const F64Image& rhs);
F64Image& operator= (const F64Image& rhs);
};
// 7.0.0~m8: pixels live in one std::vector per plane. These aliases
// are views onto it, so the historical usage
// ImageFileArray v = im.getArray(); v[ix][iy] = ...;
// keeps working unchanged at every call site; v(ix, iy) is the form to
// prefer in new code.
using ImageFileBase = F32Image; // on-disk sample size unchanged (float32)
using ImageFileValue = double;
using ImageFileColumn = double*;
using ImageFileColumnConst = const double*;
// Views, not references: the pixels are one buffer and these address it.
// "ImageFileArray v = im.getArray(); v[ix][iy] = ..." is unchanged.
using ImageFileArray = Array2dPlane;
using ImageFileArrayConst = Array2dPlaneConst;
class ImageFile : public ImageFileBase
{
private:
static const char* s_aszExportFormatName[];
static const char* s_aszExportFormatTitle[];
static const int s_iExportFormatCount;
static const char* s_aszImportFormatName[];
static const char* s_aszImportFormatTitle[];
static const int s_iImportFormatCount;
static void skipSpacePPM (FILE* fp); // skip space in a ppm file
static bool readIntPPM (FILE* fp, int& iValue); // checked integer read
public:
static const int EXPORT_FORMAT_INVALID;
static const int IMPORT_FORMAT_INVALID;
static const int EXPORT_FORMAT_TEXT;
static const int EXPORT_FORMAT_PGM;
static const int EXPORT_FORMAT_PGMASCII;
static const int IMPORT_FORMAT_PPM;
#if HAVE_PNG
static const int EXPORT_FORMAT_PNG;
static const int EXPORT_FORMAT_PNG16;
static const int IMPORT_FORMAT_PNG;
#endif
#if HAVE_DCMTK
static const int EXPORT_FORMAT_DICOM;
static const int IMPORT_FORMAT_DICOM;
#endif
static const int EXPORT_FORMAT_RAW;
static int getExportFormatCount() {return s_iExportFormatCount;}
static const char** getExportFormatNameArray() {return s_aszExportFormatName;}
static const char** getExportFormatTitleArray() {return s_aszExportFormatTitle;}
static int convertExportFormatNameToID (std::string_view name);
static const char* convertExportFormatIDToName (const int ExportFormatID);
static const char* convertExportFormatIDToTitle (const int ExportFormatID);
static int getImportFormatCount() {return s_iImportFormatCount;}
static const char** getImportFormatNameArray() {return s_aszImportFormatName;}
static const char** getImportFormatTitleArray() {return s_aszImportFormatTitle;}
static int convertImportFormatNameToID (std::string_view name);
static const char* convertImportFormatIDToName (const int ImportFormatID);
static const char* convertImportFormatIDToTitle (const int ImportFormatID);
static const double s_dRedGrayscaleFactor;
static const double s_dGreenGrayscaleFactor;
static const double s_dBlueGrayscaleFactor;
ImageFile (int nx, int ny)
: ImageFileBase (nx, ny)
{}
ImageFile (void)
: ImageFileBase ()
{}
void getCenterCoordinates (unsigned int& iXCenter, unsigned int& iYCenter);
bool convertRealToComplex ();
bool convertComplexToReal ();
void filterResponse (std::string_view domainName, double bw, std::string_view filterName, double filt_param, double dInputScale = 1., double dOutputScale = 1.);
void statistics (double& min, double& max, double& mean, double& mode, double& median, double& stddev) const;
void statistics (ImageFileArrayConst v, double& min, double& max, double& mean, double& mode, double& median, double& stddev) const;
void getMinMax (double& min, double& max) const;
void printStatistics (std::ostream& os) const;
bool comparativeStatistics (const ImageFile& imComp, double& d, double& r, double& e) const;
// The three measures written the same way everywhere they are reported --
// if2, the graphical comparison, and a script's expect-compare --
// so a number printed by one can be compared with a number printed by
// another. Nine significant digits: a double carries about sixteen, and
// six was too few to tell two reconstructions apart.
//
// The names matter: d and r are error measures, but e is not. It is the
// worst 2x2 neighbourhood, from Herman's book, and calling it an error
// invites it to be read as one.
static std::string formatComparativeStatistics (double d, double r, double e);
// Each measure has a short label, used where the numbers are reported, and
// a full name, used where there is room to explain what is being measured.
// The short labels are what a person scanning a column of output reads, and
// what a harness matches on.
static const char* labelOfDistanceMeasure(); // "NormRMS"
static const char* labelOfAbsoluteMeasure(); // "NormMeanAbs"
static const char* labelOfWorstCaseMeasure(); // "Worst2x2"
static const char* nameOfDistanceMeasure(); // "normalized root mean squared distance"
static const char* nameOfAbsoluteMeasure(); // "normalized mean absolute distance"
static const char* nameOfWorstCaseMeasure(); // "worst case 2x2 neighbourhood distance"
bool printComparativeStatistics (const ImageFile& imComp, std::ostream& os) const;
bool subtractImages (const ImageFile& rRHS, ImageFile& result) const;
bool addImages (const ImageFile& rRHS, ImageFile& result) const;
bool multiplyImages (const ImageFile& rRHS, ImageFile& result) const;
bool divideImages (const ImageFile& rRHS, ImageFile& result) const;
bool scaleImage (ImageFile& result) const;
bool invertPixelValues (ImageFile& result) const;
bool sqrt (ImageFile& result) const;
bool square (ImageFile& result) const;
bool log (ImageFile& result) const;
bool exp (ImageFile& result) const;
bool fourier (ImageFile& result) const;
bool inverseFourier (ImageFile& result) const;
#ifdef HAVE_FFTW
bool fft (ImageFile& result) const;
bool ifft (ImageFile& result) const;
// In-place transforms: these modify this image's own pixels and convert it
// to complex if needed. Before 6.2.0 they took an ImageFile& that every
// caller had to alias to *this (rIF.fftRows (rIF)); the parameter is gone.
bool fftRows ();
bool ifftRows ();
bool fftCols ();
bool ifftCols ();
#endif
bool magnitude (ImageFile& result) const;
bool phase (ImageFile& result) const;
bool real (ImageFile& result) const;
bool imaginary (ImageFile& result) const;
bool exportImage (std::string_view format, std::string_view filename, int nxcell, int nycell, double densmin, double densmax);
bool importImage (std::string_view format, std::string_view filename);
#ifdef HAVE_PNG
bool writeImagePNG (std::string_view outfile, int bitdepth, int nxcell, int nycell, double densmin, double densmax);
bool readImagePNG (std::string_view filename);
#endif
bool writeImagePGM (std::string_view outfile, int nxcell, int nycell, double densmin, double densmax);
bool writeImagePGMASCII (std::string_view outfile, int nxcell, int nycell, double densmin, double densmax);
bool readImagePPM (std::string_view filename);
bool writeImageRaw (std::string_view outfile, int nxcell, int nycell);
bool writeImageText (std::string_view outfile);
static double redGrayscaleFactor() {return s_dRedGrayscaleFactor;}
static double greenGrayscaleFactor() {return s_dGreenGrayscaleFactor;}
static double blueGrayscaleFactor() {return s_dBlueGrayscaleFactor;}
static double colorToGrayscale (double r, double g, double b)
{ return r * s_dRedGrayscaleFactor + g * s_dGreenGrayscaleFactor + b * s_dBlueGrayscaleFactor; }
};
#endif
ctsim-7.0.0/include/array2d.h 0000644 0001750 0001750 00000006065 15253666241 015030 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: array2d.h
** Purpose: 2-dimension array classes
** Programmer: Kevin Rosenberg
** Date Started: June 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef ARRAY2D_H
#define ARRAY2D_H
#include "ctsupport.h"
#include
// storage is std::vector, so the destructor is no longer hand written.
// Until 6.3.x this class allocated a T*[nx] of T[ny] rows and released each row
// with a scalar delete, which is undefined behaviour; with 1024-detector
// reconstructions it corrupted the heap and crashed pjrec (fixed in 6.2.1, but
// only by correcting the delete). A column pointer table is kept so that
// getArray() can still hand out a T** to the existing call sites.
template
class Array2d {
public:
Array2d (unsigned int x, unsigned int y)
: m_nx(0), m_ny(0)
{
initSetSize (x, y);
}
Array2d ()
: m_nx(0), m_ny(0)
{}
~Array2d ()
{}
void initSetSize (unsigned int x, unsigned int y)
{
m_nx = x;
m_ny = y;
m_vecData.assign (m_nx, std::vector (m_ny, T()));
m_vecColumns.resize (m_nx);
for (unsigned int i = 0; i < m_nx; i++)
m_vecColumns[i] = m_vecData[i].data();
}
T** getArray () const
{ return m_nx ? const_cast(m_vecColumns.data()) : nullptr; }
T* getColumn (unsigned int x) const
{ return (x < m_nx) ? const_cast(m_vecData[x].data()) : nullptr; }
T getPoint (unsigned int x, unsigned int y) const
{ return (x < m_nx && y < m_ny) ? m_vecData[x][y] : T(); }
unsigned int sizeofPixel () const
{ return sizeof(T); }
unsigned int sizeofColumn () const
{ return (sizeof(T) * m_ny); }
unsigned int sizeofArray () const
{ return (sizeof(T) * m_nx * m_ny); }
private:
unsigned int m_nx;
unsigned int m_ny;
std::vector > m_vecData;
std::vector m_vecColumns; // non-owning view, for the T** accessor
Array2d (const Array2d& rhs); // the column table would dangle
Array2d& operator= (const Array2d& rhs);
};
#endif
ctsim-7.0.0/include/fnetorderstream.h 0000644 0001750 0001750 00000007066 15253543770 016673 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: fnetorderstream.h
** Purpose: Network-order file stream header
** Programmer: Kevin Rosenberg
** Date Started: Sep 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef NETORDER_H
#define NETORDER_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include
#include
#include
inline bool NativeBigEndian (void)
{
#ifdef WORDS_BIGENDIAN
return true;
#else
return false;
#endif
}
inline void
SwapBytes2 (void* buffer)
{
unsigned char* p = static_cast(buffer);
unsigned char temp = p[0];
p[0] = p[1];
p[1] = temp;
}
// 0<->3 1<->2 = 0123 -> 3210
inline void
SwapBytes4 (void* buffer)
{
unsigned char* p = static_cast(buffer);
unsigned char temp = p[0];
p[0] = p[3];
p[3] = temp;
temp = p[1];
p[1] = p[2];
p[2] = temp;
}
// 0<->7 1<->6 2<->5 3<->4 = 01234567 -> 76543210
inline void
SwapBytes8 (void* buffer)
{
unsigned char* p = static_cast(buffer);
unsigned char temp = p[0];
p[0] = p[7];
p[7] = temp;
temp = p[1];
p[1] = p[6];
p[6] = temp;
temp = p[2];
p[2] = p[5];
p[5] = temp;
temp = p[3];
p[3] = p[4];
p[4] = temp;
}
inline void
SwapBytes2IfLittleEndian (void* buffer)
{
#ifndef WORDS_BIGENDIAN
SwapBytes2 (buffer);
#endif
}
inline void
SwapBytes4IfLittleEndian (void* buffer)
{
#ifndef WORDS_BIGENDIAN
SwapBytes4 (buffer);
#endif
}
inline void
SwapBytes8IfLittleEndian (void* buffer)
{
#ifndef WORDS_BIGENDIAN
SwapBytes8 (buffer);
#endif
}
void ConvertNetworkOrder (void* buffer, size_t bytes);
void ConvertReverseNetworkOrder (void* buffer, size_t bytes);
using std::fstream;
class fnetorderstream : public fstream {
public:
fnetorderstream (const char* filename, std::ios::openmode mode)
: fstream (filename, mode) {}
~fnetorderstream (void)
{}
virtual void writeInt16 (kuint16 n);
virtual void writeInt32 (kuint32 n);
virtual void writeFloat32 (kfloat32 n);
virtual void writeFloat64 (kfloat64 n);
virtual void readInt16 (kuint16& n);
virtual void readInt32 (kuint32& n);
virtual void readFloat32 (kfloat32& n);
virtual void readFloat64 (kfloat64& n);
};
class frnetorderstream : public fnetorderstream {
public:
frnetorderstream (const char* filename, std::ios::openmode mode)
: fnetorderstream (filename, mode) {}
virtual void writeInt16 (kuint16 n);
virtual void writeInt32 (kuint32 n);
virtual void writeFloat32 (kfloat32 n);
virtual void writeFloat64 (kfloat64 n);
virtual void readInt16 (kuint16& n);
virtual void readInt32 (kuint32& n);
virtual void readFloat32 (kfloat32& n);
virtual void readFloat64 (kfloat64& n);
};
#endif
ctsim-7.0.0/include/fileformat.h 0000644 0001750 0001750 00000004342 15253666241 015610 0 ustar kevin kevin /*****************************************************************************
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef CTSIM_FILEFORMAT_H
#define CTSIM_FILEFORMAT_H
#include
#include
// HDF5 is the default format for newly written image and projection
// files. Reading detects the format from the file itself, so the legacy
// binaries keep working and no flag is needed to open them.
enum CTSimFileFormat {
CTSIM_FORMAT_LEGACY, // the original CTSim binary .if / .pj
CTSIM_FORMAT_HDF5
};
// True when the file begins with the HDF5 signature. Works even in a build
// without HDF5 support, so such a build can report the situation properly
// rather than failing to parse.
bool ctsimFileIsHDF5 (std::string_view svFilename);
// True when this build can actually read and write HDF5.
bool ctsimHaveHDF5 ();
// What a file holds, determined from the file itself: the HDF5 "content"
// attribute, or the two-byte signature of a legacy file. Lets a caller pick
// the right reader instead of trying each and emitting errors on the way.
enum CTSimFileContent {
CTSIM_CONTENT_UNKNOWN,
CTSIM_CONTENT_IMAGE,
CTSIM_CONTENT_PROJECTIONS,
CTSIM_CONTENT_PLOT // text .plt; recognized by its tag (7.0.0)
};
CTSimFileContent ctsimFileContent (std::string_view svFilename);
CTSimFileFormat ctsimDefaultFileFormat ();
void ctsimSetDefaultFileFormat (CTSimFileFormat format);
#endif
ctsim-7.0.0/include/reconstruct.h 0000644 0001750 0001750 00000005101 15253543770 016026 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: reconstruct.h Header file for Reconstruction class
** Programmer: Kevin Rosenberg
** Date Started: Aug 84
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef __RECONSTRUCT_H
#define __RECONSTRUCT_H
#include
#include
class Projections;
class ImageFile;
class Backprojector;
class ProcessSignal;
#include
#include
struct ReconstructionROI {
double m_dXMin;
double m_dYMin;
double m_dXMax;
double m_dYMax;
};
class Reconstructor
{
private:
const Projections& m_rOriginalProj;
const Projections* m_pProj;
ImageFile& m_rImagefile;
ProcessSignal* m_pProcessSignal;
Backprojector* m_pBackprojector;
int m_nFilteredProjections;
int m_iTrace;
const bool m_bRebinToParallel;
bool m_bFail;
std::string m_strFailMessage;
std::vector m_vecPlotXAxis;
public:
Reconstructor (const Projections& rProj, ImageFile& rIF, std::string_view filterName, double filt_param,
std::string_view filterMethodName, const int zeropad, std::string_view filterGenerationName,
std::string_view interpName, int interpFactor, std::string_view backprojectName, const int trace,
ReconstructionROI* pROI = nullptr, bool bRebinToParallel = false, SGP* pSGP = nullptr);
~Reconstructor ();
bool fail() const {return m_bFail;}
const std::string& failMessage() const {return m_strFailMessage;}
void plotFilter (SGP* pSGP = nullptr);
void reconstructAllViews ();
void reconstructView (int iStartView = 0, int iViewCount = -1, SGP* pSGP = nullptr, bool bBackprojectView = true, double dGraphWidth = 1.);
void postProcessing ();
};
#endif
ctsim-7.0.0/include/scanner.h 0000644 0001750 0001750 00000017705 15253543770 015121 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: scanner.h
** Purpose: Scanner header file
** Programmer: Kevin Rosenberg
** Date Started: July 1, 1984
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef SCANNER_H
#define SCANNER_H
#include
#include
#include
#include
#include "trace.h"
class Projections;
class Phantom;
class PhantomElement;
class SGP;
// Projections are collected along an array of ndet detectors. The data
// for these detectors is stored in the class DetectorArray
using DetectorValue = float;
class DetectorArray
{
public:
DetectorArray (const int ndet);
~DetectorArray ();
int nDet() const {return m_nDet;}
double viewAngle() const {return m_viewAngle;}
// Spans, so the values travel with their count. The array owns a vector
// rather than a new[] that had to be matched with a delete[].
std::span detValues() { return m_vecDetValues; }
std::span detValues() const { return m_vecDetValues; }
void setViewAngle (double viewAngle)
{ m_viewAngle = viewAngle; }
private:
std::vector m_vecDetValues; // what the detectors recorded
int m_nDet; // Number of detectors in array */
double m_viewAngle; // View angle in radians
DetectorArray& operator=(const DetectorArray& rhs); // assignment
DetectorArray (const DetectorArray& rhs); // copy constructor
};
class Scanner
{
public:
static const int GEOMETRY_INVALID;
static const int GEOMETRY_PARALLEL;
static const int GEOMETRY_EQUILINEAR;
static const int GEOMETRY_EQUIANGULAR;
Scanner (const Phantom& phm, std::string_view geometryName, int nDet,
int nView, int iOffsetView, int nSample, const double rot_anglen,
double dFocalLengthRatio, double dCenterDetectorRatio, double dViewRatio, double dScanRatio);
~Scanner();
void collectProjections (Projections& proj, const Phantom& phm, const int trace = Trace::TRACE_NONE,
SGP* pSGP = nullptr);
void collectProjections (Projections& proj, const Phantom& phm, const int iStartView, const int iNumViews, const int iOffsetView, bool bStoreAtViewPosition, const int trace = Trace::TRACE_NONE, SGP* pSGP = nullptr);
void collectProjections (Projections& proj, const Phantom& phm, const int iStartView, const int iNumViews, const int iOffsetView, int iStorageOffset, const int trace = Trace::TRACE_NONE, SGP* pSGP = nullptr);
void setNView (int nView);
void setOffsetView (int iOffsetView);
bool fail() const {return m_fail;}
const std::string& failMessage() const {return m_failMessage;}
unsigned int nDet() const {return m_nDet;}
unsigned int nView() const {return m_nView;}
unsigned int offsetView() const {return m_iOffsetView;}
unsigned int startView() const {return m_startView;}
double rotInc() const {return m_rotInc;}
double detInc() const {return m_detInc;}
double detLen() const {return m_detLen;}
double detStart() const {return m_detStart;}
double focalLength() const {return m_dFocalLength;}
double sourceDetectorLength() const {return m_dSourceDetectorLength;}
double centerDetectorLength() const {return m_dCenterDetectorLength;}
double viewDiameter() const {return m_dViewDiameter;}
double scanDiameter() const {return m_dScanDiameter;}
double fanBeamAngle() const {return m_dFanBeamAngle;}
int geometry() const {return m_idGeometry;}
static int getGeometryCount() {return s_iGeometryCount;}
static const char* const* getGeometryNameArray() {return s_aszGeometryName;}
static const char* const* getGeometryTitleArray() {return s_aszGeometryTitle;}
static int convertGeometryNameToID (std::string_view name);
static const char* convertGeometryIDToName (const int idGeometry);
static const char* convertGeometryIDToTitle (const int idGeometry);
private:
bool m_fail;
std::string m_failMessage;
int m_idGeometry;
unsigned int m_nDet; /* Number of detectors in array */
unsigned int m_nView; /* Number of rotated views */
unsigned int m_iOffsetView;
unsigned int m_startView;
unsigned int m_nSample; /* Number of rays per detector */
double m_dFocalLength; // Focal Length, distance from source to center
double m_dSourceDetectorLength; // Distance from source to detectors
double m_dCenterDetectorLength; // Distance from center to detectors
double m_dViewDiameter; // Diameter of area being processed
double m_dScanDiameter; // Diamer of area being scanned
double m_dViewRatio; // View Ratio to diameter phantom
double m_dFocalLengthRatio; // Source to Center Length as ratio to viewDiameter radius
double m_dCenterDetectorRatio; // Center to Detector Length as ratio of viewDiameter radius
double m_dScanRatio; // Scan length to view length ratio
double m_dFanBeamAngle;
double m_detLen; // Total length of detector array
double m_rotLen; // Rotation angle length in radians (norm 2PI)
double m_detInc; // Increment between centers of detectors
double m_rotInc; // Increment in rotation angle between views
double m_detStart;
double m_dXCenter; // Center of Phantom
double m_dYCenter;
double m_dAngularDetIncrement;
double m_dAngularDetLen;
int m_trace;
struct {
double xd1,yd1,xd2,yd2; /* Coordinates of detector endpoints */
double xs1,ys1,xs2,ys2; /* Coordinates of source endpoints */
double angle; /* Starting angle */
double dAngularDet;
} m_initPos;
GRFMTX_2D m_rotmtxIncrement;
#ifdef HAVE_SGP
SGP* m_pSGP; // Pointer to graphics device
double m_dXMinWin; // Extent of graphics window
double m_dXMaxWin;
double m_dYMinWin;
double m_dYMaxWin;
double m_dTextHeight;
#endif
static const char* const s_aszGeometryName[];
static const char* const s_aszGeometryTitle[];
static const int s_iGeometryCount;
void projectSingleView (const Phantom& phm, DetectorArray& darray, 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 projectSingleLine (const Phantom& phm, const double x1, const double y1, const double x2, const double y2);
double projectLineAgainstPElem (const PhantomElement& pelem, const double x1, const double y1, const double x2, const double y2);
void traceShowParam (const char* szLabel, const char *fmt, int row, int color, ...);
void traceShowParamXOR (const char* szLabel, const char *fmt, int row, int color, ...);
void traceShowParamRasterOp (int iRasterOp, const char* szLabel, const char* fmt, int row, int color, va_list va);
};
const static int PROJECTION_TRACE_ROW_PHANT_ID=0;
const static int PROJECTION_TRACE_ROW_GEOMETRY=1;
const static int PROJECTION_TRACE_ROW_FOCAL_LENGTH=2;
const static int PROJECTION_TRACE_ROW_FIELD_OF_VIEW=3;
const static int PROJECTION_TRACE_ROW_NDET=4;
const static int PROJECTION_TRACE_ROW_NVIEW=5;
const static int PROJECTION_TRACE_ROW_SAMPLES=6;
const static int PROJECTION_TRACE_ROW_CURR_VIEW=7;
const static int PROJECTION_TRACE_ROW_ATTEN=8;
#endif
ctsim-7.0.0/include/pngmeta.h 0000644 0001750 0001750 00000004373 15253543770 015120 0 ustar kevin kevin /*****************************************************************************
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef PNGMETA_H
#define PNGMETA_H
#include
#include
#include
// What a PNG file says about itself (M6b): the header fields and the
// optional chunks a viewer would want to show -- gamma, physical resolution,
// text. Read without decoding the pixels, so it is cheap for any size.
#include
#include
struct PNGMetadata {
int iWidth = 0;
int iHeight = 0;
int iBitDepth = 0;
std::string strColorType; // "grayscale", "RGB", "palette", "grayscale+alpha", "RGBA"
int iChannels = 0;
bool bInterlaced = false;
bool bHasGamma = false;
double dGamma = 0.;
bool bHasResolution = false; // pHYs
double dPixelsPerMetreX = 0.;
double dPixelsPerMetreY = 0.;
bool bHasBackground = false;
bool bHasTransparency = false; // tRNS
bool bHasICCProfile = false;
bool bHasSRGB = false;
std::vector > vecText; // tEXt / zTXt / iTXt, key and value
std::int64_t lFileBytes = 0; // long is 32 bits on Windows
};
// True if the file begins with the PNG signature.
bool pngFileIsPNG (std::string_view svFilename);
// Reads the header and ancillary chunks. False, with strError set, if the
// file is not a PNG or cannot be read.
bool pngReadMetadata (std::string_view svFilename, PNGMetadata& meta, std::string& strError);
#endif
ctsim-7.0.0/include/array2dfile.h 0000644 0001750 0001750 00000033644 15253666241 015673 0 ustar kevin kevin /*****************************************************************************
** FILE IDENTIFICATION
**
** Name: array2dfile.h
** Purpose: 2-dimension array file class
** Programmer: Kevin Rosenberg
** Date Started: June 2000
**
** This is part of the CTSim program
** Copyright (c) 1983-2026 Kevin Rosenberg
** SPDX-License-Identifier: GPL-3.0-or-later
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
******************************************************************************/
#ifndef ARRAY2DFILE_H
#define ARRAY2DFILE_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include