summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--COPYING674
-rw-r--r--NEWS.txt23
-rw-r--r--README.txt100
-rw-r--r--astra_vc08.sln215
-rw-r--r--astra_vc08.vcproj3146
-rw-r--r--build/Cuda.rules358
-rw-r--r--build/linux/Makefile.in314
-rw-r--r--build/linux/README.txt20
-rw-r--r--build/linux/acinclude.m474
-rwxr-xr-xbuild/linux/autogen.sh36
-rwxr-xr-xbuild/linux/config.guess.dist1501
-rwxr-xr-xbuild/linux/config.sub.dist1705
-rw-r--r--build/linux/configure.ac185
-rwxr-xr-xbuild/linux/install-sh.dist519
-rw-r--r--cuda/2d/algo.cu356
-rw-r--r--cuda/2d/algo.h155
-rw-r--r--cuda/2d/arith.cu893
-rw-r--r--cuda/2d/arith.h101
-rw-r--r--cuda/2d/astra.cu824
-rw-r--r--cuda/2d/astra.h205
-rw-r--r--cuda/2d/cgls.cu304
-rw-r--r--cuda/2d/cgls.h92
-rw-r--r--cuda/2d/darthelper.cu358
-rw-r--r--cuda/2d/darthelper.h44
-rw-r--r--cuda/2d/dataop.cu130
-rw-r--r--cuda/2d/dataop.h47
-rw-r--r--cuda/2d/dims.h68
-rw-r--r--cuda/2d/em.cu262
-rw-r--r--cuda/2d/em.h77
-rw-r--r--cuda/2d/fan_bp.cu374
-rw-r--r--cuda/2d/fan_bp.h45
-rw-r--r--cuda/2d/fan_fp.cu370
-rw-r--r--cuda/2d/fan_fp.h41
-rw-r--r--cuda/2d/fbp_filters.h58
-rw-r--r--cuda/2d/fft.cu873
-rw-r--r--cuda/2d/fft.h69
-rw-r--r--cuda/2d/par_bp.cu357
-rw-r--r--cuda/2d/par_bp.h48
-rw-r--r--cuda/2d/par_fp.cu704
-rw-r--r--cuda/2d/par_fp.h41
-rw-r--r--cuda/2d/sart.cu283
-rw-r--r--cuda/2d/sart.h85
-rw-r--r--cuda/2d/sirt.cu342
-rw-r--r--cuda/2d/sirt.h90
-rw-r--r--cuda/2d/util.cu244
-rw-r--r--cuda/2d/util.h90
-rw-r--r--cuda/3d/algo3d.cu108
-rw-r--r--cuda/3d/algo3d.h68
-rw-r--r--cuda/3d/arith3d.cu610
-rw-r--r--cuda/3d/arith3d.h79
-rw-r--r--cuda/3d/astra3d.cu1620
-rw-r--r--cuda/3d/astra3d.h450
-rw-r--r--cuda/3d/cgls3d.cu428
-rw-r--r--cuda/3d/cgls3d.h114
-rw-r--r--cuda/3d/cone_bp.cu481
-rw-r--r--cuda/3d/cone_bp.h45
-rw-r--r--cuda/3d/cone_fp.cu513
-rw-r--r--cuda/3d/cone_fp.h46
-rw-r--r--cuda/3d/darthelper3d.cu229
-rw-r--r--cuda/3d/darthelper3d.h46
-rw-r--r--cuda/3d/dims3d.h84
-rw-r--r--cuda/3d/fdk.cu646
-rw-r--r--cuda/3d/fdk.h43
-rw-r--r--cuda/3d/par3d_bp.cu464
-rw-r--r--cuda/3d/par3d_bp.h45
-rw-r--r--cuda/3d/par3d_fp.cu814
-rw-r--r--cuda/3d/par3d_fp.h51
-rw-r--r--cuda/3d/sirt3d.cu533
-rw-r--r--cuda/3d/sirt3d.h118
-rw-r--r--cuda/3d/util3d.cu514
-rw-r--r--cuda/3d/util3d.h69
-rw-r--r--include/astra/Algorithm.h135
-rw-r--r--include/astra/AlgorithmTypelist.h108
-rw-r--r--include/astra/ArtAlgorithm.h196
-rw-r--r--include/astra/AstraObjectFactory.h149
-rw-r--r--include/astra/AstraObjectManager.h290
-rw-r--r--include/astra/AsyncAlgorithm.h128
-rw-r--r--include/astra/BackProjectionAlgorithm.h155
-rw-r--r--include/astra/CglsAlgorithm.h182
-rw-r--r--include/astra/ConeProjectionGeometry3D.h213
-rw-r--r--include/astra/ConeVecProjectionGeometry3D.h154
-rw-r--r--include/astra/Config.h80
-rw-r--r--include/astra/CudaBackProjectionAlgorithm.h110
-rw-r--r--include/astra/CudaBackProjectionAlgorithm3D.h152
-rw-r--r--include/astra/CudaCglsAlgorithm.h122
-rw-r--r--include/astra/CudaCglsAlgorithm3D.h173
-rw-r--r--include/astra/CudaDartMaskAlgorithm.h126
-rw-r--r--include/astra/CudaDartMaskAlgorithm3D.h122
-rw-r--r--include/astra/CudaDartSmoothingAlgorithm.h125
-rw-r--r--include/astra/CudaDartSmoothingAlgorithm3D.h122
-rw-r--r--include/astra/CudaDataOperationAlgorithm.h128
-rw-r--r--include/astra/CudaEMAlgorithm.h92
-rw-r--r--include/astra/CudaFDKAlgorithm3D.h164
-rw-r--r--include/astra/CudaFilteredBackProjectionAlgorithm.h94
-rw-r--r--include/astra/CudaForwardProjectionAlgorithm.h169
-rw-r--r--include/astra/CudaForwardProjectionAlgorithm3D.h135
-rw-r--r--include/astra/CudaProjector2D.h122
-rw-r--r--include/astra/CudaProjector3D.h131
-rw-r--r--include/astra/CudaReconstructionAlgorithm2D.h176
-rw-r--r--include/astra/CudaRoiSelectAlgorithm.h123
-rw-r--r--include/astra/CudaSartAlgorithm.h112
-rw-r--r--include/astra/CudaSirtAlgorithm.h131
-rw-r--r--include/astra/CudaSirtAlgorithm3D.h187
-rw-r--r--include/astra/DataProjector.h327
-rw-r--r--include/astra/DataProjectorPolicies.h382
-rw-r--r--include/astra/DataProjectorPolicies.inl855
-rw-r--r--include/astra/FanFlatBeamLineKernelProjector2D.h194
-rw-r--r--include/astra/FanFlatBeamLineKernelProjector2D.inl740
-rw-r--r--include/astra/FanFlatBeamStripKernelProjector2D.h191
-rw-r--r--include/astra/FanFlatBeamStripKernelProjector2D.inl961
-rw-r--r--include/astra/FanFlatProjectionGeometry2D.h244
-rw-r--r--include/astra/FanFlatVecProjectionGeometry2D.h155
-rw-r--r--include/astra/FilteredBackProjectionAlgorithm.h155
-rw-r--r--include/astra/Float32Data.h88
-rw-r--r--include/astra/Float32Data2D.h544
-rw-r--r--include/astra/Float32Data3D.h199
-rw-r--r--include/astra/Float32Data3DMemory.h338
-rw-r--r--include/astra/Float32ProjectionData2D.h247
-rw-r--r--include/astra/Float32ProjectionData3D.h257
-rw-r--r--include/astra/Float32ProjectionData3DMemory.h218
-rw-r--r--include/astra/Float32VolumeData2D.h183
-rw-r--r--include/astra/Float32VolumeData3D.h265
-rw-r--r--include/astra/Float32VolumeData3DMemory.h213
-rw-r--r--include/astra/ForwardProjectionAlgorithm.h225
-rw-r--r--include/astra/Fourier.h127
-rw-r--r--include/astra/Globals.h309
-rw-r--r--include/astra/Logger.h72
-rw-r--r--include/astra/ParallelBeamBlobKernelProjector2D.h232
-rw-r--r--include/astra/ParallelBeamBlobKernelProjector2D.inl212
-rw-r--r--include/astra/ParallelBeamLineKernelProjector2D.h186
-rw-r--r--include/astra/ParallelBeamLineKernelProjector2D.inl731
-rw-r--r--include/astra/ParallelBeamLinearKernelProjector2D.h194
-rw-r--r--include/astra/ParallelBeamLinearKernelProjector2D.inl416
-rw-r--r--include/astra/ParallelBeamStripKernelProjector2D.h191
-rw-r--r--include/astra/ParallelBeamStripKernelProjector2D.inl739
-rw-r--r--include/astra/ParallelProjectionGeometry2D.h153
-rw-r--r--include/astra/ParallelProjectionGeometry3D.h165
-rw-r--r--include/astra/ParallelVecProjectionGeometry3D.h157
-rw-r--r--include/astra/PlatformDepSystemCode.h83
-rw-r--r--include/astra/ProjectionGeometry2D.h373
-rw-r--r--include/astra/ProjectionGeometry3D.h589
-rw-r--r--include/astra/Projector2D.h204
-rw-r--r--include/astra/Projector2DImpl.inl37
-rw-r--r--include/astra/Projector3D.h185
-rw-r--r--include/astra/ProjectorTypelist.h104
-rw-r--r--include/astra/ReconstructionAlgorithm2D.h222
-rw-r--r--include/astra/ReconstructionAlgorithm3D.h223
-rw-r--r--include/astra/SartAlgorithm.h226
-rw-r--r--include/astra/Singleton.h87
-rw-r--r--include/astra/SirtAlgorithm.h217
-rw-r--r--include/astra/SparseMatrix.h144
-rw-r--r--include/astra/SparseMatrixProjectionGeometry2D.h154
-rw-r--r--include/astra/SparseMatrixProjector2D.h210
-rw-r--r--include/astra/SparseMatrixProjector2D.inl90
-rw-r--r--include/astra/TypeList.h236
-rw-r--r--include/astra/Utilities.h131
-rw-r--r--include/astra/Vector3D.h131
-rw-r--r--include/astra/VolumeGeometry2D.h608
-rw-r--r--include/astra/VolumeGeometry3D.h842
-rw-r--r--include/astra/XMLDocument.h101
-rw-r--r--include/astra/XMLNode.h325
-rw-r--r--include/astra/jama_wrapper.h35
-rw-r--r--include/astra/swrap.h41
-rw-r--r--lib/include/rapidxml/rapidxml.hpp2596
-rw-r--r--lib/include/rapidxml/rapidxml_print.hpp424
-rw-r--r--lib/include/tnt/jama_cholesky.h258
-rw-r--r--lib/include/tnt/jama_eig.h1034
-rw-r--r--lib/include/tnt/jama_lu.h323
-rw-r--r--lib/include/tnt/jama_qr.h326
-rw-r--r--lib/include/tnt/jama_svd.h543
-rw-r--r--lib/include/tnt/tnt.h64
-rw-r--r--lib/include/tnt/tnt_array1d.h278
-rw-r--r--lib/include/tnt/tnt_array1d_utils.h230
-rw-r--r--lib/include/tnt/tnt_array2d.h315
-rw-r--r--lib/include/tnt/tnt_array2d_utils.h287
-rw-r--r--lib/include/tnt/tnt_array3d.h296
-rw-r--r--lib/include/tnt/tnt_array3d_utils.h236
-rw-r--r--lib/include/tnt/tnt_cmat.h580
-rw-r--r--lib/include/tnt/tnt_fortran_array1d.h267
-rw-r--r--lib/include/tnt/tnt_fortran_array1d_utils.h242
-rw-r--r--lib/include/tnt/tnt_fortran_array2d.h225
-rw-r--r--lib/include/tnt/tnt_fortran_array2d_utils.h236
-rw-r--r--lib/include/tnt/tnt_fortran_array3d.h223
-rw-r--r--lib/include/tnt/tnt_fortran_array3d_utils.h249
-rw-r--r--lib/include/tnt/tnt_i_refvec.h243
-rw-r--r--lib/include/tnt/tnt_math_utils.h34
-rw-r--r--lib/include/tnt/tnt_sparse_matrix_csr.h103
-rw-r--r--lib/include/tnt/tnt_stopwatch.h95
-rw-r--r--lib/include/tnt/tnt_subscript.h54
-rw-r--r--lib/include/tnt/tnt_vec.h404
-rw-r--r--lib/include/tnt/tnt_version.h39
-rw-r--r--lib/licenses/rapidxml.txt52
-rw-r--r--lib/licenses/tnt.txt14
-rw-r--r--matlab/algorithms/DART/DARTalgorithm.m229
-rw-r--r--matlab/algorithms/DART/IterativeTomography.m455
-rw-r--r--matlab/algorithms/DART/IterativeTomography3D.m433
-rw-r--r--matlab/algorithms/DART/Kernels.m68
-rw-r--r--matlab/algorithms/DART/MaskingDefault.m212
-rw-r--r--matlab/algorithms/DART/MaskingGPU.m94
-rw-r--r--matlab/algorithms/DART/OutputDefault.m173
-rw-r--r--matlab/algorithms/DART/SegmentationDefault.m55
-rw-r--r--matlab/algorithms/DART/SmoothingDefault.m179
-rw-r--r--matlab/algorithms/DART/SmoothingGPU.m119
-rw-r--r--matlab/algorithms/DART/StatisticsDefault.m72
-rw-r--r--matlab/algorithms/DART/TomographyDefault.m73
-rw-r--r--matlab/algorithms/DART/TomographyDefault3D.m73
-rw-r--r--matlab/algorithms/DART/examples/cylinders.pngbin0 -> 3934 bytes
-rw-r--r--matlab/algorithms/DART/examples/example1.m79
-rw-r--r--matlab/algorithms/DART/examples/example2.m80
-rw-r--r--matlab/algorithms/DART/examples/example3.m79
-rw-r--r--matlab/algorithms/DART/examples/phantom3d.matbin0 -> 242654 bytes
-rw-r--r--matlab/mex/astra_mex.cpp121
-rw-r--r--matlab/mex/astra_mex_algorithm_c.cpp348
-rw-r--r--matlab/mex/astra_mex_algorithm_vc08.vcproj593
-rw-r--r--matlab/mex/astra_mex_c.cpp127
-rw-r--r--matlab/mex/astra_mex_data2d_c.cpp667
-rw-r--r--matlab/mex/astra_mex_data2d_vc08.vcproj591
-rw-r--r--matlab/mex/astra_mex_data3d_c.cpp1036
-rw-r--r--matlab/mex/astra_mex_data3d_vc08.vcproj588
-rw-r--r--matlab/mex/astra_mex_matrix_c.cpp437
-rw-r--r--matlab/mex/astra_mex_matrix_vc08.vcproj591
-rw-r--r--matlab/mex/astra_mex_projector3d_c.cpp433
-rw-r--r--matlab/mex/astra_mex_projector3d_vc08.vcproj588
-rw-r--r--matlab/mex/astra_mex_projector_c.cpp510
-rw-r--r--matlab/mex/astra_mex_projector_vc08.vcproj591
-rw-r--r--matlab/mex/astra_mex_vc08.vcproj591
-rw-r--r--matlab/mex/mex.def1
-rw-r--r--matlab/mex/mexHelpFunctions.cpp642
-rw-r--r--matlab/mex/mexHelpFunctions.h76
-rw-r--r--matlab/tools/ROIselectfull.m18
-rw-r--r--matlab/tools/astra_add_noise_to_sino.m47
-rw-r--r--matlab/tools/astra_clear.m19
-rw-r--r--matlab/tools/astra_create_backprojection.m63
-rw-r--r--matlab/tools/astra_create_backprojection3d_cuda.m54
-rw-r--r--matlab/tools/astra_create_backprojection_cuda.m39
-rw-r--r--matlab/tools/astra_create_fbp_reconstruction.m23
-rw-r--r--matlab/tools/astra_create_proj_geom.m204
-rw-r--r--matlab/tools/astra_create_projector.m50
-rw-r--r--matlab/tools/astra_create_reconstruction.m97
-rw-r--r--matlab/tools/astra_create_reconstruction_cuda.m80
-rw-r--r--matlab/tools/astra_create_sino.m63
-rw-r--r--matlab/tools/astra_create_sino3d_cuda.m54
-rw-r--r--matlab/tools/astra_create_sino_cuda.m58
-rw-r--r--matlab/tools/astra_create_sino_gpu.m58
-rw-r--r--matlab/tools/astra_create_sino_sampling.m59
-rw-r--r--matlab/tools/astra_create_vol_geom.m96
-rw-r--r--matlab/tools/astra_data_gui.figbin0 -> 5810 bytes
-rw-r--r--matlab/tools/astra_data_gui.m396
-rw-r--r--matlab/tools/astra_data_op.m11
-rw-r--r--matlab/tools/astra_data_op_mask.m12
-rw-r--r--matlab/tools/astra_downsample_sinogram.m36
-rw-r--r--matlab/tools/astra_geom_2vec.m84
-rw-r--r--matlab/tools/astra_geom_postalignment.m11
-rw-r--r--matlab/tools/astra_geom_size.m28
-rw-r--r--matlab/tools/astra_geom_superresolution.m14
-rw-r--r--matlab/tools/astra_imshow.m10
-rw-r--r--matlab/tools/astra_mex.m24
-rw-r--r--matlab/tools/astra_mex_algorithm.m24
-rw-r--r--matlab/tools/astra_mex_data2d.m24
-rw-r--r--matlab/tools/astra_mex_data3d.m24
-rw-r--r--matlab/tools/astra_mex_matrix.m24
-rw-r--r--matlab/tools/astra_mex_projector.m24
-rw-r--r--matlab/tools/astra_mex_projector3d.m24
-rw-r--r--matlab/tools/astra_projector_handle.m29
-rw-r--r--matlab/tools/astra_set_directory.m27
-rw-r--r--matlab/tools/astra_struct.m37
-rw-r--r--matlab/tools/compute_rnmp.m29
-rw-r--r--matlab/tools/createOrderART.m66
-rw-r--r--matlab/tools/downsample_sinogram.m12
-rw-r--r--matlab/tools/imreadgs.m26
-rw-r--r--matlab/tools/imresize3D.m26
-rw-r--r--matlab/tools/imscale.m28
-rw-r--r--matlab/tools/imwritesc.m22
-rw-r--r--matlab/tools/kaiserBessel.m31
-rw-r--r--matlab/tools/linspace2.m25
-rw-r--r--matlab/tools/overlayImage.m24
-rw-r--r--matlab/tools/rebin_fan2par.m82
-rw-r--r--matlab/tools/sliceExtractor.m34
-rw-r--r--samples/s001_sinogram_par2d.m33
-rw-r--r--samples/s002_data2d.m60
-rw-r--r--samples/s003_gpu_reconstruction.m52
-rw-r--r--samples/s004_cpu_reconstruction.m60
-rw-r--r--samples/s005_3d_geometry.m98
-rw-r--r--samples/s006_3d_data.m62
-rw-r--r--samples/s007_3d_reconstruction.m53
-rw-r--r--samples/s008_gpu_selection.m37
-rw-r--r--samples/s009_projection_matrix.m45
-rw-r--r--samples/s010_supersampling.m58
-rw-r--r--samples/s011_object_info.m36
-rw-r--r--samples/s012_masks.m60
-rw-r--r--samples/s013_constraints.m47
-rw-r--r--samples/s014_FBP.m47
-rw-r--r--samples/s015_fp_bp.m62
-rw-r--r--samples/s016_plots.m54
-rw-r--r--src/Algorithm.cpp64
-rw-r--r--src/ArtAlgorithm.cpp331
-rw-r--r--src/AstraObjectFactory.cpp39
-rw-r--r--src/AstraObjectManager.cpp43
-rw-r--r--src/AsyncAlgorithm.cpp195
-rw-r--r--src/BackProjectionAlgorithm.cpp192
-rw-r--r--src/CglsAlgorithm.cpp297
-rw-r--r--src/ConeProjectionGeometry3D.cpp228
-rw-r--r--src/ConeVecProjectionGeometry3D.cpp232
-rw-r--r--src/Config.cpp166
-rw-r--r--src/ConvexHullAlgorithm.cpp239
-rw-r--r--src/CudaBackProjectionAlgorithm.cpp96
-rw-r--r--src/CudaBackProjectionAlgorithm3D.cpp222
-rw-r--r--src/CudaCglsAlgorithm.cpp98
-rw-r--r--src/CudaCglsAlgorithm3D.cpp314
-rw-r--r--src/CudaDartMaskAlgorithm.cpp166
-rw-r--r--src/CudaDartMaskAlgorithm3D.cpp168
-rw-r--r--src/CudaDartSmoothingAlgorithm.cpp158
-rw-r--r--src/CudaDartSmoothingAlgorithm3D.cpp160
-rw-r--r--src/CudaDataOperationAlgorithm.cpp208
-rw-r--r--src/CudaEMAlgorithm.cpp97
-rw-r--r--src/CudaFDKAlgorithm3D.cpp192
-rw-r--r--src/CudaFilteredBackProjectionAlgorithm.cpp442
-rw-r--r--src/CudaForwardProjectionAlgorithm.cpp276
-rw-r--r--src/CudaForwardProjectionAlgorithm3D.cpp311
-rw-r--r--src/CudaProjector2D.cpp122
-rw-r--r--src/CudaProjector3D.cpp153
-rw-r--r--src/CudaReconstructionAlgorithm2D.cpp518
-rw-r--r--src/CudaRoiSelectAlgorithm.cpp149
-rw-r--r--src/CudaSartAlgorithm.cpp136
-rw-r--r--src/CudaSirtAlgorithm.cpp154
-rw-r--r--src/CudaSirtAlgorithm3D.cpp306
-rw-r--r--src/DataProjector.cpp36
-rw-r--r--src/DataProjectorPolicies.cpp36
-rw-r--r--src/FanFlatBeamLineKernelProjector2D.cpp179
-rw-r--r--src/FanFlatBeamStripKernelProjector2D.cpp223
-rw-r--r--src/FanFlatProjectionGeometry2D.cpp209
-rw-r--r--src/FanFlatVecProjectionGeometry2D.cpp232
-rw-r--r--src/FilteredBackProjectionAlgorithm.cpp336
-rw-r--r--src/Float32Data.cpp50
-rw-r--r--src/Float32Data2D.cpp523
-rw-r--r--src/Float32Data3D.cpp55
-rw-r--r--src/Float32Data3DMemory.cpp356
-rw-r--r--src/Float32ProjectionData2D.cpp139
-rw-r--r--src/Float32ProjectionData3D.cpp273
-rw-r--r--src/Float32ProjectionData3DMemory.cpp221
-rw-r--r--src/Float32VolumeData2D.cpp135
-rw-r--r--src/Float32VolumeData3D.cpp269
-rw-r--r--src/Float32VolumeData3DMemory.cpp208
-rw-r--r--src/ForwardProjectionAlgorithm.cpp280
-rw-r--r--src/Fourier.cpp233
-rw-r--r--src/Globals.cpp32
-rw-r--r--src/Logger.cpp77
-rw-r--r--src/ParallelBeamBlobKernelProjector2D.cpp271
-rw-r--r--src/ParallelBeamLineKernelProjector2D.cpp222
-rw-r--r--src/ParallelBeamLinearKernelProjector2D.cpp222
-rw-r--r--src/ParallelBeamStripKernelProjector2D.cpp224
-rw-r--r--src/ParallelProjectionGeometry2D.cpp186
-rw-r--r--src/ParallelProjectionGeometry3D.cpp211
-rw-r--r--src/ParallelVecProjectionGeometry3D.cpp230
-rw-r--r--src/PlatformDepSystemCode.cpp76
-rw-r--r--src/ProjectionGeometry2D.cpp203
-rw-r--r--src/ProjectionGeometry3D.cpp329
-rw-r--r--src/Projector2D.cpp217
-rw-r--r--src/Projector3D.cpp121
-rw-r--r--src/ReconstructionAlgorithm2D.cpp275
-rw-r--r--src/ReconstructionAlgorithm3D.cpp306
-rw-r--r--src/ReconstructionAlgorithmMultiSlice2D.cpp288
-rw-r--r--src/SartAlgorithm.cpp452
-rw-r--r--src/SirtAlgorithm.cpp321
-rw-r--r--src/SparseMatrix.cpp91
-rw-r--r--src/SparseMatrixProjectionGeometry2D.cpp203
-rw-r--r--src/SparseMatrixProjector2D.cpp219
-rw-r--r--src/Utilities.cpp128
-rw-r--r--src/Vector3D.cpp29
-rw-r--r--src/VolumeGeometry2D.cpp282
-rw-r--r--src/VolumeGeometry3D.cpp384
-rw-r--r--src/XMLDocument.cpp112
-rw-r--r--src/XMLNode.cpp499
-rw-r--r--src/astra.def6
-rw-r--r--src/swrap.cpp47
-rw-r--r--tests/main.cpp38
-rw-r--r--tests/test_AstraObjectManager.cpp79
-rw-r--r--tests/test_FanFlatProjectionGeometry2D.cpp119
-rw-r--r--tests/test_Float32Data2D.cpp229
-rw-r--r--tests/test_Float32ProjectionData2D.cpp115
-rw-r--r--tests/test_Float32VolumeData2D.cpp110
-rw-r--r--tests/test_Fourier.cpp182
-rw-r--r--tests/test_ParallelBeamLineKernelProjector2D.cpp82
-rw-r--r--tests/test_ParallelBeamLinearKernelProjector2D.cpp172
-rw-r--r--tests/test_ParallelProjectionGeometry2D.cpp120
-rw-r--r--tests/test_VolumeGeometry2D.cpp150
-rw-r--r--tests/test_XMLDocument.cpp158
-rw-r--r--tests/tests_vc08.vcproj699
388 files changed, 89656 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/NEWS.txt b/NEWS.txt
new file mode 100644
index 0000000..d11238f
--- /dev/null
+++ b/NEWS.txt
@@ -0,0 +1,23 @@
+-----------------------------------------------------------------------
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox")
+
+Copyright: iMinds-Vision Lab, University of Antwerp
+License: Open Source under GPLv3
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+ http://code.google.com/p/astra-toolbox/
+-----------------------------------------------------------------------
+
+1.3 (2013-07-02)
+ * various consistency and bug fixes
+ * add a version of the DART algorithm (written by Wim van Aarle)
+
+1.2 (2013-03-01)
+ * various consistency and bug fixes
+
+1.1 (2012-10-24)
+ * add support for matlab single arrays in mex interface
+
+1.0 (2012-08-22)
+ * first public release
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..67a673b
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,100 @@
+-----------------------------------------------------------------------
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox")
+
+Copyright: iMinds-Vision Lab, University of Antwerp
+License: Open Source under GPLv3
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+ http://code.google.com/p/astra-toolbox/
+-----------------------------------------------------------------------
+
+
+The ASTRA Toolbox is a MATLAB toolbox of high-performance GPU primitives
+for 2D and 3D tomography.
+
+We support 2D parallel and fan beam geometries, and 3D parallel and cone beam.
+All of them have highly flexible source/detector positioning.
+
+A large number of 2D and 3D algorithms are available, including FBP, SIRT,
+SART, CGLS.
+
+The basic forward and backward projection operations are GPU-accelerated,
+and directly callable from MATLAB to enable building new algorithms.
+
+
+
+
+Documentation / samples:
+-------------------------
+
+See the matlab code samples in samples/ and on
+http://code.google.com/p/astra-toolbox/ .
+
+
+
+
+
+Installation instructions:
+---------------------------
+
+
+Windows, binary:
+-----------------
+
+Add the mex and tools subdirectories to your matlab path.
+
+
+
+Linux, from source:
+--------------------
+
+Requirements: g++, boost, CUDA (driver+toolkit), matlab
+
+cd build/linux
+./configure --with-cuda=/usr/local/cuda \
+ --with-matlab=/usr/local/MATLAB/R2012a \
+ --prefix=/usr/local/astra
+make
+make install
+Add /usr/local/astra/lib to your LD_LIBRARY_PATH.
+Add /usr/local/astra/matlab and its subdirectories (tools, mex)
+ to your matlab path.
+
+
+NB: Each matlab version only supports a specific range of g++ versions.
+Despite this, if you have a newer g++ and if you get errors related to missing
+GLIBCXX_3.4.xx symbols, it is often possible to work around this requirement
+by deleting the version of libstdc++ supplied by matlab in
+MATLAB_PATH/bin/glnx86 or MATLAB_PATH/bin/glnxa64 (at your own risk).
+
+
+Windows, from source using Visual Studio 2008:
+-----------------------------------------------
+
+Requirements: Visual Studio 2008, boost, CUDA (driver+toolkit), matlab.
+Note that a .zip with all required (and precompiled) boost files is
+ available from our website.
+
+Set the environment variable MATLAB_ROOT to your matlab install location.
+Open astra_vc08.sln in Visual Studio.
+Select the appropriate solution configuration.
+ (typically Release_CUDA|win32 or Release_CUDA|x64)
+Build the solution.
+Install by copying AstraCuda32.dll or AstraCuda64.dll from bin/ and
+ all .mexw32 or .mexw64 files from bin/Release_CUDA or bin/Debug_CUDA
+ and the entire matlab/tools directory to a directory to be added to
+ your matlab path.
+
+
+References:
+------------
+
+If you use parallel beam GPU code for your research, we would appreciate it if
+you would refer to the following paper:
+
+W. J. Palenstijn, K J. Batenburg, and J. Sijbers, "Performance improvements
+for iterative electron tomography reconstruction using graphics processing
+units (GPUs)", Journal of Structural Biology, vol. 176, issue 2, pp. 250-253,
+2011
+
diff --git a/astra_vc08.sln b/astra_vc08.sln
new file mode 100644
index 0000000..60f2e25
--- /dev/null
+++ b/astra_vc08.sln
@@ -0,0 +1,215 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "astra_mex", "astra_mex", "{33EF0AC5-B475-40BF-BAE5-67075B204D10}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_matrix", "matlab\mex\astra_mex_matrix_vc08.vcproj", "{9D041710-2119-4230-BCF2-5FBE753FDE49}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra", "astra_vc08.vcproj", "{12926444-6723-46A8-B388-12E65E0577FA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tests", "tests\tests_vc08.vcproj", "{32C1BDD3-38C2-4C80-A03C-2129782F59B5}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_projector", "matlab\mex\astra_mex_projector_vc08.vcproj", "{4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_projector3d", "matlab\mex\astra_mex_projector3d_vc08.vcproj", "{F94CCD79-AA11-42DF-AC8A-6C9D2238A883}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_data3d", "matlab\mex\astra_mex_data3d_vc08.vcproj", "{0BEC029B-0929-4BF9-BD8B-9C9806A52065}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_data2d", "matlab\mex\astra_mex_data2d_vc08.vcproj", "{E4092269-B19C-46F7-A84E-4F146CC70E44}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex_algorithm", "matlab\mex\astra_mex_algorithm_vc08.vcproj", "{056BF7A9-294D-487C-8CC3-BE629077CA94}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "astra_mex", "matlab\mex\astra_mex_vc08.vcproj", "{3FDA35E0-0D54-4663-A3E6-5ABA96F32221}"
+ ProjectSection(ProjectDependencies) = postProject
+ {12926444-6723-46A8-B388-12E65E0577FA} = {12926444-6723-46A8-B388-12E65E0577FA}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug_CUDA|Win32 = Debug_CUDA|Win32
+ Debug_CUDA|x64 = Debug_CUDA|x64
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release_CUDA|Win32 = Release_CUDA|Win32
+ Release_CUDA|x64 = Release_CUDA|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug|Win32.Build.0 = Debug|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug|x64.ActiveCfg = Debug|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Debug|x64.Build.0 = Debug|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release|Win32.ActiveCfg = Release|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release|Win32.Build.0 = Release|Win32
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release|x64.ActiveCfg = Release|x64
+ {9D041710-2119-4230-BCF2-5FBE753FDE49}.Release|x64.Build.0 = Release|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug|Win32.Build.0 = Debug|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug|x64.ActiveCfg = Debug|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Debug|x64.Build.0 = Debug|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release|Win32.ActiveCfg = Release|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release|Win32.Build.0 = Release|Win32
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release|x64.ActiveCfg = Release|x64
+ {12926444-6723-46A8-B388-12E65E0577FA}.Release|x64.Build.0 = Release|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug|Win32.Build.0 = Debug|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug|x64.ActiveCfg = Debug|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Debug|x64.Build.0 = Debug|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release|Win32.ActiveCfg = Release|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release|Win32.Build.0 = Release|Win32
+ {32C1BDD3-38C2-4C80-A03C-2129782F59B5}.Release|x64.ActiveCfg = Release|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug|Win32.Build.0 = Debug|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug|x64.ActiveCfg = Debug|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Debug|x64.Build.0 = Debug|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release|Win32.ActiveCfg = Release|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release|Win32.Build.0 = Release|Win32
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release|x64.ActiveCfg = Release|x64
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}.Release|x64.Build.0 = Release|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug|Win32.Build.0 = Debug|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug|x64.ActiveCfg = Debug|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Debug|x64.Build.0 = Debug|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release|Win32.ActiveCfg = Release|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release|Win32.Build.0 = Release|Win32
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release|x64.ActiveCfg = Release|x64
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883}.Release|x64.Build.0 = Release|x64
+
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug|Win32.Build.0 = Debug|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug|x64.ActiveCfg = Debug|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Debug|x64.Build.0 = Debug|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release|Win32.ActiveCfg = Release|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release|Win32.Build.0 = Release|Win32
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release|x64.ActiveCfg = Release|x64
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065}.Release|x64.Build.0 = Release|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug|Win32.Build.0 = Debug|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug|x64.ActiveCfg = Debug|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Debug|x64.Build.0 = Debug|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release|Win32.ActiveCfg = Release|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release|Win32.Build.0 = Release|Win32
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release|x64.ActiveCfg = Release|x64
+ {E4092269-B19C-46F7-A84E-4F146CC70E44}.Release|x64.Build.0 = Release|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug|Win32.ActiveCfg = Debug|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug|Win32.Build.0 = Debug|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug|x64.ActiveCfg = Debug|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Debug|x64.Build.0 = Debug|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release|Win32.ActiveCfg = Release|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release|Win32.Build.0 = Release|Win32
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release|x64.ActiveCfg = Release|x64
+ {056BF7A9-294D-487C-8CC3-BE629077CA94}.Release|x64.Build.0 = Release|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug_CUDA|Win32.ActiveCfg = Debug_CUDA|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug_CUDA|Win32.Build.0 = Debug_CUDA|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug_CUDA|x64.ActiveCfg = Debug_CUDA|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug_CUDA|x64.Build.0 = Debug_CUDA|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug|Win32.Build.0 = Debug|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug|x64.ActiveCfg = Debug|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Debug|x64.Build.0 = Debug|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release_CUDA|Win32.ActiveCfg = Release_CUDA|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release_CUDA|Win32.Build.0 = Release_CUDA|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release_CUDA|x64.ActiveCfg = Release_CUDA|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release_CUDA|x64.Build.0 = Release_CUDA|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release|Win32.ActiveCfg = Release|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release|Win32.Build.0 = Release|Win32
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release|x64.ActiveCfg = Release|x64
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9D041710-2119-4230-BCF2-5FBE753FDE49} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {4DD6056F-8EEE-4C9A-B2A9-923F01A32E97} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {F94CCD79-AA11-42DF-AC8A-6C9D2238A883} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {0BEC029B-0929-4BF9-BD8B-9C9806A52065} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {E4092269-B19C-46F7-A84E-4F146CC70E44} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {056BF7A9-294D-487C-8CC3-BE629077CA94} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ {3FDA35E0-0D54-4663-A3E6-5ABA96F32221} = {33EF0AC5-B475-40BF-BAE5-67075B204D10}
+ EndGlobalSection
+EndGlobal
diff --git a/astra_vc08.vcproj b/astra_vc08.vcproj
new file mode 100644
index 0000000..441262f
--- /dev/null
+++ b/astra_vc08.vcproj
@@ -0,0 +1,3146 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="astra"
+ ProjectGUID="{12926444-6723-46A8-B388-12E65E0577FA}"
+ RootNamespace="astra"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ <ToolFile
+ RelativePath=".\build\Cuda.rules"
+ />
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Release"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Platform="1"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="0"
+ EnableIntrinsicFunctions="false"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="false"
+ EnableFiberSafeOptimizations="false"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories="lib\include;include"
+ PreprocessorDefinitions="DLL_EXPORTS"
+ ExceptionHandling="1"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="bin\win32\Astra32.dll"
+ AdditionalLibraryDirectories="&quot;.\lib\win32&quot;"
+ GenerateManifest="true"
+ ModuleDefinitionFile=""
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ Profile="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Release"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Platform="2"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="lib\include;include"
+ PreprocessorDefinitions="DLL_EXPORTS"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="bin\x64\Astra64.dll"
+ AdditionalLibraryDirectories="&quot;.\lib\x64&quot;"
+ GenerateManifest="true"
+ ModuleDefinitionFile=""
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Release_CUDA"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Runtime="2"
+ Platform="1"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="0"
+ EnableIntrinsicFunctions="false"
+ FavorSizeOrSpeed="1"
+ OmitFramePointers="false"
+ EnableFiberSafeOptimizations="false"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories="&quot;$(CUDA_INC_PATH)&quot;;lib\include;lib\include\cuda;include\"
+ PreprocessorDefinitions="ASTRA_CUDA;DLL_EXPORTS"
+ ExceptionHandling="1"
+ RuntimeLibrary="2"
+ CallingConvention="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cudart.lib cufft.lib"
+ OutputFile="bin\win32\AstraCuda32.dll"
+ AdditionalLibraryDirectories="&quot;.\lib\win32&quot;;&quot;$(CUDA_LIB_PATH)&quot;;&quot;$(NVSDKCOMPUTE_ROOT)&quot;/C/common/lib"
+ GenerateManifest="true"
+ ModuleDefinitionFile=""
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ Profile="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Release_CUDA"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Runtime="2"
+ Platform="2"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/MP"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ AdditionalIncludeDirectories="&quot;$(CUDA_INC_PATH)&quot;;lib\include;lib\include\cuda;include\"
+ PreprocessorDefinitions="ASTRA_CUDA;DLL_EXPORTS"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cudart.lib cufft.lib"
+ OutputFile="bin\x64\AstraCuda64.dll"
+ AdditionalLibraryDirectories="&quot;.\lib\x64&quot;;&quot;$(CUDA_LIB_PATH)&quot;;&quot;$(NVSDKCOMPUTE_ROOT)&quot;/C/common/lib"
+ GenerateManifest="true"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile=""
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Debug_CUDA"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Debug="true"
+ Defines="-DDLL_EXPORTS"
+ Optimization="0"
+ Runtime="3"
+ Platform="1"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ InlineFunctionExpansion="0"
+ EnableIntrinsicFunctions="false"
+ FavorSizeOrSpeed="0"
+ OmitFramePointers="false"
+ EnableFiberSafeOptimizations="false"
+ WholeProgramOptimization="false"
+ AdditionalIncludeDirectories="&quot;$(CUDA_INC_PATH)&quot;;lib\include;lib\include\cuda;include\"
+ PreprocessorDefinitions="ASTRA_CUDA;DLL_EXPORTS;_DEBUG"
+ ExceptionHandling="1"
+ RuntimeLibrary="3"
+ DebugInformationFormat="3"
+ CallingConvention="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cufft.lib cudart.lib"
+ OutputFile="bin\win32\AstraCuda32D.dll"
+ AdditionalLibraryDirectories="&quot;.\lib\win32&quot;;&quot;$(CUDA_LIB_PATH)&quot;;&quot;$(NVSDKCOMPUTE_ROOT)&quot;/C/common/lib"
+ GenerateManifest="true"
+ IgnoreAllDefaultLibraries="false"
+ IgnoreDefaultLibraryNames=""
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ AssemblyDebug="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ Profile="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Debug_CUDA"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda;include;lib\include"
+ Debug="true"
+ Defines="-DDLL_EXPORTS"
+ Optimization="0"
+ Runtime="3"
+ Platform="2"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(CUDA_INC_PATH)&quot;;lib\include;lib\include\cuda;include\"
+ PreprocessorDefinitions="ASTRA_CUDA;DLL_EXPORTS;_DEBUG"
+ RuntimeLibrary="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="cudart.lib cufft.lib"
+ OutputFile="bin\x64\AstraCuda64D.dll"
+ AdditionalLibraryDirectories="&quot;.\lib\x64&quot;;&quot;$(CUDA_LIB_PATH)&quot;;&quot;$(NVSDKCOMPUTE_ROOT)&quot;/C/common/lib"
+ GenerateManifest="true"
+ IgnoreAllDefaultLibraries="false"
+ IgnoreDefaultLibraryNames=""
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Debug"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Platform="1"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ FavorSizeOrSpeed="0"
+ AdditionalIncludeDirectories="lib\include;include"
+ PreprocessorDefinitions="_DEBUG;DLL_EXPORTS"
+ RuntimeLibrary="3"
+ DebugInformationFormat="3"
+ EnablePREfast="false"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="bin\win32\Astra32D.dll"
+ AdditionalLibraryDirectories="&quot;.\lib\win32&quot;"
+ GenerateManifest="true"
+ DelayLoadDLLs=""
+ GenerateDebugInformation="true"
+ GenerateMapFile="false"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ Profile="false"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\Debug"
+ IntermediateDirectory="$(OutDir)/obj"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="CUDA Build Rule"
+ Include="lib\include\cuda"
+ Defines="-DDLL_EXPORTS"
+ Platform="2"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="lib\include;include"
+ PreprocessorDefinitions="_DEBUG;DLL_EXPORTS"
+ RuntimeLibrary="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies=""
+ OutputFile="bin\x64\Astra64D.dll"
+ AdditionalLibraryDirectories="&quot;.\lib\x64&quot;"
+ GenerateManifest="true"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\src\astra.def"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Algorithms"
+ >
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\include\astra\Algorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\AlgorithmTypelist.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ArtAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\AsyncAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\BackProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CglsAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FilteredBackProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ForwardProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Fourier.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ReconstructionAlgorithm2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ReconstructionAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SartAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SirtAlgorithm.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\src\Algorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ArtAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\AsyncAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\BackProjectionAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\CglsAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FilteredBackProjectionAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ForwardProjectionAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Fourier.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ReconstructionAlgorithm2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ReconstructionAlgorithm3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SartAlgorithm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SirtAlgorithm.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Projectors"
+ >
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\include\astra\DataProjector.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\DataProjectorPolicies.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatBeamLineKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatBeamStripKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamBlobKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamLinearKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamLineKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamStripKernelProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Projector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Projector3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ProjectorTypelist.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SparseMatrixProjector2D.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\src\DataProjector.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\DataProjectorPolicies.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FanFlatBeamLineKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FanFlatBeamStripKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelBeamBlobKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelBeamLinearKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelBeamLineKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelBeamStripKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Projector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Projector3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SparseMatrixProjector2D.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Inline Files"
+ >
+ <File
+ RelativePath=".\include\astra\DataProjectorPolicies.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatBeamLineKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatBeamStripKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamLinearKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamLineKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelBeamStripKernelProjector2D.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Projector2DImpl.inl"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SparseMatrixProjector2D.inl"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Global &amp; Other"
+ >
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\src\AstraObjectFactory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\AstraObjectManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Config.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Globals.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Logger.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\PlatformDepSystemCode.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Utilities.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\XMLDocument.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\XMLNode.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\include\astra\AstraObjectFactory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\AstraObjectManager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Config.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Globals.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Logger.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\PlatformDepSystemCode.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Singleton.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\TypeList.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\XMLDocument.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\XMLNode.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="CUDA"
+ >
+ <Filter
+ Name="CUDA source"
+ >
+ <File
+ RelativePath=".\cuda\2d\algo.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\algo3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\arith.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\arith3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\astra.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\astra3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\cgls.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cgls3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cone_bp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cone_fp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\darthelper.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\darthelper3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\em.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fan_bp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fan_fp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\fdk.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fft.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\par3d_bp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\par3d_fp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\par_bp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\par_fp.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\sart.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\sirt.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\sirt3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\2d\util.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\cuda\3d\util3d.cu"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="CUDA Build Rule"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="headers"
+ >
+ <File
+ RelativePath=".\cuda\2d\algo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\algo3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\arith.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\arith3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\astra.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\astra3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\cgls.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cgls3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cone_bp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\cone_fp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\darthelper.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\darthelper3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\dims.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\dims3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\em.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fan_bp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fan_fp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fbp_filters.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\fft.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\par3d_bp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\par3d_fp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\par_bp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\par_fp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\sart.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\sirt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\sirt3d.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\2d\util.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cuda\3d\util3d.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="astra code"
+ >
+ <Filter
+ Name="headers"
+ >
+ <File
+ RelativePath=".\include\astra\CudaBackProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaBackProjectionAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaCglsAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaCglsAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaDartMaskAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaDartMaskAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaDartSmoothingAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaDartSmoothingAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaEMAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaFDKAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaFilteredBackProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaForwardProjectionAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaForwardProjectionAlgorithm3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaProjector2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaProjector3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaReconstructionAlgorithm2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaSartAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaSirtAlgorithm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\CudaSirtAlgorithm3D.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="source"
+ >
+ <File
+ RelativePath=".\src\CudaBackProjectionAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaBackProjectionAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaCglsAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaCglsAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDartMaskAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDartMaskAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDartSmoothingAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDartSmoothingAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaDataOperationAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaEMAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaFDKAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaFilteredBackProjectionAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaForwardProjectionAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaForwardProjectionAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaProjector2D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaProjector3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaReconstructionAlgorithm2D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaRoiSelectAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaSartAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaSirtAlgorithm.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\src\CudaSirtAlgorithm3D.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ ExcludedFromBuild="true"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Data &amp; Geometry Objects"
+ >
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\include\astra\ConeProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ConeVecProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\FanFlatVecProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32Data.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32Data2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32Data3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32Data3DMemory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32ProjectionData2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32ProjectionData3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32ProjectionData3DMemory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32VolumeData2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32VolumeData3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Float32VolumeData3DMemory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ParallelVecProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\ProjectionGeometry3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SparseMatrix.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\SparseMatrixProjectionGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\Vector3D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\VolumeGeometry2D.h"
+ >
+ </File>
+ <File
+ RelativePath=".\include\astra\VolumeGeometry3D.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\src\ConeProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ConeVecProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FanFlatProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\FanFlatVecProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32Data.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32Data2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32Data3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32Data3DMemory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32ProjectionData2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32ProjectionData3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32ProjectionData3DMemory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32VolumeData2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32VolumeData3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Float32VolumeData3DMemory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ParallelVecProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\ProjectionGeometry3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SparseMatrix.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\SparseMatrixProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\Vector3D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\VolumeGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\VolumeGeometry3D.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/build/Cuda.rules b/build/Cuda.rules
new file mode 100644
index 0000000..733aa1f
--- /dev/null
+++ b/build/Cuda.rules
@@ -0,0 +1,358 @@
+<?xml version="1.0" encoding="utf-8"?>
+<VisualStudioToolFile
+ Name="CUDA Build Rule v2.1.0"
+ Version="8,00"
+ >
+ <Rules>
+ <CustomBuildRule
+ Name="CUDA Build Rule"
+ DisplayName="CUDA Build Rule v2.1.0"
+ CommandLine="echo [CompilerPath] [Keep] [ExtraNvccOptions] [Platform] [Arch] -ccbin &quot;$(VCInstallDir)bin&quot; [Emulation] [FastMath] [Defines] -Xcompiler &quot;/EHsc [Warning] /nologo [Optimization] /Zi [RuntimeChecks] [Runtime] [TypeInfo] [ExtraCppOptions]&quot; [Include] [MaxRegCount] [PtxAsOptionV] [NvccCompilation] &quot;$(InputPath)&quot; &#x0D;&#x0A; [CompilerPath] [Keep] [ExtraNvccOptions] [Platform] [Arch] -ccbin &quot;$(VCInstallDir)bin&quot; [Emulation] [FastMath] [Defines] -Xcompiler &quot;/EHsc [Warning] /nologo [Optimization] /Zi [RuntimeChecks] [Runtime] [TypeInfo] [ExtraCppOptions]&quot; [Include] [MaxRegCount] [ptxasoptionv] [NvccCompilation] &quot;$(InputPath)&quot; "
+ Outputs="[compileout]"
+ AdditionalDependencies="[AddedDependencies]"
+ FileExtensions="*.cu"
+ ExecutionDescription="Compiling with CUDA Build Rule..."
+ >
+ <Properties>
+ <StringProperty
+ Name="Include"
+ DisplayName="Additional Include Directories"
+ Description="Specifies one or more directories to add to the include path; use semi-colon delimited list if more than one. (/I[path])"
+ Switch="-I[value]"
+ DefaultValue="&quot;$(CUDA_INC_PATH)&quot;"
+ Delimited="true"
+ Delimiters=";"
+ Inheritable="true"
+ />
+ <BooleanProperty
+ Name="Debug"
+ DisplayName="Generate Debug Information"
+ Description="Specifies whether or not debugging information is generated by the CUDA compiler. (-D_DEBUG)"
+ Switch="-D_DEBUG"
+ />
+ <EnumProperty
+ Name="NvccCompilation"
+ DisplayName="NVCC Compilation Type"
+ Description="Select desired output of NVCC compilation (-c/-compile, -cuda, -gpu, -cubin, -ptx)"
+ >
+ <Values>
+ <EnumValue
+ Value="0"
+ Switch="--compile -o &quot;$(IntDir)\$(InputName).cu.obj&quot;"
+ DisplayName="Generate hybrid object file (--compile / -c)"
+ />
+ <EnumValue
+ Value="1"
+ Switch="-cuda -o &quot;$(IntDir)\$(InputName).cu.c&quot;"
+ DisplayName="Generate hybrid .c file (-cuda)"
+ />
+ <EnumValue
+ Value="2"
+ Switch="-gpu -o &quot;$(IntDir)\$(InputName).gpu&quot;"
+ DisplayName="Generate .gpu file (-gpu)"
+ />
+ <EnumValue
+ Value="3"
+ Switch="-m32 -cubin -o &quot;data\$(InputName).cubin&quot;"
+ DisplayName="Generate .cubin file (-cubin)"
+ />
+ <EnumValue
+ Value="4"
+ Switch="-ptx -o &quot;$(IntDir)\$(InputName).ptx&quot;"
+ DisplayName="Generate .ptx file (-ptx)"
+ />
+ </Values>
+ </EnumProperty>
+ <EnumProperty
+ Name="compileout"
+ DisplayName="Compiler Output (obj/cubin)"
+ Description="Sets output as an OBJ or cubin file"
+ >
+ <Values>
+ <EnumValue
+ Value="0"
+ Switch="&quot;$(IntDir)/$(InputName).cu.obj&quot;"
+ DisplayName="&quot;$(IntDir)/$(InputName).cu.obj&quot;"
+ />
+ <EnumValue
+ Value="1"
+ Switch="&quot;data/$(InputName).cubin&quot;"
+ DisplayName="&quot;data/$(InputName).cubin&quot;"
+ />
+ </Values>
+ </EnumProperty>
+ <EnumProperty
+ Name="Arch"
+ DisplayName="GPU Architecture"
+ Description="Select option for the GPU architecture to use on the command line (-arch sm_10, sm_11, sm_12, sm_13)"
+ DefaultValue="10"
+ >
+ <Values>
+ <EnumValue
+ Value="10"
+ Switch="-arch sm_10"
+ DisplayName="sm_10"
+ />
+ <EnumValue
+ Value="11"
+ Switch="-arch sm_11"
+ DisplayName="sm_11"
+ />
+ <EnumValue
+ Value="12"
+ Switch="-arch sm_12"
+ DisplayName="sm_12"
+ />
+ <EnumValue
+ Value="13"
+ Switch="-arch sm_13"
+ DisplayName="sm_13"
+ />
+ </Values>
+ </EnumProperty>
+ <EnumProperty
+ Name="CompilerPath"
+ DisplayName="Path to nvcc.exe"
+ Description="Specifies the path to the CUDA compiler, nvcc.exe "
+ >
+ <Values>
+ <EnumValue
+ Value="0"
+ Switch="&quot;$(CUDA_BIN_PATH)\nvcc.exe&quot;"
+ DisplayName="Installed Toolkit (uses CUDA_BIN_PATH environment varible)"
+ />
+ <EnumValue
+ Value="1"
+ Switch="&quot;[AlternateNvccPath]&quot;"
+ DisplayName="Use Alternate path to CUDA, specified below"
+ />
+ </Values>
+ </EnumProperty>
+ <StringProperty
+ Name="AlternateNvccPath"
+ DisplayName="Alternate path to nvcc.exe (non-standard installation)"
+ Switch="[value]\nvcc.exe"
+ />
+ <BooleanProperty
+ Name="Emulation"
+ DisplayName="Emulation Mode"
+ Description="Whether or not to generate emulated code."
+ Switch="-deviceemu -D_DEVICEEMU"
+ />
+ <BooleanProperty
+ Name="FastMath"
+ DisplayName="Use Fast Math"
+ Category="Default"
+ Description="Make use of the fast math library."
+ Switch="-use_fast_math"
+ />
+ <IntegerProperty
+ Name="MaxRegCount"
+ DisplayName="maxrregcount"
+ Switch="-maxrregcount=[Value]"
+ DefaultValue="32"
+ />
+ <BooleanProperty
+ Name="PtxAsOptionV"
+ DisplayName="PtxAsOptionV"
+ Switch="--ptxas-options=-v"
+ />
+ <StringProperty
+ Name="ExtraNvccOptions"
+ DisplayName="Extra Options"
+ Description="Supply any additional command line options to NVCC"
+ Switch="[value]"
+ />
+ <StringProperty
+ Name="Defines"
+ DisplayName="Preprocessor Definitions"
+ PropertyPageName="Preprocessor"
+ Description="Specifies one or more preprocessor defines. (-D[macro])"
+ Switch="-D[value]"
+ Delimited="true"
+ Inheritable="true"
+ />
+ <BooleanProperty
+ Name="Keep"
+ DisplayName="Keep preprocessed files (.ptx, .cubin, cudafe1.c, cudafe1.cpp, cudafe1.gpu, etc.)"
+ PropertyPageName="Preprocessor"
+ Description="Specifies that preprocessor files generated by the CUDA compiler are not deleted."
+ Switch="--keep"
+ />
+ <EnumProperty
+ Name="Warning"
+ DisplayName="Warning Level"
+ PropertyPageName="Hybrid CUDA/C++ Options"
+ Description="Select how strict you want the compiler to be about checking for potentially suspect constructs. (/W0 - /W4)"
+ DefaultValue="3"
+ >
+ <Values>
+ <EnumValue
+ Value="0"
+ Switch="/W0"
+ DisplayName="Off: Turn Off All Warnings (/W0)"
+ />
+ <EnumValue
+ Value="1"
+ Switch="/W1"
+ DisplayName="Level 1 (/W1)"
+ />
+ <EnumValue
+ Value="2"
+ Switch="/W2"
+ DisplayName="Level 2 (/W2)"
+ />
+ <EnumValue
+ Value="3"
+ Switch="/W3"
+ DisplayName="Level 3 (/W3)"
+ />
+ <EnumValue
+ Value="4"
+ Switch="/W4"
+ DisplayName="Level 4 (/W4)"
+ />
+ </Values>
+ </EnumProperty>
+ <EnumProperty
+ Name="Optimization"
+ DisplayName="Optimization"
+ Description="Select option for code optimization; choose Custom to use specific optimization options. (/Od, /O1, /O2, /Ox)"
+ DefaultValue="2"
+ >
+ <Values>
+ <EnumValue
+ Value="0"
+ Switch="/Od"
+ DisplayName="Disabled (/Od)"
+ />
+ <EnumValue
+ Value="1"
+ Switch="/O1"
+ DisplayName="Minimize Size (/O1)"
+ />
+ <EnumValue
+ Value="2"
+ Switch="/O2"
+ DisplayName="Maximize Speed (/O2)"
+ />
+ <EnumValue
+ Value="3"
+ Switch="/Ox"
+ DisplayName="Full Optimization (/Ox)"
+ />
+ </Values>
+ </EnumProperty>
+ <StringProperty
+ Name="AddedDependencies"
+ DisplayName="Source Dependencies"
+ Description="Add additional CUDA file dependencies"
+ Switch="[value]"
+ />
+ <EnumProperty
+ Name="RuntimeChecks"
+ DisplayName="Basic Runtime Checks"
+ PropertyPageName="Hybrid CUDA/C++ Options"
+ Description="Perform basic runtime error checks, incompatible with any optimization type other than debug. (/RTCs, /RTCu, /RTC1)"
+ >
+ <Values>
+ <EnumValue
+ Value="0"
+ Switch=" "
+ DisplayName="Default"
+ />
+ <EnumValue
+ Value="1"
+ Switch="/RTCs"
+ DisplayName="Stack Frames (/RTCs)"
+ />
+ <EnumValue
+ Value="2"
+ Switch="/RTCu"
+ DisplayName="Uninitialized Variables (/RTCu)"
+ />
+ <EnumValue
+ Value="3"
+ Switch="/RTC1"
+ DisplayName="Both (/RTC1, equiv. to /RTCsu)"
+ />
+ </Values>
+ </EnumProperty>
+ <EnumProperty
+ Name="Runtime"
+ DisplayName="Runtime Library"
+ PropertyPageName="Hybrid CUDA/C++ Options"
+ Description="Specify runtime library for linking. (/MT, /MTd, /MD, /MDd, /ML, /MLd)"
+ >
+ <Values>
+ <EnumValue
+ Value="0"
+ Switch="/MT"
+ DisplayName="Multi-Threaded (/MT)"
+ />
+ <EnumValue
+ Value="1"
+ Switch="/MTd"
+ DisplayName="Multi-Threaded Debug (/MTd)"
+ />
+ <EnumValue
+ Value="2"
+ Switch="/MD"
+ DisplayName="Multi-Threaded DLL (/MD)"
+ />
+ <EnumValue
+ Value="3"
+ Switch="/MDd"
+ DisplayName="Multi-Threaded Debug DLL (/MDd)"
+ />
+ <EnumValue
+ Value="4"
+ Switch="/ML"
+ DisplayName="Single-Threaded (/ML)"
+ />
+ <EnumValue
+ Value="5"
+ Switch="/MLd"
+ DisplayName="Single-Threaded Debug (/MLd)"
+ />
+ </Values>
+ </EnumProperty>
+ <BooleanProperty
+ Name="TypeInfo"
+ DisplayName="Enable Run-Time Type Info"
+ PropertyPageName="Hybrid CUDA/C++ Options"
+ Description="Adds code for checking C++ object types at run time (runtime type information). (/GR)"
+ Switch="/GR"
+ />
+ <StringProperty
+ Name="ExtraCppOptions"
+ DisplayName="Extra C++ Options"
+ PropertyPageName="Hybrid CUDA/C++ Options"
+ Description="Supply any additional command line options to the host C++ compiler"
+ Switch="[value]"
+ />
+ <EnumProperty
+ Name="Platform"
+ DisplayName="Platform"
+ >
+ <Values>
+ <EnumValue
+ Value="0"
+ DisplayName="Default"
+ />
+ <EnumValue
+ Value="1"
+ Switch="-m32"
+ DisplayName="Win32"
+ />
+ <EnumValue
+ Value="2"
+ Switch="-m64"
+ DisplayName="x64"
+ />
+ </Values>
+ </EnumProperty>
+ </Properties>
+ </CustomBuildRule>
+ </Rules>
+</VisualStudioToolFile>
diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in
new file mode 100644
index 0000000..943e10c
--- /dev/null
+++ b/build/linux/Makefile.in
@@ -0,0 +1,314 @@
+cuda=@HAVECUDA@
+matlab=@HAVEMATLAB@
+
+MATLAB_ROOT=@MATLAB_ROOT@
+
+TARGETS=libastra.la
+
+ifeq ($(matlab),yes)
+TARGETS+=mex
+endif
+
+all: $(TARGETS)
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+
+VPATH=../..
+
+CPPFLAGS=@SAVED_CPPFLAGS@
+CXXFLAGS=@SAVED_CXXFLAGS@
+LDFLAGS=@SAVED_LDFLAGS@
+
+CPPFLAGS+=-I../.. -I../../include -I../../lib/include/rapidxml
+CXXFLAGS+=-g -O3 -Wall -Wshadow
+LIBS=-lpthread -lrt
+LDFLAGS+=-g
+
+ifeq ($(cuda),yes)
+CPPFLAGS += @CPPFLAGS_CUDA@ -DASTRA_CUDA
+NVCCFLAGS = @NVCCFLAGS@ @CPPFLAGS_CUDA@ -I../.. -I../../include -DASTRA_CUDA
+LDFLAGS += @LDFLAGS_CUDA@
+LIBS += -lcudart -lcufft
+NVCC = @NVCC@
+endif
+
+ifeq ($(matlab),yes)
+CPPFLAGS+=-I$(MATLAB_ROOT)/extern/include -DMATLAB_MEX_FILE
+endif
+
+TNT_CPPFLAGS=@TNT_CPPFLAGS@
+BOOST_CPPFLAGS=
+BOOST_LDFLAGS=
+
+
+CPPFLAGS+=$(TNT_CPPFLAGS) $(BOOST_CPPFLAGS)
+LDFLAGS+=$(BOOST_LDFLAGS)
+
+
+MKDIR=mkdir -p
+CXX=g++
+LD=g++
+SHELL=@SHELL@
+
+ifeq ($(matlab),yes)
+MEXFLAGS = -cxx
+MEXLDFLAGS='$$LDFLAGS $(LDFLAGS) -L.libs -lut'
+MEXSUFFIX = @MEXSUFFIX@
+MEX = @MEX@
+endif
+
+LIBDIR=/usr/local/lib
+
+DEPDIR=.deps
+
+BASE_OBJECTS=\
+ src/Algorithm.lo \
+ src/AsyncAlgorithm.lo \
+ src/ReconstructionAlgorithm2D.lo \
+ src/ReconstructionAlgorithm3D.lo \
+ src/ArtAlgorithm.lo \
+ src/AstraObjectFactory.lo \
+ src/AstraObjectManager.lo \
+ src/BackProjectionAlgorithm.lo \
+ src/CglsAlgorithm.lo \
+ src/ConeProjectionGeometry3D.lo \
+ src/ConeVecProjectionGeometry3D.lo \
+ src/Config.lo \
+ src/DataProjector.lo \
+ src/DataProjectorPolicies.lo \
+ src/FanFlatBeamLineKernelProjector2D.lo \
+ src/FanFlatBeamStripKernelProjector2D.lo \
+ src/FanFlatProjectionGeometry2D.lo \
+ src/FanFlatVecProjectionGeometry2D.lo \
+ src/FilteredBackProjectionAlgorithm.lo \
+ src/Float32Data2D.lo \
+ src/Float32Data3D.lo \
+ src/Float32Data3DMemory.lo \
+ src/Float32Data.lo \
+ src/Float32ProjectionData2D.lo \
+ src/Float32ProjectionData3D.lo \
+ src/Float32ProjectionData3DMemory.lo \
+ src/Float32VolumeData2D.lo \
+ src/Float32VolumeData3D.lo \
+ src/Float32VolumeData3DMemory.lo \
+ src/ForwardProjectionAlgorithm.lo \
+ src/Fourier.lo \
+ src/Globals.lo \
+ src/Logger.lo \
+ src/ParallelBeamBlobKernelProjector2D.lo \
+ src/ParallelBeamLinearKernelProjector2D.lo \
+ src/ParallelBeamLineKernelProjector2D.lo \
+ src/ParallelBeamStripKernelProjector2D.lo \
+ src/ParallelProjectionGeometry2D.lo \
+ src/ParallelProjectionGeometry3D.lo \
+ src/ParallelVecProjectionGeometry3D.lo \
+ src/PlatformDepSystemCode.lo \
+ src/ProjectionGeometry2D.lo \
+ src/ProjectionGeometry3D.lo \
+ src/Projector2D.lo \
+ src/Projector3D.lo \
+ src/SartAlgorithm.lo \
+ src/SirtAlgorithm.lo \
+ src/SparseMatrixProjectionGeometry2D.lo \
+ src/SparseMatrixProjector2D.lo \
+ src/SparseMatrix.lo \
+ src/Utilities.lo \
+ src/VolumeGeometry2D.lo \
+ src/VolumeGeometry3D.lo \
+ src/XMLDocument.lo \
+ src/XMLNode.lo \
+ src/swrap.lo
+
+CUDA_CXX_OBJECTS=\
+ src/CudaProjector2D.lo \
+ src/CudaProjector3D.lo \
+ src/CudaReconstructionAlgorithm2D.lo \
+ src/CudaBackProjectionAlgorithm.lo \
+ src/CudaDartMaskAlgorithm.lo \
+ src/CudaDartMaskAlgorithm3D.lo \
+ src/CudaDataOperationAlgorithm.lo \
+ src/CudaRoiSelectAlgorithm.lo \
+ src/CudaDartSmoothingAlgorithm.lo \
+ src/CudaDartSmoothingAlgorithm3D.lo \
+ src/CudaFilteredBackProjectionAlgorithm.lo \
+ src/CudaForwardProjectionAlgorithm.lo \
+ src/CudaSartAlgorithm.lo \
+ src/CudaSirtAlgorithm.lo \
+ src/CudaCglsAlgorithm.lo \
+ src/CudaCglsAlgorithm3D.lo \
+ src/CudaEMAlgorithm.lo \
+ src/CudaFDKAlgorithm3D.lo \
+ src/CudaSirtAlgorithm3D.lo \
+ src/CudaBackProjectionAlgorithm3D.lo \
+ src/CudaForwardProjectionAlgorithm3D.lo
+
+CUDA_OBJECTS=\
+ cuda/2d/algo.lo \
+ cuda/2d/par_fp.lo \
+ cuda/2d/par_bp.lo \
+ cuda/2d/fan_fp.lo \
+ cuda/2d/fan_bp.lo \
+ cuda/2d/sirt.lo \
+ cuda/2d/sart.lo \
+ cuda/2d/cgls.lo \
+ cuda/2d/em.lo \
+ cuda/2d/astra.lo \
+ cuda/2d/util.lo \
+ cuda/2d/arith.lo \
+ cuda/2d/fft.lo \
+ cuda/2d/darthelper.lo \
+ cuda/3d/darthelper3d.lo \
+ cuda/3d/algo3d.lo \
+ cuda/3d/cgls3d.lo \
+ cuda/3d/cone_fp.lo \
+ cuda/3d/cone_bp.lo \
+ cuda/3d/fdk.lo \
+ cuda/3d/par3d_fp.lo \
+ cuda/3d/par3d_bp.lo \
+ cuda/3d/sirt3d.lo \
+ cuda/3d/astra3d.lo \
+ cuda/3d/util3d.lo \
+ cuda/3d/arith3d.lo
+
+ALL_OBJECTS=$(BASE_OBJECTS)
+ifeq ($(cuda),yes)
+ALL_OBJECTS+=$(CUDA_CXX_OBJECTS) $(CUDA_OBJECTS)
+endif
+
+TEST_OBJECTS=\
+ tests/main.o \
+ tests/test_AstraObjectManager.o \
+ tests/test_ParallelBeamLineKernelProjector2D.o \
+ tests/test_ParallelBeamLinearKernelProjector2D.o \
+ tests/test_Float32Data2D.o \
+ tests/test_VolumeGeometry2D.o \
+ tests/test_ParallelProjectionGeometry2D.o \
+ tests/test_FanFlatProjectionGeometry2D.o \
+ tests/test_Float32VolumeData2D.o \
+ tests/test_Float32ProjectionData2D.o \
+ tests/test_Fourier.o \
+ tests/test_XMLDocument.o
+
+MATLAB_CXX_OBJECTS=\
+ matlab/mex/mexHelpFunctions.o
+
+MATLAB_MEX=\
+ matlab/mex/astra_mex_algorithm_c.$(MEXSUFFIX) \
+ matlab/mex/astra_mex_data2d_c.$(MEXSUFFIX) \
+ matlab/mex/astra_mex_c.$(MEXSUFFIX) \
+ matlab/mex/astra_mex_matrix_c.$(MEXSUFFIX) \
+ matlab/mex/astra_mex_projector_c.$(MEXSUFFIX) \
+ matlab/mex/astra_mex_projector3d_c.$(MEXSUFFIX) \
+ matlab/mex/astra_mex_data3d_c.$(MEXSUFFIX)
+
+
+OBJECT_DIRS = src/ tests/ cuda/2d/ cuda/3d/ matlab/mex/ ./
+DEPDIRS = $(addsuffix $(DEPDIR),$(OBJECT_DIRS))
+-include $(wildcard $(addsuffix /*.d,$(DEPDIRS)))
+LIBDIRS = $(addsuffix .libs,./ src/ cuda/2d/old/ cuda/2d)
+
+
+ifeq ($(matlab),yes)
+mex: $(MATLAB_MEX)
+
+%.$(MEXSUFFIX): %.o $(MATLAB_CXX_OBJECTS) libastra.la
+ $(MEX) LDFLAGS=$(MEXLDFLAGS) $(MEXFLAGS) $(LIBS) -lastra -output $* $*.o $(MATLAB_CXX_OBJECTS)
+endif
+
+libastra.la: $(ALL_OBJECTS)
+ ./libtool --mode=link --tag=CXX $(LD) -rpath $(LIBDIR) -o $@ $(LDFLAGS) $(LIBS) $+
+
+%.o: %.cpp
+ $(MKDIR) $(*D)/$(DEPDIR)
+ $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) -fPIC -DPIC $(CPPFLAGS) -c $(<) -o $*.o
+
+%.lo: %.cpp
+ $(MKDIR) $(*D)/$(DEPDIR)
+ ./libtool --mode=compile --tag=CXX $(CXX) -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o
+
+ifeq ($(cuda),yes)
+%.lo: %.cu
+ @# Behave like libtool: compile both a PIC and a non-PIC object file
+ @$(MKDIR) $(*D)
+ $(NVCC) $(NVCCFLAGS) -c $(<) -o $*.o
+ @$(MKDIR) $(*D)/.libs
+ @$(MKDIR) $(*D)/$(DEPDIR)
+ @$(NVCC) $(NVCCFLAGS) -c $(<) -Xcompiler -fPIC -DPIC -o $(*D)/.libs/$(*F).o >/dev/null 2>&1
+ @# Generate a .d file, and change the target name in it from .o to .lo
+ @$(NVCC) $(NVCCFLAGS) -M $(<) -odir $(*D) -o $(*D)/$(DEPDIR)/$(*F).d2
+ @sed '1s/\.o :/.lo :/' < $(*D)/$(DEPDIR)/$(*F).d2 > $(*D)/$(DEPDIR)/$(*F).d
+ @rm -f $(*D)/$(DEPDIR)/$(*F).d2
+ @# Generate a fake libtool .lo file
+ @echo "# $*.lo - a libtool object file" > $*.lo
+ @echo "# Generated by" `./libtool --version | head -n 1` >> $*.lo
+ @echo "#" >> $*.lo
+ @echo "# Please DO NOT delete this file!" >> $*.lo
+ @echo "# It is necessary for linking the library." >> $*.lo
+ @echo >> $*.lo
+ @echo "# Name of the PIC object." >> $*.lo
+ @echo "pic_object='.libs/$(*F).o'" >> $*.lo
+ @echo >> $*.lo
+ @echo "# Name of the non-PIC object." >> $*.lo
+ @echo "non_pic_object='$(*F).o'" >> $*.lo
+ @# Remove generated .linkinfo file
+ @rm -f $(*F).linkinfo
+endif
+
+test.bin: $(ALL_OBJECTS) $(TEST_OBJECTS)
+ ./libtool --mode=link $(LD) -o $@ $(LDFLAGS) $(LIBS) $+ -lboost_unit_test_framework
+
+test: test.bin
+ ./test.bin
+
+clean:
+ rm -f $(MATLAB_MEX) libastra.la
+ rm -f $(addsuffix /*.lo,$(OBJECT_DIRS))
+ rm -f $(addsuffix /*.o,$(OBJECT_DIRS))
+ rm -f $(addsuffix /*.d,$(DEPDIRS))
+ rm -f $(addsuffix /*,$(LIBDIRS))
+ rm -f $(TEST_OBJECTS) test.bin
+
+distclean: clean
+ rm -f config.guess config.sub ltmain.sh libtool install-sh
+ rm -f config.log config.status
+ rm -f aclocal.m4
+ rm -rf autom4te.cache
+ rm -f configure Makefile
+
+install: install-libraries install-matlab
+
+install-libraries: libastra.la
+ ./install-sh -m 755 -d @libdir@
+ ./libtool --mode=install ./install-sh -m 644 libastra.la @libdir@
+ ./libtool --mode=finish @libdir@
+
+ifeq ($(matlab),yes)
+# TODO: This install location doesn't work well for /usr or /usr/local
+install-matlab: $(MATLAB_MEX)
+ ./install-sh -m 755 -d @prefix@/matlab
+ ./install-sh -m 755 -d @prefix@/matlab/mex
+ ./install-sh -m 755 -d @prefix@/matlab/tools
+ ./install-sh -m 644 $(MATLAB_MEX) @prefix@/matlab/mex
+ ./install-sh -m 644 ../../matlab/tools/*.m @prefix@/matlab/tools
+# TODO: docs
+else
+install-matlab:
+endif
+
+
+Makefile: Makefile.in config.status
+ CONFIG_HEADERS= CONFIG_LINKS= CONFIG_FILES=$@ $(SHELL) ./config.status
+
+config.status: configure
+ @echo "configure script has changed. Re-running it with last parameters"
+ $(SHELL) ./config.status --recheck
+
+configure: configure.ac
+ @echo "configure.ac has been changed. Regenerating configure script"
+ $(SHELL) ./autogen.sh
+
+.PHONY: all mex test clean distclean install install-libraries
+
+# don't remove intermediate files:
+.SECONDARY:
diff --git a/build/linux/README.txt b/build/linux/README.txt
new file mode 100644
index 0000000..9dd7a7a
--- /dev/null
+++ b/build/linux/README.txt
@@ -0,0 +1,20 @@
+Requirements: g++, boost, CUDA (driver+toolkit),
+matlab
+
+cd build/linux
+./configure --with-cuda=/usr/local/cuda \
+ --with-matlab=/usr/local/MATLAB/R2012a \
+ --prefix=/usr/local/astra
+make
+make install
+Add /usr/local/astra/lib to your LD_LIBRARY_PATH.
+Add /usr/local/astra/matlab and its subdirectories (tools, mex)
+ to your matlab path.
+
+
+NB: Each matlab version only supports a specific range of g++ versions.
+Despite this, if you have a newer g++ and if you get errors related to missing
+GLIBCXX_3.4.xx symbols, it is often possible to work around this requirement
+by deleting the version of libstdc++ supplied by matlab in
+MATLAB_PATH/bin/glnx86 or MATLAB_PATH/bin/glnxa64 (at your own risk).
+
diff --git a/build/linux/acinclude.m4 b/build/linux/acinclude.m4
new file mode 100644
index 0000000..5027e85
--- /dev/null
+++ b/build/linux/acinclude.m4
@@ -0,0 +1,74 @@
+AC_DEFUN([ASTRA_CHECK_BOOST_THREAD],[
+BOOST_BACKUP_LIBS="$LIBS"
+LIBS="$LIBS $1"
+AC_LINK_IFELSE([AC_LANG_SOURCE([
+#include <boost/thread.hpp>
+int main()
+{
+ boost::thread t;
+ boost::posix_time::milliseconds m(1);
+ t.timed_join(m);
+ return 0;
+}
+])],[$2],[$3])
+LIBS="$BOOST_BACKUP_LIBS"
+unset BOOST_BACKUP_LIBS
+])
+
+AC_DEFUN([ASTRA_CHECK_BOOST_UNIT_TEST_FRAMEWORK],[
+BOOST_BACKUP_LIBS="$LIBS"
+LIBS="$LIBS $1"
+AC_LINK_IFELSE([AC_LANG_SOURCE([
+#define BOOST_TEST_DYN_LINK
+
+#define BOOST_AUTO_TEST_MAIN
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+])],[$2],[$3])
+LIBS="$BOOST_BACKUP_LIBS"
+unset BOOST_BACKUP_LIBS
+])
+
+dnl ASTRA_CHECK_MEX_SUFFIX(list-of-suffices, variable-to-set)
+AC_DEFUN([ASTRA_CHECK_MEX_SUFFIX],[
+cat >conftest.cc <<_ACEOF
+extern "C" void mexFunction() {
+}
+_ACEOF
+$CXX -fPIC -c -o conftest.o conftest.cc
+$MEX -cxx -output conftest conftest.o
+$2=""
+for suffix in $1; do
+ if test -f "conftest.$suffix"; then
+ $2="$suffix"
+ rm -f "conftest.$suffix"
+ fi
+done
+rm -f conftest.cc conftest.o
+])
+
+dnl ASTRA_CHECK_NVCC(variable-to-set,cppflags-to-set)
+AC_DEFUN([ASTRA_CHECK_NVCC],[
+cat >conftest.cu <<_ACEOF
+#include <iostream>
+int main() {
+ std::cout << "Test" << std::endl;
+ return 0;
+}
+_ACEOF
+$1="yes"
+$NVCC -c -o conftest.o conftest.cu $$2 >conftest.nvcc.out 2>&1 || {
+ $1="no"
+ # Check if hack for gcc 4.4 helps
+ if grep -q __builtin_stdarg_start conftest.nvcc.out; then
+ NVCC_OPT="-Xcompiler -D__builtin_stdarg_start=__builtin_va_start"
+ $NVCC -c -o conftest.o conftest.cu $$2 $NVCC_OPT >/dev/null 2>&1 && {
+ $1="yes"
+ $2="$$2 $NVCC_OPT"
+ }
+ fi
+}
+rm -f conftest.cu conftest.o conftest.nvcc.out
+])
diff --git a/build/linux/autogen.sh b/build/linux/autogen.sh
new file mode 100755
index 0000000..c856793
--- /dev/null
+++ b/build/linux/autogen.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+aclocal
+if test $? -ne 0; then
+ echo "Error running aclocal"
+ exit 1
+fi
+
+autoconf
+if test $? -ne 0; then
+ echo "Error running autoconf"
+ exit 1
+fi
+
+libtoolize --install --force > /dev/null 2>&1
+if test $? -ne 0; then
+ libtoolize --force
+ if test $? -ne 0; then
+ echo "Error running libtoolize"
+ exit 1
+ fi
+fi
+
+if test ! -e config.guess; then
+ ln -s config.guess.dist config.guess
+fi
+
+if test ! -e config.sub; then
+ ln -s config.sub.dist config.sub
+fi
+
+if test ! -e install-sh; then
+ ln -s install-sh.dist install-sh
+fi
+
+echo "Done."
diff --git a/build/linux/config.guess.dist b/build/linux/config.guess.dist
new file mode 100755
index 0000000..dc84c68
--- /dev/null
+++ b/build/linux/config.guess.dist
@@ -0,0 +1,1501 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+# Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[456])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/build/linux/config.sub.dist b/build/linux/config.sub.dist
new file mode 100755
index 0000000..2a55a50
--- /dev/null
+++ b/build/linux/config.sub.dist
@@ -0,0 +1,1705 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+# Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tile*)
+ basic_machine=tile-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/build/linux/configure.ac b/build/linux/configure.ac
new file mode 100644
index 0000000..ad1d36c
--- /dev/null
+++ b/build/linux/configure.ac
@@ -0,0 +1,185 @@
+dnl -----------------------------------------------------------------------
+dnl Copyright 2012 iMinds-Vision Lab, University of Antwerp
+dnl
+dnl Contact: astra@ua.ac.be
+dnl Website: http://astra.ua.ac.be
+dnl
+dnl
+dnl This file is part of the
+dnl All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+dnl
+dnl The ASTRA Toolbox is free software: you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation, either version 3 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl The ASTRA Toolbox is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+dnl
+dnl -----------------------------------------------------------------------
+dnl $Id$
+
+AC_INIT(astra_toolbox, 1.3.0)
+AC_CONFIG_SRCDIR([Makefile.in])
+LT_INIT([disable-static])
+
+SAVED_CPPFLAGS="$CPPFLAGS"
+SAVED_CXXFLAGS="$CXXFLAGS"
+SAVED_LDFLAGS="$LDFLAGS"
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+AC_PROG_MAKE_SET
+
+AC_LANG([C++])
+
+dnl Use iostream to check if the C++ compiler works
+AC_CHECK_HEADER(iostream, , AC_MSG_ERROR([No working c++ compiler found]))
+
+dnl TODO: Use ../../lib/include instead of .../tnt once all other
+dnl libraries have been moved out of SVN
+TNT_CPPFLAGS="-I../../lib/include/tnt -DJAMA_NO_SUBDIR"
+CPPFLAGS="$CPPFLAGS $TNT_CPPFLAGS"
+AC_CHECK_HEADER(tnt.h, HAVETNT=yes, HAVETNT=no)
+AC_CHECK_HEADER(jama_lu.h, HAVEJAMA=yes, HAVEJAMA=no)
+
+if test x$HAVETNT = xno -o x$HAVEJAMA = xno; then
+ AC_MSG_ERROR([tnt or jama not found])
+fi
+AC_SUBST(TNT_CPPFLAGS)
+
+
+
+# boost-unit-test-framework
+
+AC_MSG_CHECKING([for boost-unit-test-framework])
+
+ASTRA_CHECK_BOOST_UNIT_TEST_FRAMEWORK(-lboost_unit_test_framework-mt, BOOSTUTF=yes_mt, BOOSTUTF=no)
+if test x$BOOSTUTF = xno; then
+ ASTRA_CHECK_BOOST_UNIT_TEST_FRAMEWORK(-lboost_unit_test_framework, BOOSTUTF=yes, BOOSTUTF=no)
+ if test x$BOOSTTHREAD = xno; then
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR([No boost-unit-test-framework library found])
+ else
+ AC_MSG_RESULT([yes, libboost_unit_test_framework])
+ LIBS_BOOSTUTF="-lboost_unit_test_framework"
+ fi
+else
+ AC_MSG_RESULT([yes, libboost_unit_test_framework-mt])
+ LIBS_BOOSTUTF="-lboost_unit_test_framework-mt"
+fi
+# TODO: do something with the result
+
+
+# nvcc, cuda
+
+AC_ARG_WITH(cuda, [[ --with-cuda=path path of CUDA SDK (optional)]],,)
+
+NVCC_PATH=$PATH
+if test x"$with_cuda" != x; then
+ NVCC_PATH="$with_cuda/bin:$NVCC_PATH"
+fi
+AC_PATH_PROG([NVCC], [nvcc], [no], [$NVCC_PATH])
+# TODO: do something with the result
+
+HAVECUDA=no
+if test x"$NVCC" != xno; then
+ HAVECUDA=yes
+ BACKUP_CUDA_LDFLAGS="$LDFLAGS"
+ if test x"$with_cuda" != x; then
+ LDFLAGS_CUDA="-L$with_cuda/lib"
+ CPPFLAGS_CUDA="-I$with_cuda/include"
+ LDFLAGS="$LDFLAGS $LDFLAGS_CUDA"
+ fi
+ AC_CHECK_LIB(cudart,cudaMalloc, ,HAVECUDA=no)
+ AC_CHECK_LIB(cufft,cufftPlan1d, ,HAVECUDA=no)
+
+ if test x"$HAVECUDA" = xno; then
+ # try lib64 instead of lib
+
+ HAVECUDA=yes
+ LDFLAGS="$BACKUP_CUDA_LDFLAGS"
+
+ # prevent cached values from being used
+ unset ac_cv_lib_cudart_cudaMalloc
+ unset ac_cv_lib_cufft_cufftPlan1d
+
+ LDFLAGS_CUDA="-L$with_cuda/lib64"
+ LDFLAGS="$LDFLAGS $LDFLAGS_CUDA"
+ AC_CHECK_LIB(cudart,cudaMalloc, ,HAVECUDA=no)
+ AC_CHECK_LIB(cufft,cufftPlan1d, ,HAVECUDA=no)
+ fi
+
+ LDFLAGS="$BACKUP_CUDA_LDFLAGS"
+ unset BACKUP_CUDA_LDFLAGS
+ # TODO: check for cuda headers?
+
+ AC_SUBST(NVCC)
+fi
+
+NVCCFLAGS=""
+AC_MSG_CHECKING([if nvcc works])
+if test x"$HAVECUDA" = xyes; then
+ ASTRA_CHECK_NVCC(HAVECUDA,NVCCFLAGS)
+fi
+AC_MSG_RESULT($HAVECUDA)
+AC_SUBST(HAVECUDA)
+AC_SUBST(LDFLAGS_CUDA)
+AC_SUBST(CPPFLAGS_CUDA)
+AC_SUBST(NVCCFLAGS)
+
+
+# mex, matlab
+
+AC_ARG_WITH(matlab, [[ --with-matlab=path path of Matlab (optional)]],,)
+
+MEX_PATH=$PATH
+HAVEMATLAB=no
+if test x"$with_matlab" != x; then
+ MEX_PATH="$with_matlab/bin:$MEX_PATH"
+ AC_PATH_PROG([MEX], [mex], [no], [$MEX_PATH])
+ if test x"$MEX" != xno; then
+ HAVEMATLAB=yes
+ # TODO: check platform of C compiler is same as mex
+ AC_SUBST(MEX)
+ MATLAB_ROOT="$with_matlab"
+ AC_SUBST(MATLAB_ROOT)
+
+ ASTRA_CHECK_MEX_SUFFIX([mexa64 mexglx mexmaci64 mexmaci],[MEXSUFFIX])
+ if test x$MEXSUFFIX = x; then
+ AC_MSG_FAILURE([Unable to determine matlab mex suffix])
+ HAVEMATLAB=no
+ fi
+ AC_SUBST(MEXSUFFIX)
+ fi
+fi
+
+AC_SUBST(HAVEMATLAB)
+
+
+# TODO:
+
+# Detection of tools:
+# libtool (how?)
+
+# options:
+# debugging/optimization/profiling flags
+
+
+AC_SUBST(SAVED_CPPFLAGS)
+AC_SUBST(SAVED_CXXFLAGS)
+AC_SUBST(SAVED_LDFLAGS)
+
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/build/linux/install-sh.dist b/build/linux/install-sh.dist
new file mode 100755
index 0000000..a5897de
--- /dev/null
+++ b/build/linux/install-sh.dist
@@ -0,0 +1,519 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2006-12-25.00
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ trap '(exit $?); exit' 1 2 13 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dst_arg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ -*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test -z "$d" && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/cuda/2d/algo.cu b/cuda/2d/algo.cu
new file mode 100644
index 0000000..5ae5d08
--- /dev/null
+++ b/cuda/2d/algo.cu
@@ -0,0 +1,356 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cassert>
+
+#include "algo.h"
+#include "par_fp.h"
+#include "fan_fp.h"
+#include "par_bp.h"
+#include "fan_bp.h"
+#include "util.h"
+#include "arith.h"
+
+namespace astraCUDA {
+
+ReconAlgo::ReconAlgo()
+{
+ angles = 0;
+ TOffsets = 0;
+ fanProjs = 0;
+ shouldAbort = false;
+
+ useVolumeMask = false;
+ useSinogramMask = false;
+ D_maskData = 0;
+ D_smaskData = 0;
+
+ D_sinoData = 0;
+ D_volumeData = 0;
+
+ useMinConstraint = false;
+ useMaxConstraint = false;
+
+ freeGPUMemory = false;
+}
+
+ReconAlgo::~ReconAlgo()
+{
+ reset();
+}
+
+void ReconAlgo::reset()
+{
+ delete[] angles;
+ delete[] TOffsets;
+ delete[] fanProjs;
+
+ if (freeGPUMemory) {
+ cudaFree(D_maskData);
+ cudaFree(D_smaskData);
+ cudaFree(D_sinoData);
+ cudaFree(D_volumeData);
+ }
+
+ angles = 0;
+ TOffsets = 0;
+ fanProjs = 0;
+ shouldAbort = false;
+
+ useVolumeMask = false;
+ useSinogramMask = false;
+
+ D_maskData = 0;
+ D_smaskData = 0;
+
+ D_sinoData = 0;
+ D_volumeData = 0;
+
+ useMinConstraint = false;
+ useMaxConstraint = false;
+
+ freeGPUMemory = false;
+}
+
+bool ReconAlgo::setGPUIndex(int iGPUIndex)
+{
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+ return true;
+}
+
+bool ReconAlgo::enableVolumeMask()
+{
+ useVolumeMask = true;
+ return true;
+}
+
+bool ReconAlgo::enableSinogramMask()
+{
+ useSinogramMask = true;
+ return true;
+}
+
+
+bool ReconAlgo::setGeometry(const SDimensions& _dims, const float* _angles)
+{
+ dims = _dims;
+
+ angles = new float[dims.iProjAngles];
+
+ memcpy(angles, _angles, sizeof(angles[0]) * dims.iProjAngles);
+
+ delete[] fanProjs;
+ fanProjs = 0;
+
+ return true;
+}
+
+bool ReconAlgo::setFanGeometry(const SDimensions& _dims,
+ const SFanProjection* _projs)
+{
+ dims = _dims;
+ fanProjs = new SFanProjection[dims.iProjAngles];
+
+ memcpy(fanProjs, _projs, sizeof(fanProjs[0]) * dims.iProjAngles);
+
+ delete[] angles;
+ angles = 0;
+
+ return true;
+}
+
+
+bool ReconAlgo::setTOffsets(const float* _TOffsets)
+{
+ // TODO: determine if they're all zero?
+ TOffsets = new float[dims.iProjAngles];
+ memcpy(TOffsets, _TOffsets, sizeof(angles[0]) * dims.iProjAngles);
+
+ return true;
+}
+
+
+
+bool ReconAlgo::setVolumeMask(float* _D_maskData, unsigned int _maskPitch)
+{
+ assert(useVolumeMask);
+
+ D_maskData = _D_maskData;
+ maskPitch = _maskPitch;
+
+ return true;
+}
+
+bool ReconAlgo::setSinogramMask(float* _D_smaskData, unsigned int _smaskPitch)
+{
+ assert(useSinogramMask);
+
+ D_smaskData = _D_smaskData;
+ smaskPitch = _smaskPitch;
+
+ return true;
+}
+
+bool ReconAlgo::setBuffers(float* _D_volumeData, unsigned int _volumePitch,
+ float* _D_projData, unsigned int _projPitch)
+{
+ D_volumeData = _D_volumeData;
+ volumePitch = _volumePitch;
+ D_sinoData = _D_projData;
+ sinoPitch = _projPitch;
+
+ return true;
+}
+
+bool ReconAlgo::setMinConstraint(float fMin)
+{
+ fMinConstraint = fMin;
+ useMinConstraint = true;
+ return true;
+}
+
+bool ReconAlgo::setMaxConstraint(float fMax)
+{
+ fMaxConstraint = fMax;
+ useMaxConstraint = true;
+ return true;
+}
+
+
+
+bool ReconAlgo::allocateBuffers()
+{
+ bool ok;
+ ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ if (!ok)
+ return false;
+
+ ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ D_volumeData = 0;
+ return false;
+ }
+
+ if (useVolumeMask) {
+ ok = allocateVolume(D_maskData, dims.iVolWidth+2, dims.iVolHeight+2, maskPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ D_volumeData = 0;
+ D_sinoData = 0;
+ return false;
+ }
+ }
+
+ if (useSinogramMask) {
+ ok = allocateVolume(D_smaskData, dims.iProjDets+2, dims.iProjAngles, smaskPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ cudaFree(D_maskData);
+ D_volumeData = 0;
+ D_sinoData = 0;
+ D_maskData = 0;
+ return false;
+ }
+ }
+
+ freeGPUMemory = true;
+ return true;
+}
+
+bool ReconAlgo::copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale,
+ const float* pfReconstruction, unsigned int iReconstructionPitch,
+ const float* pfVolMask, unsigned int iVolMaskPitch,
+ const float* pfSinoMask, unsigned int iSinoMaskPitch)
+{
+ if (!pfSinogram)
+ return false;
+ if (!pfReconstruction)
+ return false;
+
+ bool ok = copySinogramToDevice(pfSinogram, iSinogramPitch,
+ dims.iProjDets,
+ dims.iProjAngles,
+ D_sinoData, sinoPitch);
+ if (!ok)
+ return false;
+
+ // rescale sinogram to adjust for pixel size
+ processVol<opMul,SINO>(D_sinoData, fSinogramScale,
+ //1.0f/(fPixelSize*fPixelSize),
+ sinoPitch,
+ dims.iProjDets, dims.iProjAngles);
+
+ ok = copyVolumeToDevice(pfReconstruction, iReconstructionPitch,
+ dims.iVolWidth, dims.iVolHeight,
+ D_volumeData, volumePitch);
+ if (!ok)
+ return false;
+
+
+
+ if (useVolumeMask) {
+ if (!pfVolMask)
+ return false;
+
+ ok = copyVolumeToDevice(pfVolMask, iVolMaskPitch,
+ dims.iVolWidth, dims.iVolHeight,
+ D_maskData, maskPitch);
+ if (!ok)
+ return false;
+ }
+
+ if (useSinogramMask) {
+ if (!pfSinoMask)
+ return false;
+
+ ok = copySinogramToDevice(pfSinoMask, iSinoMaskPitch,
+ dims.iProjDets, dims.iProjAngles,
+ D_smaskData, smaskPitch);
+ if (!ok)
+ return false;
+ }
+
+ return true;
+}
+
+bool ReconAlgo::getReconstruction(float* pfReconstruction,
+ unsigned int iReconstructionPitch) const
+{
+ bool ok = copyVolumeFromDevice(pfReconstruction, iReconstructionPitch,
+ dims.iVolWidth,
+ dims.iVolHeight,
+ D_volumeData, volumePitch);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+
+bool ReconAlgo::callFP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ float outputScale)
+{
+ if (angles) {
+ assert(!fanProjs);
+ return FP(D_volumeData, volumePitch, D_projData, projPitch,
+ dims, angles, TOffsets, outputScale);
+ } else {
+ assert(fanProjs);
+ return FanFP(D_volumeData, volumePitch, D_projData, projPitch,
+ dims, fanProjs, outputScale);
+ }
+}
+
+bool ReconAlgo::callBP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch)
+{
+ if (angles) {
+ assert(!fanProjs);
+ return BP(D_volumeData, volumePitch, D_projData, projPitch,
+ dims, angles, TOffsets);
+ } else {
+ assert(fanProjs);
+ return FanBP(D_volumeData, volumePitch, D_projData, projPitch,
+ dims, fanProjs);
+ }
+
+}
+
+
+
+}
diff --git a/cuda/2d/algo.h b/cuda/2d/algo.h
new file mode 100644
index 0000000..96195a3
--- /dev/null
+++ b/cuda/2d/algo.h
@@ -0,0 +1,155 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_ALGO_H
+#define _CUDA_ALGO_H
+
+#include "util.h"
+
+namespace astraCUDA {
+
+class _AstraExport ReconAlgo {
+public:
+ ReconAlgo();
+ virtual ~ReconAlgo();
+
+ bool setGPUIndex(int iGPUIndex);
+
+ bool setGeometry(const SDimensions& dims, const float* angles);
+ bool setFanGeometry(const SDimensions& dims, const SFanProjection* projs);
+
+ // setTOffsets should (optionally) be called after setGeometry
+ bool setTOffsets(const float* TOffsets);
+
+ void signalAbort() { shouldAbort = true; }
+
+ virtual bool enableVolumeMask();
+ virtual bool enableSinogramMask();
+
+ // init should be called after setting all geometry
+ virtual bool init() = 0;
+
+ // setVolumeMask should be called after init and before iterate,
+ // but only if enableVolumeMask was called before init.
+ // It may be called again after iterate.
+ bool setVolumeMask(float* D_maskData, unsigned int maskPitch);
+
+ // setSinogramMask should be called after init and before iterate,
+ // but only if enableSinogramMask was called before init.
+ // It may be called again after iterate.
+ bool setSinogramMask(float* D_smaskData, unsigned int smaskPitch);
+
+
+ // setBuffers should be called after init and before iterate.
+ // It may be called again after iterate.
+ virtual bool setBuffers(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch);
+
+
+ // instead of calling setBuffers, you can also call allocateBuffers
+ // to let ReconAlgo manage its own GPU memory
+ virtual bool allocateBuffers();
+ virtual bool copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale,
+ const float* pfReconstruction, unsigned int iReconstructionPitch,
+ const float* pfVolMask, unsigned int iVolMaskPitch,
+ const float* pfSinoMask, unsigned int iSinoMaskPitch);
+
+
+
+ // set Min/Max constraints. They may be called at any time, and will affect
+ // any iterate() calls afterwards.
+ virtual bool setMinConstraint(float fMin);
+ virtual bool setMaxConstraint(float fMax);
+
+
+ // iterate should be called after init and setBuffers.
+ // It may be called multiple times.
+ virtual bool iterate(unsigned int iterations) = 0;
+
+ // Compute the norm of the difference of the FP of the current
+ // reconstruction and the sinogram. (This performs one FP.)
+ // It can be called after iterate.
+ virtual float computeDiffNorm() = 0;
+ // TODO: computeDiffNorm shouldn't be virtual, but for it to be
+ // implemented in ReconAlgo, it needs a way to get a suitable
+ // temporary sinogram buffer.
+
+ bool getReconstruction(float* pfReconstruction,
+ unsigned int iReconstructionPitch) const;
+
+
+
+protected:
+ void reset();
+
+ bool callFP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ float outputScale);
+ bool callBP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch);
+
+
+ SDimensions dims;
+ float* angles;
+ float* TOffsets;
+ SFanProjection* fanProjs;
+
+ volatile bool shouldAbort;
+
+ bool freeGPUMemory;
+
+ // Input/output
+ float* D_sinoData;
+ unsigned int sinoPitch;
+
+ float* D_volumeData;
+ unsigned int volumePitch;
+
+ // Masks
+ bool useVolumeMask;
+ bool useSinogramMask;
+
+ float* D_maskData;
+ unsigned int maskPitch;
+ float* D_smaskData;
+ unsigned int smaskPitch;
+
+ // Min/max
+ bool useMinConstraint;
+ bool useMaxConstraint;
+ float fMinConstraint;
+ float fMaxConstraint;
+
+
+};
+
+
+}
+
+#endif
+
diff --git a/cuda/2d/arith.cu b/cuda/2d/arith.cu
new file mode 100644
index 0000000..1ee02ca
--- /dev/null
+++ b/cuda/2d/arith.cu
@@ -0,0 +1,893 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "util.h"
+#include "arith.h"
+#include <cassert>
+
+namespace astraCUDA {
+
+
+struct opAddScaled {
+ __device__ void operator()(float& out, const float in, const float inp) {
+ out += in * inp;
+ }
+};
+struct opScaleAndAdd {
+ __device__ void operator()(float& out, const float in, const float inp) {
+ out = in + out * inp;
+ }
+};
+struct opAddMulScaled {
+ __device__ void operator()(float& out, const float in1, const float in2, const float inp) {
+ out += in1 * in2 * inp;
+ }
+};
+struct opAddMul {
+ __device__ void operator()(float& out, const float in1, const float in2) {
+ out += in1 * in2;
+ }
+};
+struct opAdd {
+ __device__ void operator()(float& out, const float in) {
+ out += in;
+ }
+};
+struct opAdd2 {
+ __device__ void operator()(float& out, const float in1, const float in2) {
+ out += in1 + in2;
+ }
+};
+struct opMul {
+ __device__ void operator()(float& out, const float in) {
+ out *= in;
+ }
+};
+struct opMul2 {
+ __device__ void operator()(float& out, const float in1, const float in2) {
+ out *= in1 * in2;
+ }
+};
+struct opDividedBy {
+ __device__ void operator()(float& out, const float in) {
+ if (out > 0.000001f) // out is assumed to be positive
+ out = in / out;
+ else
+ out = 0.0f;
+ }
+};
+struct opInvert {
+ __device__ void operator()(float& out) {
+ if (out > 0.000001f) // out is assumed to be positive
+ out = 1 / out;
+ else
+ out = 0.0f;
+ }
+};
+struct opSet {
+ __device__ void operator()(float& out, const float inp) {
+ out = inp;
+ }
+};
+struct opClampMin {
+ __device__ void operator()(float& out, const float inp) {
+ if (out < inp)
+ out = inp;
+ }
+};
+struct opClampMax {
+ __device__ void operator()(float& out, const float inp) {
+ if (out > inp)
+ out = inp;
+ }
+};
+struct opClampMinMask {
+ __device__ void operator()(float& out, const float in) {
+ if (out < in)
+ out = in;
+ }
+};
+struct opClampMaxMask {
+ __device__ void operator()(float& out, const float in) {
+ if (out > in)
+ out = in;
+ }
+};
+struct opSetMaskedValues {
+ __device__ void operator()(float& out, const float in, const float inp) {
+ if (!in)
+ out = inp;
+ }
+};
+struct opSegmentAndMask {
+ __device__ void operator()(float& out1, float& out2, const float inp1, const float inp2) {
+ if (out1 >= inp1) {
+ out1 = inp2;
+ out2 = 0.0f;
+ }
+
+ }
+
+};
+struct opMulMask {
+ __device__ void operator()(float& out, const float mask, const float in) {
+ if (mask > 0.0f) {
+ out *= in;
+ }
+ }
+};
+
+
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devtoD(float* pfOut, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off]);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devFtoD(float* pfOut, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], fParam);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devFFtoDD(float* pfOut1, float* pfOut2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut1[off], pfOut2[off], fParam1, fParam2);
+ off += pitch;
+ y++;
+ }
+}
+
+
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devDtoD(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], pfIn[off]);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devDFtoD(float* pfOut, const float* pfIn, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], pfIn[off], fParam);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devDDtoD(float* pfOut, const float* pfIn1, const float* pfIn2, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], pfIn1[off], pfIn2[off]);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devDDFtoD(float* pfOut, const float* pfIn1, const float* pfIn2, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], pfIn1[off], pfIn2[off], fParam);
+ off += pitch;
+ y++;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+template<typename op, VolType t>
+void processVolCopy(float* out, unsigned int width, unsigned int height)
+{
+ float* D_out;
+
+ unsigned int pitch;
+ allocateVolume(D_out, width+2, height+2, pitch);
+ copyVolumeToDevice(out, width, width, height, D_out, pitch);
+
+ processVol<op, t>(D_out, pitch, width, height);
+
+ copyVolumeFromDevice(out, width, width, height, D_out, pitch);
+
+ cudaFree(D_out);
+}
+
+template<typename op, VolType t>
+void processVolCopy(float* out, float param, unsigned int width, unsigned int height)
+{
+ float* D_out;
+
+ unsigned int pitch;
+ allocateVolume(D_out, width+2, height+2, pitch);
+ copyVolumeToDevice(out, width, width, height, D_out, pitch);
+
+ processVol<op, t>(D_out, param, pitch, width, height);
+
+ copyVolumeFromDevice(out, width, width, height, D_out, pitch);
+
+ cudaFree(D_out);
+}
+
+template<typename op, VolType t>
+void processVolCopy(float* out1, float* out2, float param1, float param2, unsigned int width, unsigned int height)
+{
+ float* D_out1;
+ float* D_out2;
+
+ unsigned int pitch;
+ allocateVolume(D_out1, width+2, height+2, pitch);
+ copyVolumeToDevice(out1, width, width, height, D_out1, pitch);
+ allocateVolume(D_out2, width+2, height+2, pitch);
+ copyVolumeToDevice(out2, width, width, height, D_out2, pitch);
+
+ processVol<op, t>(D_out1, D_out2, param1, param2, pitch, width, height);
+
+ copyVolumeFromDevice(out1, width, width, height, D_out1, pitch);
+ copyVolumeFromDevice(out2, width, width, height, D_out2, pitch);
+
+ cudaFree(D_out1);
+ cudaFree(D_out2);
+}
+
+
+template<typename op, VolType t>
+void processVolCopy(float* out, const float* in, unsigned int width, unsigned int height)
+{
+ float* D_out;
+ float* D_in;
+
+ unsigned int pitch;
+ allocateVolume(D_out, width+2, height+2, pitch);
+ copyVolumeToDevice(out, width, width, height, D_out, pitch);
+ allocateVolume(D_in, width+2, height+2, pitch);
+ copyVolumeToDevice(in, width, width, height, D_in, pitch);
+
+ processVol<op, t>(D_out, D_in, pitch, width, height);
+
+ copyVolumeFromDevice(out, width, width, height, D_out, pitch);
+
+ cudaFree(D_out);
+ cudaFree(D_in);
+}
+
+template<typename op, VolType t>
+void processVolCopy(float* out, const float* in, float param, unsigned int width, unsigned int height)
+{
+ float* D_out;
+ float* D_in;
+
+ unsigned int pitch;
+ allocateVolume(D_out, width+2, height+2, pitch);
+ copyVolumeToDevice(out, width, width, height, D_out, pitch);
+ allocateVolume(D_in, width+2, height+2, pitch);
+ copyVolumeToDevice(in, width, width, height, D_in, pitch);
+
+ processVol<op, t>(D_out, D_in, param, pitch, width, height);
+
+ copyVolumeFromDevice(out, width, width, height, D_out, pitch);
+
+ cudaFree(D_out);
+ cudaFree(D_in);
+}
+
+template<typename op, VolType t>
+void processVolCopy(float* out, const float* in1, const float* in2, unsigned int width, unsigned int height)
+{
+ float* D_out;
+ float* D_in1;
+ float* D_in2;
+
+ unsigned int pitch;
+ allocateVolume(D_out, width+2, height+2, pitch);
+ copyVolumeToDevice(out, width, width, height, D_out, pitch);
+ allocateVolume(D_in1, width+2, height+2, pitch);
+ copyVolumeToDevice(in1, width, width, height, D_in1, pitch);
+ allocateVolume(D_in2, width+2, height+2, pitch);
+ copyVolumeToDevice(in2, width, width, height, D_in2, pitch);
+
+ processVol<op, t>(D_out, D_in1, D_in2, pitch, width, height);
+
+ copyVolumeFromDevice(out, width, width, height, D_out, pitch);
+
+ cudaFree(D_out);
+ cudaFree(D_in1);
+ cudaFree(D_in2);
+}
+
+template<typename op, VolType t>
+void processVolCopy(float* out, const float* in1, const float* in2, float param, unsigned int width, unsigned int height)
+{
+ float* D_out;
+ float* D_in1;
+ float* D_in2;
+
+ unsigned int pitch;
+ allocateVolume(D_out, width+2, height+2, pitch);
+ copyVolumeToDevice(out, width, width, height, D_out, pitch);
+ allocateVolume(D_in1, width+2, height+2, pitch);
+ copyVolumeToDevice(in1, width, width, height, D_in1, pitch);
+ allocateVolume(D_in2, width+2, height+2, pitch);
+ copyVolumeToDevice(in2, width, width, height, D_in2, pitch);
+
+ processVol<op, t>(D_out, D_in1, D_in2, param, pitch, width, height);
+
+ copyVolumeFromDevice(out, width, width, height, D_out, pitch);
+
+ cudaFree(D_out);
+ cudaFree(D_in1);
+ cudaFree(D_in2);
+}
+
+
+
+
+
+
+
+
+
+template<typename op, VolType t>
+void processVol(float* pfOut, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+511)/512);
+
+ devtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(float* pfOut, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ devFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, fParam, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(float* pfOut1, float* pfOut2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ devFFtoDD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut1, pfOut2, fParam1, fParam2, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+template<typename op, VolType t>
+void processVol(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ devDtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(float* pfOut, const float* pfIn, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ devDFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(float* pfOut, const float* pfIn1, const float* pfIn2, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ devDDFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(float* pfOut, const float* pfIn1, const float* pfIn2, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ devDDtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut1 = (float*)out1.ptr;
+ float *pfOut2 = (float*)out2.ptr;
+ unsigned int step = out1.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devFFtoDD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut1, pfOut2, fParam1, fParam2, out1.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut1 += step;
+ pfOut2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn = (float*)in.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ pfIn += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn = (float*)in.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ pfIn += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn1 = (float*)in1.ptr;
+ float *pfIn2 = (float*)in2.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devDDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ pfIn1 += step;
+ pfIn2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn1 = (float*)in1.ptr;
+ float *pfIn2 = (float*)in2.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devDDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ pfIn1 += step;
+ pfIn2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut1 = (float*)out1.ptr;
+ float *pfOut2 = (float*)out2.ptr;
+ unsigned int step = out1.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devFFtoDD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut1, pfOut2, fParam1, fParam2, out1.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut1 += step;
+ pfOut2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn = (float*)in.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ pfIn += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn = (float*)in.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ pfIn += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn1 = (float*)in1.ptr;
+ float *pfIn2 = (float*)in2.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devDDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ pfIn1 += step;
+ pfIn2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn1 = (float*)in1.ptr;
+ float *pfIn2 = (float*)in2.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devDDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ pfIn1 += step;
+ pfIn2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define INST_DFtoD(name) \
+ template void processVolCopy<name, VOL>(float* out, const float* in, float param, unsigned int width, unsigned int height); \
+ template void processVolCopy<name, SINO>(float* out, const float* in, float param, unsigned int width, unsigned int height); \
+ template void processVol<name, VOL>(float* out, const float* in, float param, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(float* out, const float* in, float param, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims);
+
+#define INST_DtoD(name) \
+ template void processVolCopy<name, VOL>(float* out, const float* in, unsigned int width, unsigned int height); \
+ template void processVolCopy<name, SINO>(float* out, const float* in, unsigned int width, unsigned int height); \
+ template void processVol<name, VOL>(float* out, const float* in, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(float* out, const float* in, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims);
+
+#define INST_DDtoD(name) \
+ template void processVolCopy<name, VOL>(float* out, const float* in1, const float* in2, unsigned int width, unsigned int height); \
+ template void processVolCopy<name, SINO>(float* out, const float* in1, const float* in2, unsigned int width, unsigned int height); \
+ template void processVol<name, VOL>(float* out, const float* in1, const float* in2, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(float* out, const float* in1, const float* in2, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims);
+
+#define INST_DDFtoD(name) \
+ template void processVolCopy<name, VOL>(float* out, const float* in1, const float* in2, float fParam, unsigned int width, unsigned int height); \
+ template void processVolCopy<name, SINO>(float* out, const float* in1, const float* in2, float fParam, unsigned int width, unsigned int height); \
+ template void processVol<name, VOL>(float* out, const float* in1, const float* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(float* out, const float* in1, const float* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims);
+
+
+#define INST_toD(name) \
+ template void processVolCopy<name, VOL>(float* out, unsigned int width, unsigned int height); \
+ template void processVolCopy<name, SINO>(float* out, unsigned int width, unsigned int height); \
+ template void processVol<name, VOL>(float* out, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(float* out, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const SDimensions3D& dims);
+
+#define INST_FtoD(name) \
+ template void processVolCopy<name, VOL>(float* out, float param, unsigned int width, unsigned int height); \
+ template void processVolCopy<name, SINO>(float* out, float param, unsigned int width, unsigned int height); \
+ template void processVol<name, VOL>(float* out, float param, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(float* out, float param, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, float param, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, float param, const SDimensions3D& dims);
+
+#define INST_FFtoDD(name) \
+ template void processVolCopy<name, VOL>(float* out1, float* out2, float fParam1, float fParam2, unsigned int width, unsigned int height); \
+ template void processVolCopy<name, SINO>(float* out1, float* out2, float fParam1, float fParam2, unsigned int width, unsigned int height); \
+ template void processVol<name, VOL>(float* out1, float* out2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(float* out1, float* out2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims);
+
+
+
+INST_DFtoD(opAddScaled)
+INST_DFtoD(opScaleAndAdd)
+INST_DDFtoD(opAddMulScaled)
+INST_DDtoD(opAddMul)
+INST_DDtoD(opMul2)
+INST_DDtoD(opAdd2)
+INST_DtoD(opMul)
+INST_DDtoD(opMulMask)
+INST_DtoD(opAdd)
+INST_DtoD(opDividedBy)
+INST_toD(opInvert)
+INST_FtoD(opSet)
+INST_FtoD(opMul)
+INST_DFtoD(opMulMask)
+INST_FtoD(opAdd)
+INST_FtoD(opClampMin)
+INST_FtoD(opClampMax)
+INST_DtoD(opClampMinMask)
+INST_DtoD(opClampMaxMask)
+
+// PDART-specific:
+INST_DFtoD(opSetMaskedValues)
+INST_FFtoDD(opSegmentAndMask)
+
+}
diff --git a/cuda/2d/arith.h b/cuda/2d/arith.h
new file mode 100644
index 0000000..c8c7b41
--- /dev/null
+++ b/cuda/2d/arith.h
@@ -0,0 +1,101 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_ARITH_H
+#define _CUDA_ARITH_H
+
+#include <cuda.h>
+
+namespace astraCUDA {
+
+
+struct opAddScaled;
+struct opScaleAndAdd;
+struct opAddMulScaled;
+struct opAddMul;
+struct opAdd;
+struct opAdd2;
+struct opMul;
+struct opMul2;
+struct opDividedBy;
+struct opInvert;
+struct opSet;
+struct opClampMin;
+struct opClampMax;
+struct opClampMinMask;
+struct opClampMaxMask;
+struct opSegmentAndMask;
+struct opSetMaskedValues;
+
+struct opMulMask;
+
+
+
+enum VolType {
+ SINO = 0,
+ VOL = 1
+};
+
+
+template<typename op, VolType t> void processVolCopy(float* out, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVolCopy(float* out, float param, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVolCopy(float* out1, float* out2, float param1, float param2, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVolCopy(float* out, const float* in, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVolCopy(float* out, const float* in, float param, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVolCopy(float* out, const float* in1, const float* in2, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVolCopy(float* out, const float* in1, const float* in2, float param, unsigned int width, unsigned int height);
+
+template<typename op, VolType t> void processVol(float* out, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(float* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(float* out1, float* out2, float fParam1, float fParam2, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(float* out, const float* in, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(float* out, const float* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(float* out, const float* in1, const float* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(float* out, const float* in1, const float* in2, unsigned int pitch, unsigned int width, unsigned int height);
+
+template<typename op> void processVol3D(cudaPitchedPtr& out, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims);
+
+template<typename op> void processSino3D(cudaPitchedPtr& out, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out1, cudaPitchedPtr& out2, float fParam1, float fParam2, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims);
+
+
+
+}
+
+#endif
diff --git a/cuda/2d/astra.cu b/cuda/2d/astra.cu
new file mode 100644
index 0000000..71ed025
--- /dev/null
+++ b/cuda/2d/astra.cu
@@ -0,0 +1,824 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+
+#include "util.h"
+#include "par_fp.h"
+#include "fan_fp.h"
+#include "par_bp.h"
+#include "arith.h"
+#include "astra.h"
+
+#include "fft.h"
+
+#include <fstream>
+#include <cuda.h>
+
+#include "../../include/astra/Logger.h"
+
+using namespace astraCUDA;
+using namespace std;
+
+
+namespace astra {
+
+enum CUDAProjectionType {
+ PROJ_PARALLEL,
+ PROJ_FAN
+};
+
+
+class AstraFBP_internal {
+public:
+ SDimensions dims;
+ float* angles;
+ float* TOffsets;
+
+ float fPixelSize;
+
+ bool initialized;
+ bool setStartReconstruction;
+
+ float* D_sinoData;
+ unsigned int sinoPitch;
+
+ float* D_volumeData;
+ unsigned int volumePitch;
+
+ cufftComplex * m_pDevFilter;
+};
+
+AstraFBP::AstraFBP()
+{
+ pData = new AstraFBP_internal();
+
+ pData->angles = 0;
+ pData->D_sinoData = 0;
+ pData->D_volumeData = 0;
+
+ pData->dims.iVolWidth = 0;
+ pData->dims.iProjAngles = 0;
+ pData->dims.fDetScale = 1.0f;
+ pData->dims.iRaysPerDet = 1;
+ pData->dims.iRaysPerPixelDim = 1;
+
+ pData->initialized = false;
+ pData->setStartReconstruction = false;
+
+ pData->m_pDevFilter = NULL;
+}
+
+AstraFBP::~AstraFBP()
+{
+ delete[] pData->angles;
+ pData->angles = 0;
+
+ delete[] pData->TOffsets;
+ pData->TOffsets = 0;
+
+ cudaFree(pData->D_sinoData);
+ pData->D_sinoData = 0;
+
+ cudaFree(pData->D_volumeData);
+ pData->D_volumeData = 0;
+
+ if(pData->m_pDevFilter != NULL)
+ {
+ freeComplexOnDevice(pData->m_pDevFilter);
+ pData->m_pDevFilter = NULL;
+ }
+
+ delete pData;
+ pData = 0;
+}
+
+bool AstraFBP::setReconstructionGeometry(unsigned int iVolWidth,
+ unsigned int iVolHeight,
+ float fPixelSize)
+{
+ if (pData->initialized)
+ return false;
+
+ pData->dims.iVolWidth = iVolWidth;
+ pData->dims.iVolHeight = iVolHeight;
+
+ pData->fPixelSize = fPixelSize;
+
+ return (iVolWidth > 0 && iVolHeight > 0 && fPixelSize > 0.0f);
+}
+
+bool AstraFBP::setProjectionGeometry(unsigned int iProjAngles,
+ unsigned int iProjDets,
+ const float* pfAngles,
+ float fDetSize)
+{
+ if (pData->initialized)
+ return false;
+
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjDets = iProjDets;
+ pData->dims.fDetScale = fDetSize / pData->fPixelSize;
+
+ if (iProjAngles == 0 || iProjDets == 0 || pfAngles == 0)
+ return false;
+
+ pData->angles = new float[iProjAngles];
+ memcpy(pData->angles, pfAngles, iProjAngles * sizeof(pfAngles[0]));
+
+ return true;
+}
+
+bool AstraFBP::setPixelSuperSampling(unsigned int iPixelSuperSampling)
+{
+ if (pData->initialized)
+ return false;
+
+ if (iPixelSuperSampling == 0)
+ return false;
+
+ pData->dims.iRaysPerPixelDim = iPixelSuperSampling;
+
+ return true;
+}
+
+
+bool AstraFBP::setTOffsets(const float* pfTOffsets)
+{
+ if (pData->initialized)
+ return false;
+
+ if (pfTOffsets == 0)
+ return false;
+
+ pData->TOffsets = new float[pData->dims.iProjAngles];
+ memcpy(pData->TOffsets, pfTOffsets, pData->dims.iProjAngles * sizeof(pfTOffsets[0]));
+
+ return true;
+}
+
+bool AstraFBP::init(int iGPUIndex)
+{
+ if (pData->initialized)
+ {
+ return false;
+ }
+
+ if (pData->dims.iProjAngles == 0 || pData->dims.iVolWidth == 0)
+ {
+ return false;
+ }
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ {
+ return false;
+ }
+
+ bool ok = allocateVolume(pData->D_volumeData, pData->dims.iVolWidth+2, pData->dims.iVolHeight+2, pData->volumePitch);
+ if (!ok)
+ {
+ return false;
+ }
+
+ ok = allocateVolume(pData->D_sinoData, pData->dims.iProjDets+2, pData->dims.iProjAngles, pData->sinoPitch);
+ if (!ok)
+ {
+ cudaFree(pData->D_volumeData);
+ pData->D_volumeData = 0;
+ return false;
+ }
+
+ pData->initialized = true;
+
+ return true;
+}
+
+bool AstraFBP::setSinogram(const float* pfSinogram,
+ unsigned int iSinogramPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pfSinogram)
+ return false;
+
+ bool ok = copySinogramToDevice(pfSinogram, iSinogramPitch,
+ pData->dims.iProjDets,
+ pData->dims.iProjAngles,
+ pData->D_sinoData, pData->sinoPitch);
+ if (!ok)
+ return false;
+
+ // rescale sinogram to adjust for pixel size
+ processVol<opMul,SINO>(pData->D_sinoData,
+ 1.0f/(pData->fPixelSize*pData->fPixelSize),
+ pData->sinoPitch,
+ pData->dims.iProjDets, pData->dims.iProjAngles);
+
+ pData->setStartReconstruction = false;
+
+ return true;
+}
+
+static int calcNextPowerOfTwo(int _iValue)
+{
+ int iOutput = 1;
+
+ while(iOutput < _iValue)
+ {
+ iOutput *= 2;
+ }
+
+ return iOutput;
+}
+
+bool AstraFBP::run()
+{
+ if (!pData->initialized)
+ {
+ return false;
+ }
+
+ zeroVolume(pData->D_volumeData, pData->volumePitch, pData->dims.iVolWidth+2, pData->dims.iVolHeight+2);
+
+ bool ok = false;
+
+ if (pData->m_pDevFilter) {
+
+ int iFFTRealDetCount = calcNextPowerOfTwo(2 * pData->dims.iProjDets);
+ int iFFTFourDetCount = calcFFTFourSize(iFFTRealDetCount);
+
+ cufftComplex * pDevComplexSinogram = NULL;
+
+ allocateComplexOnDevice(pData->dims.iProjAngles, iFFTFourDetCount, &pDevComplexSinogram);
+
+ runCudaFFT(pData->dims.iProjAngles, pData->D_sinoData, pData->sinoPitch, 1, pData->dims.iProjDets, iFFTRealDetCount, iFFTFourDetCount, pDevComplexSinogram);
+
+ applyFilter(pData->dims.iProjAngles, iFFTFourDetCount, pDevComplexSinogram, pData->m_pDevFilter);
+
+ runCudaIFFT(pData->dims.iProjAngles, pDevComplexSinogram, pData->D_sinoData, pData->sinoPitch, 1, pData->dims.iProjDets, iFFTRealDetCount, iFFTFourDetCount);
+
+ freeComplexOnDevice(pDevComplexSinogram);
+
+ }
+
+ ok = BP(pData->D_volumeData, pData->volumePitch, pData->D_sinoData, pData->sinoPitch, pData->dims, pData->angles, pData->TOffsets);
+ if(!ok)
+ {
+ return false;
+ }
+
+ processVol<opMul,VOL>(pData->D_volumeData,
+ (M_PI / 2.0f) / (float)pData->dims.iProjAngles,
+ pData->volumePitch,
+ pData->dims.iVolWidth, pData->dims.iVolHeight);
+
+ return true;
+}
+
+bool AstraFBP::getReconstruction(float* pfReconstruction, unsigned int iReconstructionPitch) const
+{
+ if (!pData->initialized)
+ return false;
+
+ bool ok = copyVolumeFromDevice(pfReconstruction, iReconstructionPitch,
+ pData->dims.iVolWidth,
+ pData->dims.iVolHeight,
+ pData->D_volumeData, pData->volumePitch);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+int AstraFBP::calcFourierFilterSize(int _iDetectorCount)
+{
+ int iFFTRealDetCount = calcNextPowerOfTwo(2 * _iDetectorCount);
+ int iFreqBinCount = calcFFTFourSize(iFFTRealDetCount);
+
+ // CHECKME: Matlab makes this at least 64. Do we also need to?
+ return iFreqBinCount;
+}
+
+bool AstraFBP::setFilter(E_FBPFILTER _eFilter, const float * _pfHostFilter /* = NULL */, int _iFilterWidth /* = 0 */, float _fD /* = 1.0f */, float _fFilterParameter /* = -1.0f */)
+{
+ if(pData->m_pDevFilter != 0)
+ {
+ freeComplexOnDevice(pData->m_pDevFilter);
+ pData->m_pDevFilter = 0;
+ }
+
+ if (_eFilter == FILTER_NONE)
+ return true; // leave pData->m_pDevFilter set to 0
+
+
+ int iFFTRealDetCount = calcNextPowerOfTwo(2 * pData->dims.iProjDets);
+ int iFreqBinCount = calcFFTFourSize(iFFTRealDetCount);
+
+ cufftComplex * pHostFilter = new cufftComplex[pData->dims.iProjAngles * iFreqBinCount];
+ memset(pHostFilter, 0, sizeof(cufftComplex) * pData->dims.iProjAngles * iFreqBinCount);
+
+ allocateComplexOnDevice(pData->dims.iProjAngles, iFreqBinCount, &(pData->m_pDevFilter));
+
+ switch(_eFilter)
+ {
+ case FILTER_NONE:
+ // handled above
+ break;
+ case FILTER_RAMLAK:
+ case FILTER_SHEPPLOGAN:
+ case FILTER_COSINE:
+ case FILTER_HAMMING:
+ case FILTER_HANN:
+ case FILTER_TUKEY:
+ case FILTER_LANCZOS:
+ case FILTER_TRIANGULAR:
+ case FILTER_GAUSSIAN:
+ case FILTER_BARTLETTHANN:
+ case FILTER_BLACKMAN:
+ case FILTER_NUTTALL:
+ case FILTER_BLACKMANHARRIS:
+ case FILTER_BLACKMANNUTTALL:
+ case FILTER_FLATTOP:
+ {
+ genFilter(_eFilter, _fD, pData->dims.iProjAngles, pHostFilter, iFFTRealDetCount, iFreqBinCount, _fFilterParameter);
+ uploadComplexArrayToDevice(pData->dims.iProjAngles, iFreqBinCount, pHostFilter, pData->m_pDevFilter);
+
+ break;
+ }
+ case FILTER_PROJECTION:
+ {
+ // make sure the offered filter has the correct size
+ assert(_iFilterWidth == iFreqBinCount);
+
+ for(int iFreqBinIndex = 0; iFreqBinIndex < iFreqBinCount; iFreqBinIndex++)
+ {
+ float fValue = _pfHostFilter[iFreqBinIndex];
+
+ for(int iProjectionIndex = 0; iProjectionIndex < (int)pData->dims.iProjAngles; iProjectionIndex++)
+ {
+ pHostFilter[iFreqBinIndex + iProjectionIndex * iFreqBinCount].x = fValue;
+ pHostFilter[iFreqBinIndex + iProjectionIndex * iFreqBinCount].y = 0.0f;
+ }
+ }
+ uploadComplexArrayToDevice(pData->dims.iProjAngles, iFreqBinCount, pHostFilter, pData->m_pDevFilter);
+ break;
+ }
+ case FILTER_SINOGRAM:
+ {
+ // make sure the offered filter has the correct size
+ assert(_iFilterWidth == iFreqBinCount);
+
+ for(int iFreqBinIndex = 0; iFreqBinIndex < iFreqBinCount; iFreqBinIndex++)
+ {
+ for(int iProjectionIndex = 0; iProjectionIndex < (int)pData->dims.iProjAngles; iProjectionIndex++)
+ {
+ float fValue = _pfHostFilter[iFreqBinIndex + iProjectionIndex * _iFilterWidth];
+
+ pHostFilter[iFreqBinIndex + iProjectionIndex * iFreqBinCount].x = fValue;
+ pHostFilter[iFreqBinIndex + iProjectionIndex * iFreqBinCount].y = 0.0f;
+ }
+ }
+ uploadComplexArrayToDevice(pData->dims.iProjAngles, iFreqBinCount, pHostFilter, pData->m_pDevFilter);
+ break;
+ }
+ case FILTER_RPROJECTION:
+ {
+ int iProjectionCount = pData->dims.iProjAngles;
+ int iRealFilterElementCount = iProjectionCount * iFFTRealDetCount;
+ float * pfHostRealFilter = new float[iRealFilterElementCount];
+ memset(pfHostRealFilter, 0, sizeof(float) * iRealFilterElementCount);
+
+ int iUsedFilterWidth = min(_iFilterWidth, iFFTRealDetCount);
+ int iStartFilterIndex = (_iFilterWidth - iUsedFilterWidth) / 2;
+ int iMaxFilterIndex = iStartFilterIndex + iUsedFilterWidth;
+
+ int iFilterShiftSize = _iFilterWidth / 2;
+
+ for(int iDetectorIndex = iStartFilterIndex; iDetectorIndex < iMaxFilterIndex; iDetectorIndex++)
+ {
+ int iFFTInFilterIndex = (iDetectorIndex + iFFTRealDetCount - iFilterShiftSize) % iFFTRealDetCount;
+ float fValue = _pfHostFilter[iDetectorIndex];
+
+ for(int iProjectionIndex = 0; iProjectionIndex < (int)pData->dims.iProjAngles; iProjectionIndex++)
+ {
+ pfHostRealFilter[iFFTInFilterIndex + iProjectionIndex * iFFTRealDetCount] = fValue;
+ }
+ }
+
+ float* pfDevRealFilter = NULL;
+ cudaMalloc((void **)&pfDevRealFilter, sizeof(float) * iRealFilterElementCount); // TODO: check for errors
+ cudaMemcpy(pfDevRealFilter, pfHostRealFilter, sizeof(float) * iRealFilterElementCount, cudaMemcpyHostToDevice);
+ delete[] pfHostRealFilter;
+
+ runCudaFFT(iProjectionCount, pfDevRealFilter, iFFTRealDetCount, 0, iFFTRealDetCount, iFFTRealDetCount, iFreqBinCount, pData->m_pDevFilter);
+
+ cudaFree(pfDevRealFilter);
+
+ break;
+ }
+ case FILTER_RSINOGRAM:
+ {
+ int iProjectionCount = pData->dims.iProjAngles;
+ int iRealFilterElementCount = iProjectionCount * iFFTRealDetCount;
+ float* pfHostRealFilter = new float[iRealFilterElementCount];
+ memset(pfHostRealFilter, 0, sizeof(float) * iRealFilterElementCount);
+
+ int iUsedFilterWidth = min(_iFilterWidth, iFFTRealDetCount);
+ int iStartFilterIndex = (_iFilterWidth - iUsedFilterWidth) / 2;
+ int iMaxFilterIndex = iStartFilterIndex + iUsedFilterWidth;
+
+ int iFilterShiftSize = _iFilterWidth / 2;
+
+ for(int iDetectorIndex = iStartFilterIndex; iDetectorIndex < iMaxFilterIndex; iDetectorIndex++)
+ {
+ int iFFTInFilterIndex = (iDetectorIndex + iFFTRealDetCount - iFilterShiftSize) % iFFTRealDetCount;
+
+ for(int iProjectionIndex = 0; iProjectionIndex < (int)pData->dims.iProjAngles; iProjectionIndex++)
+ {
+ float fValue = _pfHostFilter[iDetectorIndex + iProjectionIndex * _iFilterWidth];
+ pfHostRealFilter[iFFTInFilterIndex + iProjectionIndex * iFFTRealDetCount] = fValue;
+ }
+ }
+
+ float* pfDevRealFilter = NULL;
+ cudaMalloc((void **)&pfDevRealFilter, sizeof(float) * iRealFilterElementCount); // TODO: check for errors
+ cudaMemcpy(pfDevRealFilter, pfHostRealFilter, sizeof(float) * iRealFilterElementCount, cudaMemcpyHostToDevice);
+ delete[] pfHostRealFilter;
+
+ runCudaFFT(iProjectionCount, pfDevRealFilter, iFFTRealDetCount, 0, iFFTRealDetCount, iFFTRealDetCount, iFreqBinCount, pData->m_pDevFilter);
+
+ cudaFree(pfDevRealFilter);
+
+ break;
+ }
+ default:
+ {
+ fprintf(stderr, "AstraFBP::setFilter: Weird filter type requested");
+ delete [] pHostFilter;
+ return false;
+ }
+ }
+
+ delete [] pHostFilter;
+
+ return true;
+}
+
+BPalgo::BPalgo()
+{
+
+}
+
+BPalgo::~BPalgo()
+{
+
+}
+
+bool BPalgo::init()
+{
+ return true;
+}
+
+bool BPalgo::iterate(unsigned int)
+{
+ // TODO: This zeroVolume makes an earlier memcpy of D_volumeData redundant
+ zeroVolume(D_volumeData, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ callBP(D_volumeData, volumePitch, D_sinoData, sinoPitch);
+ return true;
+}
+
+float BPalgo::computeDiffNorm()
+{
+ float *D_projData;
+ unsigned int projPitch;
+
+ allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch);
+
+ cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice);
+ callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f);
+
+ float s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0);
+
+ cudaFree(D_projData);
+
+ return sqrt(s);
+}
+
+
+bool astraCudaFP(const float* pfVolume, float* pfSinogram,
+ unsigned int iVolWidth, unsigned int iVolHeight,
+ unsigned int iProjAngles, unsigned int iProjDets,
+ const float *pfAngles, const float *pfOffsets,
+ float fDetSize, unsigned int iDetSuperSampling,
+ int iGPUIndex)
+{
+ SDimensions dims;
+
+ if (iProjAngles == 0 || iProjDets == 0 || pfAngles == 0)
+ return false;
+
+ dims.iProjAngles = iProjAngles;
+ dims.iProjDets = iProjDets;
+ dims.fDetScale = fDetSize;
+
+ if (iDetSuperSampling == 0)
+ return false;
+
+ dims.iRaysPerDet = iDetSuperSampling;
+
+ if (iVolWidth <= 0 || iVolHeight <= 0)
+ return false;
+
+ dims.iVolWidth = iVolWidth;
+ dims.iVolHeight = iVolHeight;
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+
+ bool ok;
+
+ float* D_volumeData;
+ unsigned int volumePitch;
+
+ ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ if (!ok)
+ return false;
+
+ float* D_sinoData;
+ unsigned int sinoPitch;
+
+ ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ return false;
+ }
+
+ ok = copyVolumeToDevice(pfVolume, dims.iVolWidth,
+ dims.iVolWidth, dims.iVolHeight,
+ D_volumeData, volumePitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles);
+ ok = FP(D_volumeData, volumePitch, D_sinoData, sinoPitch, dims, pfAngles, pfOffsets, 1.0f);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ ok = copySinogramFromDevice(pfSinogram, dims.iProjDets,
+ dims.iProjDets,
+ dims.iProjAngles,
+ D_sinoData, sinoPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return true;
+}
+
+bool astraCudaFanFP(const float* pfVolume, float* pfSinogram,
+ unsigned int iVolWidth, unsigned int iVolHeight,
+ unsigned int iProjAngles, unsigned int iProjDets,
+ const float *pfAngles, float fOriginSourceDistance,
+ float fOriginDetectorDistance, float fPixelSize,
+ float fDetSize,
+ unsigned int iDetSuperSampling,
+ int iGPUIndex)
+{
+ SDimensions dims;
+
+ if (iProjAngles == 0 || iProjDets == 0 || pfAngles == 0)
+ return false;
+
+ dims.iProjAngles = iProjAngles;
+ dims.iProjDets = iProjDets;
+
+ if (iDetSuperSampling == 0)
+ return false;
+
+ dims.iRaysPerDet = iDetSuperSampling;
+
+ if (iVolWidth <= 0 || iVolHeight <= 0)
+ return false;
+
+ dims.iVolWidth = iVolWidth;
+ dims.iVolHeight = iVolHeight;
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+
+ bool ok;
+
+ float* D_volumeData;
+ unsigned int volumePitch;
+
+ ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ if (!ok)
+ return false;
+
+ float* D_sinoData;
+ unsigned int sinoPitch;
+
+ ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ return false;
+ }
+
+ ok = copyVolumeToDevice(pfVolume, dims.iVolWidth,
+ dims.iVolWidth, dims.iVolHeight,
+ D_volumeData, volumePitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles);
+
+ // TODO: Turn this geometry conversion into a util function
+ SFanProjection* projs = new SFanProjection[dims.iProjAngles];
+
+ float fSrcX0 = 0.0f;
+ float fSrcY0 = -fOriginSourceDistance / fPixelSize;
+ float fDetUX0 = fDetSize / fPixelSize;
+ float fDetUY0 = 0.0f;
+ float fDetSX0 = dims.iProjDets * fDetUX0 / -2.0f;
+ float fDetSY0 = fOriginDetectorDistance / fPixelSize;
+
+#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = f##name##X0 * cos(alpha) - f##name##Y0 * sin(alpha); projs[i].f##name##Y = f##name##X0 * sin(alpha) + f##name##Y0 * cos(alpha); } while(0)
+ for (int i = 0; i < dims.iProjAngles; ++i) {
+ ROTATE0(Src, i, pfAngles[i]);
+ ROTATE0(DetS, i, pfAngles[i]);
+ ROTATE0(DetU, i, pfAngles[i]);
+ }
+
+#undef ROTATE0
+
+ ok = FanFP(D_volumeData, volumePitch, D_sinoData, sinoPitch, dims, projs, 1.0f);
+ delete[] projs;
+
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ ok = copySinogramFromDevice(pfSinogram, dims.iProjDets,
+ dims.iProjDets,
+ dims.iProjAngles,
+ D_sinoData, sinoPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+
+ return true;
+
+}
+
+
+bool astraCudaFanFP(const float* pfVolume, float* pfSinogram,
+ unsigned int iVolWidth, unsigned int iVolHeight,
+ unsigned int iProjAngles, unsigned int iProjDets,
+ const SFanProjection *pAngles,
+ unsigned int iDetSuperSampling,
+ int iGPUIndex)
+{
+ SDimensions dims;
+
+ if (iProjAngles == 0 || iProjDets == 0 || pAngles == 0)
+ return false;
+
+ dims.iProjAngles = iProjAngles;
+ dims.iProjDets = iProjDets;
+ dims.fDetScale = 1.0f; // TODO?
+
+ if (iDetSuperSampling == 0)
+ return false;
+
+ dims.iRaysPerDet = iDetSuperSampling;
+
+ if (iVolWidth <= 0 || iVolHeight <= 0)
+ return false;
+
+ dims.iVolWidth = iVolWidth;
+ dims.iVolHeight = iVolHeight;
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+
+ bool ok;
+
+ float* D_volumeData;
+ unsigned int volumePitch;
+
+ ok = allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ if (!ok)
+ return false;
+
+ float* D_sinoData;
+ unsigned int sinoPitch;
+
+ ok = allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ return false;
+ }
+
+ ok = copyVolumeToDevice(pfVolume, dims.iVolWidth,
+ dims.iVolWidth, dims.iVolHeight,
+ D_volumeData, volumePitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles);
+
+ ok = FanFP(D_volumeData, volumePitch, D_sinoData, sinoPitch, dims, pAngles, 1.0f);
+
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ ok = copySinogramFromDevice(pfSinogram, dims.iProjDets,
+ dims.iProjDets,
+ dims.iProjAngles,
+ D_sinoData, sinoPitch);
+ if (!ok) {
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+ return false;
+ }
+
+ cudaFree(D_volumeData);
+ cudaFree(D_sinoData);
+
+ return true;
+
+}
+
+
+}
diff --git a/cuda/2d/astra.h b/cuda/2d/astra.h
new file mode 100644
index 0000000..9e58301
--- /dev/null
+++ b/cuda/2d/astra.h
@@ -0,0 +1,205 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_ASTRA_H
+#define _CUDA_ASTRA_H
+
+#include "fft.h"
+#include "fbp_filters.h"
+#include "dims.h"
+#include "algo.h"
+
+using astraCUDA::SFanProjection;
+
+namespace astra {
+
+enum Cuda2DProjectionKernel {
+ ker2d_default = 0
+};
+
+class AstraFBP_internal;
+
+class _AstraExport AstraFBP {
+public:
+ // Constructor
+ AstraFBP();
+
+ // Destructor
+ ~AstraFBP();
+
+ // Set the size of the reconstruction rectangle.
+ // Volume pixels are currently assumed to be 1x1 squares.
+ bool setReconstructionGeometry(unsigned int iVolWidth,
+ unsigned int iVolHeight,
+ float fPixelSize = 1.0f);
+
+ // Set the projection angles and number of detector pixels per angle.
+ // pfAngles must be a float array of length iProjAngles.
+ // fDetSize indicates the size of a detector pixel compared to a
+ // volume pixel edge.
+ //
+ // pfAngles will only be read from during this call.
+ bool setProjectionGeometry(unsigned int iProjAngles,
+ unsigned int iProjDets,
+ const float *pfAngles,
+ float fDetSize = 1.0f);
+
+ // Set linear supersampling factor for the BP.
+ // (The number of rays is the square of this)
+ //
+ // This may optionally be called before init().
+ bool setPixelSuperSampling(unsigned int iPixelSuperSampling);
+
+ // Set per-detector shifts.
+ //
+ // pfTOffsets will only be read from during this call.
+ bool setTOffsets(const float *pfTOffsets);
+
+ // Returns the required size of a filter in the fourier domain
+ // when multiplying it with the fft of the projection data.
+ // Its value is equal to the smallest power of two larger than
+ // or equal to twice the number of detectors in the spatial domain.
+ //
+ // _iDetectorCount is the number of detectors in the spatial domain.
+ static int calcFourierFilterSize(int _iDetectorCount);
+
+ // Sets the filter type. Some filter types require the user to supply an
+ // array containing the filter.
+ // The number of elements in a filter in the fourier domain should be equal
+ // to the value returned by calcFourierFilterSize().
+ // The following types require a filter:
+ //
+ // - FILTER_PROJECTION:
+ // The filter size should be equal to the output of
+ // calcFourierFilterSize(). The filtered sinogram is
+ // multiplied with the supplied filter.
+ //
+ // - FILTER_SINOGRAM:
+ // Same as FILTER_PROJECTION, but now the filter should contain a row for
+ // every projection direction.
+ //
+ // - FILTER_RPROJECTION:
+ // The filter should now contain one kernel (= ifft of filter), with the
+ // peak in the center. The filter width
+ // can be any value. If odd, the peak is assumed to be in the center, if
+ // even, it is assumed to be at floor(filter-width/2).
+ //
+ // - FILTER_RSINOGRAM
+ // Same as FILTER_RPROJECTION, but now the supplied filter should contain a
+ // row for every projection direction.
+ //
+ // A large number of other filters (FILTER_RAMLAK, FILTER_SHEPPLOGAN,
+ // FILTER_COSINE, FILTER_HAMMING, and FILTER_HANN)
+ // have a D variable, which gives the cutoff point in the frequency domain.
+ // Setting this value to 1.0 will include the whole filter
+ bool setFilter(E_FBPFILTER _eFilter,
+ const float * _pfHostFilter = NULL,
+ int _iFilterWidth = 0, float _fD = 1.0f, float _fFilterParameter = -1.0f);
+
+ // Initialize CUDA, allocate GPU buffers and
+ // precompute geometry-specific data.
+ //
+ // CUDA is set up to use GPU number iGPUIndex.
+ //
+ // This must be called after calling setReconstructionGeometry() and
+ // setProjectionGeometry().
+ bool init(int iGPUIndex = 0);
+
+ // Setup input sinogram for a slice.
+ // pfSinogram must be a float array of size iProjAngles*iSinogramPitch.
+ // NB: iSinogramPitch is measured in floats, not in bytes.
+ //
+ // This must be called after init(), and before iterate(). It may be
+ // called again after iterate()/getReconstruction() to start a new slice.
+ //
+ // pfSinogram will only be read from during this call.
+ bool setSinogram(const float* pfSinogram, unsigned int iSinogramPitch);
+
+ // Runs an FBP reconstruction.
+ // This must be called after setSinogram().
+ //
+ // run can be called before setFilter, but will then use the default Ram-Lak filter
+ bool run();
+
+ // Get the reconstructed slice.
+ // pfReconstruction must be a float array of size
+ // iVolHeight*iReconstructionPitch.
+ // NB: iReconstructionPitch is measured in floats, not in bytes.
+ //
+ // This may be called after run().
+ bool getReconstruction(float* pfReconstruction,
+ unsigned int iReconstructionPitch) const;
+
+private:
+ AstraFBP_internal* pData;
+};
+
+class _AstraExport BPalgo : public astraCUDA::ReconAlgo {
+public:
+ BPalgo();
+ ~BPalgo();
+
+ virtual bool init();
+
+ virtual bool iterate(unsigned int iterations);
+
+ virtual float computeDiffNorm();
+};
+
+
+
+
+// TODO: Clean up this interface to FP
+
+// Do a single forward projection
+_AstraExport bool astraCudaFP(const float* pfVolume, float* pfSinogram,
+ unsigned int iVolWidth, unsigned int iVolHeight,
+ unsigned int iProjAngles, unsigned int iProjDets,
+ const float *pfAngles, const float *pfOffsets,
+ float fDetSize = 1.0f, unsigned int iDetSuperSampling = 1,
+ int iGPUIndex = 0);
+
+// Do a single forward projection, fan beam
+_AstraExport bool astraCudaFanFP(const float* pfVolume, float* pfSinogram,
+ unsigned int iVolWidth, unsigned int iVolHeight,
+ unsigned int iProjAngles, unsigned int iProjDets,
+ const float *pfAngles, float fOriginSourceDistance,
+ float fOriginDetectorDistance, float fPixelSize = 1.0f,
+ float fDetSize = 1.0f,
+ unsigned int iDetSuperSampling = 1,
+ int iGPUIndex = 0);
+
+_AstraExport bool astraCudaFanFP(const float* pfVolume, float* pfSinogram,
+ unsigned int iVolWidth, unsigned int iVolHeight,
+ unsigned int iProjAngles, unsigned int iProjDets,
+ const SFanProjection *pAngles,
+ unsigned int iDetSuperSampling = 1,
+ int iGPUIndex = 0);
+
+}
+#endif
diff --git a/cuda/2d/cgls.cu b/cuda/2d/cgls.cu
new file mode 100644
index 0000000..5b1cf46
--- /dev/null
+++ b/cuda/2d/cgls.cu
@@ -0,0 +1,304 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+
+#include "cgls.h"
+#include "util.h"
+#include "arith.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+namespace astraCUDA {
+
+CGLS::CGLS() : ReconAlgo()
+{
+ D_z = 0;
+ D_p = 0;
+ D_r = 0;
+ D_w = 0;
+
+ sliceInitialized = false;
+}
+
+
+CGLS::~CGLS()
+{
+ reset();
+}
+
+void CGLS::reset()
+{
+ cudaFree(D_z);
+ cudaFree(D_p);
+ cudaFree(D_r);
+ cudaFree(D_w);
+
+ D_z = 0;
+ D_p = 0;
+ D_r = 0;
+ D_w = 0;
+
+ ReconAlgo::reset();
+}
+
+bool CGLS::init()
+{
+ // Lifetime of z: within an iteration
+ allocateVolume(D_z, dims.iVolWidth+2, dims.iVolHeight+2, zPitch);
+
+ // Lifetime of p: full algorithm
+ allocateVolume(D_p, dims.iVolWidth+2, dims.iVolHeight+2, pPitch);
+
+ // Lifetime of r: full algorithm
+ allocateVolume(D_r, dims.iProjDets+2, dims.iProjAngles, rPitch);
+
+ // Lifetime of w: within an iteration
+ allocateVolume(D_w, dims.iProjDets+2, dims.iProjAngles, wPitch);
+
+ // TODO: check if allocations succeeded
+ return true;
+}
+
+
+bool CGLS::setBuffers(float* _D_volumeData, unsigned int _volumePitch,
+ float* _D_projData, unsigned int _projPitch)
+{
+ bool ok = ReconAlgo::setBuffers(_D_volumeData, _volumePitch,
+ _D_projData, _projPitch);
+
+ if (!ok)
+ return false;
+
+ sliceInitialized = false;
+
+ return true;
+}
+
+bool CGLS::copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale,
+ const float* pfReconstruction, unsigned int iReconstructionPitch,
+ const float* pfVolMask, unsigned int iVolMaskPitch,
+ const float* pfSinoMask, unsigned int iSinoMaskPitch)
+{
+ sliceInitialized = false;
+
+ return ReconAlgo::copyDataToGPU(pfSinogram, iSinogramPitch, fSinogramScale, pfReconstruction, iReconstructionPitch, pfVolMask, iVolMaskPitch, pfSinoMask, iSinoMaskPitch);
+}
+
+bool CGLS::iterate(unsigned int iterations)
+{
+ shouldAbort = false;
+
+ if (!sliceInitialized) {
+
+ // copy sinogram
+ cudaMemcpy2D(D_r, sizeof(float)*rPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice);
+
+ // r = sino - A*x
+ if (useVolumeMask) {
+ // Use z as temporary storage here since it is unused
+ cudaMemcpy2D(D_z, sizeof(float)*zPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice);
+ processVol<opMul, VOL>(D_z, D_maskData, zPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP(D_z, zPitch, D_r, rPitch, -1.0f);
+ } else {
+ callFP(D_volumeData, volumePitch, D_r, rPitch, -1.0f);
+ }
+
+
+ // p = A'*r
+ zeroVolume(D_p, pPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ callBP(D_p, pPitch, D_r, rPitch);
+ if (useVolumeMask)
+ processVol<opMul, VOL>(D_p, D_maskData, pPitch, dims.iVolWidth, dims.iVolHeight);
+
+
+ gamma = dotProduct2D(D_p, pPitch, dims.iVolWidth, dims.iVolHeight, 1, 1);
+
+ sliceInitialized = true;
+ }
+
+
+ // iteration
+ for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) {
+
+ // w = A*p
+ zeroVolume(D_w, wPitch, dims.iProjDets+2, dims.iProjAngles);
+ callFP(D_p, pPitch, D_w, wPitch, 1.0f);
+
+ // alpha = gamma / <w,w>
+ float ww = dotProduct2D(D_w, wPitch, dims.iProjDets, dims.iProjAngles, 1, 0);
+ float alpha = gamma / ww;
+
+ // x += alpha*p
+ processVol<opAddScaled, VOL>(D_volumeData, D_p, alpha, volumePitch, dims.iVolWidth, dims.iVolHeight);
+
+ // r -= alpha*w
+ processVol<opAddScaled, SINO>(D_r, D_w, -alpha, rPitch, dims.iProjDets, dims.iProjAngles);
+
+
+ // z = A'*r
+ zeroVolume(D_z, zPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ callBP(D_z, zPitch, D_r, rPitch);
+ if (useVolumeMask)
+ processVol<opMul, VOL>(D_z, D_maskData, zPitch, dims.iVolWidth, dims.iVolHeight);
+
+ float beta = 1.0f / gamma;
+ gamma = dotProduct2D(D_z, zPitch, dims.iVolWidth, dims.iVolHeight, 1, 1);
+ beta *= gamma;
+
+ // p = z + beta*p
+ processVol<opScaleAndAdd, VOL>(D_p, D_z, beta, pPitch, dims.iVolWidth, dims.iVolHeight);
+
+ }
+
+ return true;
+}
+
+
+float CGLS::computeDiffNorm()
+{
+ // We can use w and z as temporary storage here since they're not
+ // used outside of iterations.
+
+ // copy sinogram to w
+ cudaMemcpy2D(D_w, sizeof(float)*wPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ cudaMemcpy2D(D_z, sizeof(float)*zPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice);
+ processVol<opMul, VOL>(D_z, D_maskData, zPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP(D_z, zPitch, D_w, wPitch, -1.0f);
+ } else {
+ callFP(D_volumeData, volumePitch, D_w, wPitch, -1.0f);
+ }
+
+ // compute norm of D_w
+
+ float s = dotProduct2D(D_w, wPitch, dims.iProjDets, dims.iProjAngles, 1, 0);
+
+ return sqrt(s);
+}
+
+bool doCGLS(float* D_volumeData, unsigned int volumePitch,
+ float* D_sinoData, unsigned int sinoPitch,
+ const SDimensions& dims, /*const SAugmentedData& augs,*/
+ const float* angles, const float* TOffsets, unsigned int iterations)
+{
+ CGLS cgls;
+ bool ok = true;
+
+ ok &= cgls.setGeometry(dims, angles);
+#if 0
+ if (D_maskData)
+ ok &= cgls.enableVolumeMask();
+#endif
+ if (TOffsets)
+ ok &= cgls.setTOffsets(TOffsets);
+
+ if (!ok)
+ return false;
+
+ ok = cgls.init();
+ if (!ok)
+ return false;
+
+#if 0
+ if (D_maskData)
+ ok &= cgls.setVolumeMask(D_maskData, maskPitch);
+#endif
+
+ ok &= cgls.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch);
+ if (!ok)
+ return false;
+
+ ok = cgls.iterate(iterations);
+
+ return ok;
+}
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA;
+
+int main()
+{
+ float* D_volumeData;
+ float* D_sinoData;
+
+ SDimensions dims;
+ dims.iVolWidth = 1024;
+ dims.iVolHeight = 1024;
+ dims.iProjAngles = 512;
+ dims.iProjDets = 1536;
+ dims.fDetScale = 1.0f;
+ dims.iRaysPerDet = 1;
+ unsigned int volumePitch, sinoPitch;
+
+ allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ zeroVolume(D_volumeData, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ printf("pitch: %u\n", volumePitch);
+
+ allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch);
+ zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles);
+ printf("pitch: %u\n", sinoPitch);
+
+ unsigned int y, x;
+ float* sino = loadImage("sino.png", y, x);
+
+ float* img = new float[dims.iVolWidth*dims.iVolHeight];
+
+ copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_sinoData, sinoPitch);
+
+ float* angle = new float[dims.iProjAngles];
+
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i)
+ angle[i] = i*(M_PI/dims.iProjAngles);
+
+ CGLS cgls;
+
+ cgls.setGeometry(dims, angle);
+ cgls.init();
+
+ cgls.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch);
+
+ cgls.iterate(25);
+
+ delete[] angle;
+
+ copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+
+ saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img);
+
+ return 0;
+}
+#endif
diff --git a/cuda/2d/cgls.h b/cuda/2d/cgls.h
new file mode 100644
index 0000000..1013bf8
--- /dev/null
+++ b/cuda/2d/cgls.h
@@ -0,0 +1,92 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_CGLS_H
+#define _CUDA_CGLS_H
+
+#include "util.h"
+#include "algo.h"
+
+namespace astraCUDA {
+
+class _AstraExport CGLS : public ReconAlgo {
+public:
+ CGLS();
+ virtual ~CGLS();
+
+ // disable some features
+ virtual bool enableSinogramMask() { return false; }
+ virtual bool setMinConstraint(float) { return false; }
+ virtual bool setMaxConstraint(float) { return false; }
+
+ virtual bool init();
+
+ virtual bool setBuffers(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch);
+
+ virtual bool copyDataToGPU(const float* pfSinogram, unsigned int iSinogramPitch, float fSinogramScale,
+ const float* pfReconstruction, unsigned int iReconstructionPitch,
+ const float* pfVolMask, unsigned int iVolMaskPitch,
+ const float* pfSinoMask, unsigned int iSinoMaskPitch);
+
+
+ virtual bool iterate(unsigned int iterations);
+
+ virtual float computeDiffNorm();
+
+protected:
+ void reset();
+
+ bool sliceInitialized;
+
+ // Buffers
+ float* D_r;
+ unsigned int rPitch;
+
+ float* D_w;
+ unsigned int wPitch;
+
+ float* D_z;
+ unsigned int zPitch;
+
+ float* D_p;
+ unsigned int pPitch;
+
+
+ float gamma;
+};
+
+
+_AstraExport bool doCGLS(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets, unsigned int iterations);
+
+}
+
+#endif
diff --git a/cuda/2d/darthelper.cu b/cuda/2d/darthelper.cu
new file mode 100644
index 0000000..db0036e
--- /dev/null
+++ b/cuda/2d/darthelper.cu
@@ -0,0 +1,358 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "util.h"
+#include "darthelper.h"
+#include <cassert>
+
+namespace astraCUDA {
+
+// CUDA function for the selection of ROI
+__global__ void devRoiSelect(float* in, float radius, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY)
+{
+ float x = (float)(threadIdx.x + 16*blockIdx.x);
+ float y = (float)(threadIdx.y + 16*blockIdx.y);
+
+ float w = (width-1.0f)*0.5f;
+ float h = (height-1.0f)*0.5f;
+
+ if ((x-w)*(x-w) + (y-h)*(y-h) > radius * radius * 0.25f)
+ {
+ float* d = (float*)in;
+ unsigned int o = (y+padY)*pitch+x+padX;
+ d[o] = 0.0f;
+ }
+}
+
+void roiSelect(float* out, float radius, unsigned int width, unsigned int height)
+{
+ float* D_data;
+
+ unsigned int pitch;
+ allocateVolume(D_data, width+2, height+2, pitch);
+ copyVolumeToDevice(out, width, width, height, D_data, pitch);
+
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+ devRoiSelect<<<gridSize, blockSize>>>(D_data, radius, pitch, width, height, 1, 1);
+
+ copyVolumeFromDevice(out, width, width, height, D_data, pitch);
+
+ cudaFree(D_data);
+}
+
+
+
+
+// CUDA function for the masking of DART with a radius == 1
+__global__ void devDartMask(float* mask, const float* in, unsigned int conn, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ unsigned int y = threadIdx.y + 16*blockIdx.y;
+
+ // Sacrifice the border pixels to simplify the implementation.
+ if (x > 0 && x < width - 1 && y > 0 && y < height - 1) {
+ float* d = (float*)in;
+ float* m = (float*)mask;
+
+ unsigned int o2 = (y+padY)*pitch+x+padX; // On this row.
+ unsigned int o1 = o2 - pitch; // On previous row.
+ unsigned int o3 = o2 + pitch; // On next row.
+
+ if ((conn == 8 && // 8-connected
+ (d[o1 - 1] != d[o2] || d[o1] != d[o2] || d[o1 + 1] != d[o2] ||
+ d[o2 - 1] != d[o2] || d[o2 + 1] != d[o2] ||
+ d[o3 - 1] != d[o2] || d[o3] != d[o2] || d[o3 + 1] != d[o2] ))
+ ||
+ (conn == 4 && // 4-connected
+ ( d[o1] != d[o2] ||
+ d[o2 - 1] != d[o2] || d[o3 + 1] != d[o2] ||
+ d[o3] != d[o2] )))
+ {
+ m[o2] = 1.0f;
+ }
+ }
+}
+
+
+// CUDA function for the masking of DART with a radius > 1
+__global__ void devDartMaskRadius(float* mask, const float* in, unsigned int conn, unsigned int radius, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ unsigned int y = threadIdx.y + 16*blockIdx.y;
+
+ // Sacrifice the border pixels to simplify the implementation.
+ if (x > radius-1 && x < width - radius && y > radius-1 && y < height - radius)
+ {
+ float* d = (float*)in;
+ float* m = (float*)mask;
+
+ int r = radius;
+
+ // o2: index of the current center pixel
+ int o2 = (y+padY)*pitch+x+padX;
+
+ if (conn == 8) // 8-connected
+ {
+ for (int row = -r; row <= r; row++)
+ {
+ int o1 = (y+padY+row)*pitch+x+padX;
+ for (int col = -r; col <= r; col++)
+ {
+ if (d[o1 + col] != d[o2]) {m[o2] = 1.0f; return;}
+ }
+ }
+ }
+ else if (conn == 4) // 4-connected
+ {
+ // horizontal
+ unsigned int o1 = (y+padY)*pitch+x+padX;
+ for (int col = -r; col <= r; col++)
+ {
+ if (d[o1 + col] != d[o2]) {m[o2] = 1.0f; return;}
+ }
+
+ // vertical
+ for (int row = -r; row <= r; row++)
+ {
+ unsigned int o1 = (y+padY+row)*pitch+x+padX;
+ if (d[o1] != d[o2]) {m[o2] = 1.0f; return;}
+ }
+ }
+ }
+}
+
+
+// CUDA function for the masking of ADART with a radius == 1
+__global__ void devADartMask(float* mask, const float* in, unsigned int conn, unsigned int threshold, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ unsigned int y = threadIdx.y + 16*blockIdx.y;
+
+ // Sacrifice the border pixels to simplify the implementation.
+ if (x > 0 && x < width - 1 && y > 0 && y < height - 1) {
+ float* d = (float*)in;
+ float* m = (float*)mask;
+
+ unsigned int o2 = (y+padY)*pitch+x+padX; // On this row.
+ unsigned int o1 = o2 - pitch; // On previous row.
+ unsigned int o3 = o2 + pitch; // On next row.
+
+ if (conn == 8)
+ {
+ if (d[o1 - 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o1 ] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o1 + 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o2 - 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o2 + 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o3 - 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o3 ] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o3 + 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ }
+ else if (conn == 4)
+ {
+ if (d[o1 ] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o2 - 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o2 + 1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ if (d[o3 ] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ }
+ }
+}
+
+
+// CUDA function for the masking of ADART with a radius > 1
+__global__ void devADartMaskRadius(float* mask, const float* in, unsigned int conn, unsigned int radius, unsigned int threshold, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ unsigned int y = threadIdx.y + 16*blockIdx.y;
+
+ // Sacrifice the border pixels to simplify the implementation.
+ if (x > radius-1 && x < width - radius && y > radius-1 && y < height - radius)
+ {
+ float* d = (float*)in;
+ float* m = (float*)mask;
+
+ int r = radius;
+
+ unsigned int o2 = (y+padY)*pitch+x+padX; // On this row.
+
+ if (conn == 8)
+ {
+ for (int row = -r; row <= r; row++)
+ {
+ unsigned int o1 = (y+padY+row)*pitch+x+padX;
+ for (int col = -r; col <= r; col++)
+ {
+ if (d[o1+col] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ }
+ }
+ }
+ else if (conn == 4)
+ {
+ // horizontal
+ for (int col = -r; col <= r; col++)
+ {
+ if (d[o2+col] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ }
+
+ // vertical
+ for (int row = -r; row <= r; row++)
+ {
+ unsigned int o1 = (y+padY+row)*pitch+x+padX;
+ if (d[o1] != d[o2] && --threshold == 0) {m[o2] = 1.0f; return;}
+ }
+ }
+ }
+}
+
+
+void dartMask(float* mask, const float* segmentation, unsigned int conn, unsigned int radius, unsigned int threshold, unsigned int width, unsigned int height)
+{
+ float* D_segmentationData;
+ float* D_maskData;
+
+ unsigned int pitch;
+ allocateVolume(D_segmentationData, width+2, height+2, pitch);
+ copyVolumeToDevice(segmentation, width, width, height, D_segmentationData, pitch);
+
+ allocateVolume(D_maskData, width+2, height+2, pitch);
+ zeroVolume(D_maskData, pitch, width+2, height+2);
+
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ if (threshold == 1 && radius == 1)
+ devDartMask<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, pitch, width, height, 1, 1);
+ else if (threshold > 1 && radius == 1)
+ devADartMask<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, threshold, pitch, width, height, 1, 1);
+ else if (threshold == 1 && radius > 1)
+ devDartMaskRadius<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, radius, pitch, width, height, 1, 1);
+ else
+ devADartMaskRadius<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, radius, threshold, pitch, width, height, 1, 1);
+
+ copyVolumeFromDevice(mask, width, width, height, D_maskData, pitch);
+
+ cudaFree(D_segmentationData);
+ cudaFree(D_maskData);
+
+}
+
+
+__global__ void devDartSmoothingRadius(float* out, const float* in, float b, unsigned int radius, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ unsigned int y = threadIdx.y + 16*blockIdx.y;
+
+ // Sacrifice the border pixels to simplify the implementation.
+ if (x > radius-1 && x < width - radius && y > radius-1 && y < height - radius)
+ {
+ float* d = (float*)in;
+ float* m = (float*)out;
+
+ unsigned int o2 = (y+padY)*pitch+x+padX;
+ int r = radius;
+ float res = -d[o2];
+
+ for (int row = -r; row < r; row++)
+ {
+ unsigned int o1 = (y+padY+row)*pitch+x+padX;
+ for (int col = -r; col <= r; col++)
+ {
+ res += d[o1+col];
+ }
+ }
+
+ res *= b / 4*r*(r+1);
+ res += (1.0f-b) * d[o2];
+
+ m[o2] = res;
+ }
+}
+
+
+__global__ void devDartSmoothing(float* out, const float* in, float b, unsigned int pitch, unsigned int width, unsigned int height, unsigned int padX, unsigned int padY)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ unsigned int y = threadIdx.y + 16*blockIdx.y;
+
+ // Sacrifice the border pixels to simplify the implementation.
+ if (x > 0 && x < width - 1 && y > 0 && y < height - 1) {
+ float* d = (float*)in;
+ float* m = (float*)out;
+
+ unsigned int o2 = (y+padY)*pitch+x+padX; // On this row.
+ unsigned int o1 = o2 - pitch; // On previous row.
+ unsigned int o3 = o2 + pitch; // On next row.
+
+ m[o2] = (1.0f-b) * d[o2] + b * 0.125f * (d[o1 - 1] + d[o1] + d[o1 + 1] + d[o2 - 1] + d[o2 + 1] + d[o3 - 1] + d[o3] + d[o3 + 1]);
+ }
+}
+
+
+void dartSmoothing(float* out, const float* in, float b, unsigned int radius, unsigned int width, unsigned int height)
+{
+ float* D_inData;
+ float* D_outData;
+
+ unsigned int pitch;
+ allocateVolume(D_inData, width+2, height+2, pitch);
+ copyVolumeToDevice(in, width, width, height, D_inData, pitch);
+
+ allocateVolume(D_outData, width+2, height+2, pitch);
+ zeroVolume(D_outData, pitch, width+2, height+2);
+
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+ if (radius == 1)
+ devDartSmoothing<<<gridSize, blockSize>>>(D_outData, D_inData, b, pitch, width, height, 1, 1);
+ else
+ devDartSmoothingRadius<<<gridSize, blockSize>>>(D_outData, D_inData, b, radius, pitch, width, height, 1, 1);
+
+ copyVolumeFromDevice(out, width, width, height, D_outData, pitch);
+
+ cudaFree(D_outData);
+ cudaFree(D_inData);
+
+}
+
+
+
+bool setGPUIndex(int iGPUIndex)
+{
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+ return true;
+}
+
+
+}
diff --git a/cuda/2d/darthelper.h b/cuda/2d/darthelper.h
new file mode 100644
index 0000000..e05f01e
--- /dev/null
+++ b/cuda/2d/darthelper.h
@@ -0,0 +1,44 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_ARITH2_H
+#define _CUDA_ARITH2_H
+
+#include <cuda.h>
+
+namespace astraCUDA {
+
+ void roiSelect(float* out, float radius, unsigned int width, unsigned int height);
+ void dartMask(float* out, const float* in, unsigned int conn, unsigned int radius, unsigned int threshold, unsigned int width, unsigned int height);
+ void dartSmoothing(float* out, const float* in, float b, unsigned int radius, unsigned int width, unsigned int height);
+
+ bool setGPUIndex(int index);
+
+}
+
+#endif
diff --git a/cuda/2d/dataop.cu b/cuda/2d/dataop.cu
new file mode 100644
index 0000000..68573b2
--- /dev/null
+++ b/cuda/2d/dataop.cu
@@ -0,0 +1,130 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "util.h"
+#include "dataop.h"
+#include "arith.h"
+#include <cassert>
+
+namespace astraCUDA {
+
+void operationVolumeMult(float* data1, float* data2, unsigned int width, unsigned int height)
+{
+ float* D_data1;
+ float* D_data2;
+
+ unsigned int pitch;
+ allocateVolume(D_data1, width+2, height+2, pitch);
+ copyVolumeToDevice(data1, width, width, height, D_data1, pitch);
+
+ allocateVolume(D_data2, width+2, height+2, pitch);
+ copyVolumeToDevice(data2, width, width, height, D_data2, pitch);
+
+ processVol<opMul, VOL>(D_data1, D_data2, pitch, width, height);
+
+ copyVolumeFromDevice(data1, width, width, height, D_data1, pitch);
+
+ cudaFree(D_data1);
+ cudaFree(D_data2);
+}
+
+void operationVolumeMultScalarMask(float* data, float* mask, float scalar, unsigned int width, unsigned int height)
+{
+ float* D_data;
+ float* D_mask;
+
+ unsigned int pitch;
+ allocateVolume(D_data, width+2, height+2, pitch);
+ copyVolumeToDevice(data, width, width, height, D_data, pitch);
+
+ allocateVolume(D_mask, width+2, height+2, pitch);
+ copyVolumeToDevice(mask, width, width, height, D_mask, pitch);
+
+ processVol<opMulMask, VOL>(D_data, D_mask, scalar, pitch, width, height);
+
+ copyVolumeFromDevice(data, width, width, height, D_data, pitch);
+
+ cudaFree(D_data);
+ cudaFree(D_mask);
+}
+
+
+void operationVolumeMultScalar(float* data, float scalar, unsigned int width, unsigned int height)
+{
+ float* D_data;
+
+ unsigned int pitch;
+ allocateVolume(D_data, width+2, height+2, pitch);
+ copyVolumeToDevice(data, width, width, height, D_data, pitch);
+
+ processVol<opMul, VOL>(D_data, scalar, pitch, width, height);
+
+ copyVolumeFromDevice(data, width, width, height, D_data, pitch);
+
+ cudaFree(D_data);
+}
+
+
+void operationVolumeAdd(float* data1, float* data2, unsigned int width, unsigned int height)
+{
+ float* D_data1;
+ float* D_data2;
+
+ unsigned int pitch;
+ allocateVolume(D_data1, width+2, height+2, pitch);
+ copyVolumeToDevice(data1, width, width, height, D_data1, pitch);
+
+ allocateVolume(D_data2, width+2, height+2, pitch);
+ copyVolumeToDevice(data2, width, width, height, D_data2, pitch);
+
+ processVol<opAdd, VOL>(D_data1, D_data2, pitch, width, height);
+
+ copyVolumeFromDevice(data1, width, width, height, D_data1, pitch);
+
+ cudaFree(D_data1);
+ cudaFree(D_data2);
+}
+
+
+void operationVolumeAddScalar(float* data, float scalar, unsigned int width, unsigned int height)
+{
+ float* D_data;
+
+ unsigned int pitch;
+ allocateVolume(D_data, width+2, height+2, pitch);
+ copyVolumeToDevice(data, width, width, height, D_data, pitch);
+
+ processVol<opAdd, VOL>(D_data, scalar, pitch, width, height);
+
+ copyVolumeFromDevice(data, width, width, height, D_data, pitch);
+
+ cudaFree(D_data);
+}
+
+
+}
diff --git a/cuda/2d/dataop.h b/cuda/2d/dataop.h
new file mode 100644
index 0000000..3e9c7e2
--- /dev/null
+++ b/cuda/2d/dataop.h
@@ -0,0 +1,47 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_DATAOP_H
+#define _CUDA_DATAOP_H
+
+#include <cuda.h>
+
+namespace astraCUDA {
+
+ void operationVolumeMult(float* data1, float* data2, unsigned int width, unsigned int height);
+
+ void operationVolumeMultScalar(float* data, float scalar, unsigned int width, unsigned int height);
+ void operationVolumeMultScalarMask(float* data, float* mask, float scalar, unsigned int width, unsigned int height);
+
+ void operationVolumeAdd(float* data1, float* data2, unsigned int width, unsigned int height);
+
+ void operationVolumeAddScalar(float* data, float scalar, unsigned int width, unsigned int height);
+
+}
+
+#endif
diff --git a/cuda/2d/dims.h b/cuda/2d/dims.h
new file mode 100644
index 0000000..21ccb31
--- /dev/null
+++ b/cuda/2d/dims.h
@@ -0,0 +1,68 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_DIMS_H
+#define _CUDA_DIMS_H
+
+namespace astraCUDA {
+
+struct SFanProjection {
+ // the source
+ float fSrcX, fSrcY;
+
+ // the start of the (linear) detector
+ float fDetSX, fDetSY;
+
+ // the length of a single detector pixel
+ float fDetUX, fDetUY;
+};
+
+
+struct SDimensions {
+ unsigned int iVolWidth;
+ unsigned int iVolHeight;
+ unsigned int iProjAngles;
+ unsigned int iProjDets;
+ float fDetScale; // size of detector compared to volume pixels
+ unsigned int iRaysPerDet;
+ unsigned int iRaysPerPixelDim;
+};
+
+struct SDimensions3D {
+ unsigned int iVolX;
+ unsigned int iVolY;
+ unsigned int iVolZ;
+ unsigned int iProjAngles;
+ unsigned int iProjU; // number of detectors in the U direction
+ unsigned int iProjV; // number of detectors in the V direction
+};
+
+}
+
+#endif
+
diff --git a/cuda/2d/em.cu b/cuda/2d/em.cu
new file mode 100644
index 0000000..74d1bbf
--- /dev/null
+++ b/cuda/2d/em.cu
@@ -0,0 +1,262 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+
+#include "em.h"
+#include "util.h"
+#include "arith.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+namespace astraCUDA {
+
+
+// TODO: ensure non-negativity somewhere??
+
+
+EM::EM()
+{
+ D_projData = 0;
+ D_tmpData = 0;
+ D_pixelWeight = 0;
+
+}
+
+
+EM::~EM()
+{
+ reset();
+}
+
+void EM::reset()
+{
+ cudaFree(D_projData);
+ cudaFree(D_tmpData);
+ cudaFree(D_pixelWeight);
+
+ D_projData = 0;
+ D_tmpData = 0;
+ D_pixelWeight = 0;
+
+ ReconAlgo::reset();
+}
+
+
+bool EM::init()
+{
+ allocateVolume(D_pixelWeight, dims.iVolWidth+2, dims.iVolHeight+2, pixelPitch);
+ zeroVolume(D_pixelWeight, pixelPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+ allocateVolume(D_tmpData, dims.iVolWidth+2, dims.iVolHeight+2, tmpPitch);
+ zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+ allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch);
+ zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles);
+
+ // We can't precompute pixelWeights when using a volume mask
+#if 0
+ if (!useVolumeMask)
+#endif
+ precomputeWeights();
+
+ // TODO: check if allocations succeeded
+ return true;
+}
+
+bool EM::precomputeWeights()
+{
+ zeroVolume(D_pixelWeight, pixelPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+#if 0
+ if (useSinogramMask) {
+ callBP(D_pixelWeight, pixelPitch, D_smaskData, smaskPitch);
+ } else
+#endif
+ {
+ processVol<opSet, SINO>(D_projData, 1.0f, projPitch, dims.iProjDets, dims.iProjAngles);
+ callBP(D_pixelWeight, pixelPitch, D_projData, projPitch);
+ }
+ processVol<opInvert, VOL>(D_pixelWeight, pixelPitch, dims.iVolWidth, dims.iVolHeight);
+
+#if 0
+ if (useVolumeMask) {
+ // scale pixel weights with mask to zero out masked pixels
+ processVol<opMul, VOL>(D_pixelWeight, D_maskData, pixelPitch, dims.iVolWidth, dims.iVolHeight);
+ }
+#endif
+
+ return true;
+}
+
+bool EM::iterate(unsigned int iterations)
+{
+ shouldAbort = false;
+
+#if 0
+ if (useVolumeMask)
+ precomputeWeights();
+#endif
+
+ // iteration
+ for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) {
+
+ // Do FP of volumeData
+ zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles);
+ callFP(D_volumeData, volumePitch, D_projData, projPitch, 1.0f);
+
+ // Divide sinogram by FP (into projData)
+ processVol<opDividedBy, SINO>(D_projData, D_sinoData, projPitch, dims.iProjDets, dims.iProjAngles);
+
+ // Do BP of projData into tmpData
+ zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ callBP(D_tmpData, tmpPitch, D_projData, projPitch);
+
+ // Multiply volumeData with tmpData divided by pixel weights
+ processVol<opMul2, VOL>(D_volumeData, D_tmpData, D_pixelWeight, pixelPitch, dims.iVolWidth, dims.iVolHeight);
+
+ }
+
+ return true;
+}
+
+float EM::computeDiffNorm()
+{
+ // copy sinogram to projection data
+ cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice);
+ processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP(D_tmpData, tmpPitch, D_projData, projPitch, -1.0f);
+ } else {
+ callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f);
+ }
+
+
+ // compute norm of D_projData
+
+ float s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0);
+
+ return sqrt(s);
+}
+
+
+bool doEM(float* D_volumeData, unsigned int volumePitch,
+ float* D_sinoData, unsigned int sinoPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets, unsigned int iterations)
+{
+ EM em;
+ bool ok = true;
+
+ ok &= em.setGeometry(dims, angles);
+ if (TOffsets)
+ ok &= em.setTOffsets(TOffsets);
+
+ if (!ok)
+ return false;
+
+ ok = em.init();
+ if (!ok)
+ return false;
+
+ ok &= em.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch);
+ if (!ok)
+ return false;
+
+ ok = em.iterate(iterations);
+
+ return ok;
+}
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA;
+
+int main()
+{
+ float* D_volumeData;
+ float* D_sinoData;
+
+ SDimensions dims;
+ dims.iVolWidth = 1024;
+ dims.iVolHeight = 1024;
+ dims.iProjAngles = 512;
+ dims.iProjDets = 1536;
+ dims.fDetScale = 1.0f;
+ dims.iRaysPerDet = 1;
+ unsigned int volumePitch, sinoPitch;
+
+ allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ zeroVolume(D_volumeData, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ printf("pitch: %u\n", volumePitch);
+
+ allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch);
+ zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles);
+ printf("pitch: %u\n", sinoPitch);
+
+ unsigned int y, x;
+ float* sino = loadImage("sino.png", y, x);
+
+ float* img = new float[dims.iVolWidth*dims.iVolHeight];
+
+ copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_sinoData, sinoPitch);
+
+ float* angle = new float[dims.iProjAngles];
+
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i)
+ angle[i] = i*(M_PI/dims.iProjAngles);
+
+ EM em;
+
+ em.setGeometry(dims, angle);
+ em.init();
+
+ // TODO: Initialize D_volumeData with an unfiltered backprojection
+
+ em.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch);
+
+ em.iterate(25);
+
+
+ delete[] angle;
+
+ copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+
+ saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img);
+
+ return 0;
+}
+
+#endif
diff --git a/cuda/2d/em.h b/cuda/2d/em.h
new file mode 100644
index 0000000..5a9ffed
--- /dev/null
+++ b/cuda/2d/em.h
@@ -0,0 +1,77 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_EM_H
+#define _CUDA_EM_H
+
+#include "util.h"
+#include "algo.h"
+
+namespace astraCUDA {
+
+class _AstraExport EM : public ReconAlgo {
+public:
+ EM();
+ virtual ~EM();
+
+ // disable some features
+ virtual bool enableSinogramMask() { return false; }
+ virtual bool enableVolumeMask() { return false; }
+ virtual bool setMinConstraint(float) { return false; }
+ virtual bool setMaxConstraint(float) { return false; }
+
+ virtual bool init();
+
+ virtual bool iterate(unsigned int iterations);
+
+ virtual float computeDiffNorm();
+
+protected:
+ void reset();
+ bool precomputeWeights();
+
+ // Temporary buffers
+ float* D_projData;
+ unsigned int projPitch;
+
+ float* D_tmpData;
+ unsigned int tmpPitch;
+
+ // Geometry-specific precomputed data
+ float* D_pixelWeight;
+ unsigned int pixelPitch;
+};
+
+_AstraExport bool doEM(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets, unsigned int iterations);
+
+}
+
+#endif
diff --git a/cuda/2d/fan_bp.cu b/cuda/2d/fan_bp.cu
new file mode 100644
index 0000000..1edc6d9
--- /dev/null
+++ b/cuda/2d/fan_bp.cu
@@ -0,0 +1,374 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+
+#include "util.h"
+#include "arith.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+#define PIXELTRACE
+
+
+typedef texture<float, 2, cudaReadModeElementType> texture2D;
+
+static texture2D gT_FanProjTexture;
+
+
+namespace astraCUDA {
+
+const unsigned int g_anglesPerBlock = 16;
+const unsigned int g_blockSliceSize = 32;
+const unsigned int g_blockSlices = 16;
+
+const unsigned int g_MaxAngles = 2560;
+
+__constant__ float gC_SrcX[g_MaxAngles];
+__constant__ float gC_SrcY[g_MaxAngles];
+__constant__ float gC_DetSX[g_MaxAngles];
+__constant__ float gC_DetSY[g_MaxAngles];
+__constant__ float gC_DetUX[g_MaxAngles];
+__constant__ float gC_DetUY[g_MaxAngles];
+
+
+static bool bindProjDataTexture(float* data, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+
+ gT_FanProjTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_FanProjTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_FanProjTexture.filterMode = cudaFilterModeLinear;
+ gT_FanProjTexture.normalized = false;
+
+ cudaBindTexture2D(0, gT_FanProjTexture, (const void*)data, channelDesc, width, height, sizeof(float)*pitch);
+
+ // TODO: error value?
+
+ return true;
+}
+
+__global__ void devFanBP(float* D_volData, unsigned int volPitch, unsigned int startAngle, const SDimensions dims)
+{
+ const int relX = threadIdx.x;
+ const int relY = threadIdx.y;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+ const int X = blockIdx.x * g_blockSlices + relX;
+ const int Y = blockIdx.y * g_blockSliceSize + relY;
+
+ if (X >= dims.iVolWidth || Y >= dims.iVolHeight)
+ return;
+
+ const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f );
+ const float fY = - ( Y - 0.5f*dims.iVolHeight + 0.5f );
+
+ float* volData = (float*)D_volData;
+
+ float fVal = 0.0f;
+ float fA = startAngle + 0.5f;
+
+ // TODO: Distance correction?
+
+ for (int angle = startAngle; angle < endAngle; ++angle)
+ {
+ const float fSrcX = gC_SrcX[angle];
+ const float fSrcY = gC_SrcY[angle];
+ const float fDetSX = gC_DetSX[angle];
+ const float fDetSY = gC_DetSY[angle];
+ const float fDetUX = gC_DetUX[angle];
+ const float fDetUY = gC_DetUY[angle];
+
+ const float fXD = fSrcX - fX;
+ const float fYD = fSrcY - fY;
+
+ const float fNum = fDetSY * fXD - fDetSX * fYD + fX*fSrcY - fY*fSrcX;
+ const float fDen = fDetUX * fYD - fDetUY * fXD;
+
+ const float fT = fNum / fDen + 1.0f;
+ fVal += tex2D(gT_FanProjTexture, fT, fA);
+ fA += 1.0f;
+ }
+
+ volData[(Y+1)*volPitch+X+1] += fVal;
+}
+
+// supersampling version
+__global__ void devFanBP_SS(float* D_volData, unsigned int volPitch, unsigned int startAngle, const SDimensions dims)
+{
+ const int relX = threadIdx.x;
+ const int relY = threadIdx.y;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+ const int X = blockIdx.x * g_blockSlices + relX;
+ const int Y = blockIdx.y * g_blockSliceSize + relY;
+
+ if (X >= dims.iVolWidth || Y >= dims.iVolHeight)
+ return;
+
+ const float fXb = ( X - 0.5f*dims.iVolWidth + 0.5f - 0.5f + 0.5f/dims.iRaysPerPixelDim);
+ const float fYb = - ( Y - 0.5f*dims.iVolHeight + 0.5f - 0.5f + 0.5f/dims.iRaysPerPixelDim);
+
+ const float fSubStep = 1.0f/dims.iRaysPerPixelDim;
+
+ float* volData = (float*)D_volData;
+
+ float fVal = 0.0f;
+ float fA = startAngle + 0.5f;
+
+ // TODO: Distance correction?
+
+ for (int angle = startAngle; angle < endAngle; ++angle)
+ {
+ const float fSrcX = gC_SrcX[angle];
+ const float fSrcY = gC_SrcY[angle];
+ const float fDetSX = gC_DetSX[angle];
+ const float fDetSY = gC_DetSY[angle];
+ const float fDetUX = gC_DetUX[angle];
+ const float fDetUY = gC_DetUY[angle];
+
+ // TODO: Optimize these loops...
+ float fX = fXb;
+ for (int iSubX = 0; iSubX < dims.iRaysPerPixelDim; ++iSubX) {
+ float fY = fYb;
+ for (int iSubY = 0; iSubY < dims.iRaysPerPixelDim; ++iSubY) {
+ const float fXD = fSrcX - fX;
+ const float fYD = fSrcY - fY;
+
+ const float fNum = fDetSY * fXD - fDetSX * fYD + fX*fSrcY - fY*fSrcX;
+ const float fDen = fDetUX * fYD - fDetUY * fXD;
+
+ const float fT = fNum / fDen + 1.0f;
+ fVal += tex2D(gT_FanProjTexture, fT, fA);
+ fY -= fSubStep;
+ }
+ fX += fSubStep;
+ }
+ fA += 1.0f;
+ }
+
+ volData[(Y+1)*volPitch+X+1] += fVal / (dims.iRaysPerPixelDim * dims.iRaysPerPixelDim);
+}
+
+
+// BP specifically for SART.
+// It includes (free) weighting with voxel weight.
+// It assumes the proj texture is set up _without_ padding, unlike regular BP.
+__global__ void devFanBP_SART(float* D_volData, unsigned int volPitch, const SDimensions dims)
+{
+ const int relX = threadIdx.x;
+ const int relY = threadIdx.y;
+
+ const int X = blockIdx.x * g_blockSlices + relX;
+ const int Y = blockIdx.y * g_blockSliceSize + relY;
+
+ if (X >= dims.iVolWidth || Y >= dims.iVolHeight)
+ return;
+
+ const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f );
+ const float fY = - ( Y - 0.5f*dims.iVolHeight + 0.5f );
+
+ float* volData = (float*)D_volData;
+
+ // TODO: Distance correction?
+
+ // TODO: Constant memory vs parameters.
+ const float fSrcX = gC_SrcX[0];
+ const float fSrcY = gC_SrcY[0];
+ const float fDetSX = gC_DetSX[0];
+ const float fDetSY = gC_DetSY[0];
+ const float fDetUX = gC_DetUX[0];
+ const float fDetUY = gC_DetUY[0];
+
+ const float fXD = fSrcX - fX;
+ const float fYD = fSrcY - fY;
+
+ const float fNum = fDetSY * fXD - fDetSX * fYD + fX*fSrcY - fY*fSrcX;
+ const float fDen = fDetUX * fYD - fDetUY * fXD;
+
+ const float fT = fNum / fDen;
+ const float fVal = tex2D(gT_FanProjTexture, fT, 0.5f);
+
+ volData[(Y+1)*volPitch+X+1] += fVal;
+}
+
+
+bool FanBP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const SFanProjection* angles)
+{
+ // TODO: process angles block by block
+ assert(dims.iProjAngles <= g_MaxAngles);
+
+ bindProjDataTexture(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles);
+
+ // transfer angles to constant memory
+ float* tmp = new float[dims.iProjAngles];
+
+#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
+
+ TRANSFER_TO_CONSTANT(SrcX);
+ TRANSFER_TO_CONSTANT(SrcY);
+ TRANSFER_TO_CONSTANT(DetSX);
+ TRANSFER_TO_CONSTANT(DetSY);
+ TRANSFER_TO_CONSTANT(DetUX);
+ TRANSFER_TO_CONSTANT(DetUY);
+
+#undef TRANSFER_TO_CONSTANT
+
+ delete[] tmp;
+
+ dim3 dimBlock(g_blockSlices, g_blockSliceSize);
+ dim3 dimGrid((dims.iVolWidth+g_blockSlices-1)/g_blockSlices,
+ (dims.iVolHeight+g_blockSliceSize-1)/g_blockSliceSize);
+
+ cudaStream_t stream;
+ cudaStreamCreate(&stream);
+
+ for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) {
+ if (dims.iRaysPerPixelDim > 1)
+ devFanBP_SS<<<dimGrid, dimBlock, 0, stream>>>(D_volumeData, volumePitch, i, dims);
+ else
+ devFanBP<<<dimGrid, dimBlock, 0, stream>>>(D_volumeData, volumePitch, i, dims);
+ }
+ cudaThreadSynchronize();
+
+ cudaTextForceKernelsCompletion();
+
+ cudaStreamDestroy(stream);
+
+ return true;
+}
+
+
+// D_projData is a pointer to one padded sinogram line
+bool FanBP_SART(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ unsigned int angle,
+ const SDimensions& dims, const SFanProjection* angles)
+{
+ // only one angle
+ bindProjDataTexture(D_projData, projPitch, dims.iProjDets, 1);
+
+ // transfer angle to constant memory
+#define TRANSFER_TO_CONSTANT(name) do { cudaMemcpyToSymbol(gC_##name, &(angles[angle].f##name), sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
+
+ TRANSFER_TO_CONSTANT(SrcX);
+ TRANSFER_TO_CONSTANT(SrcY);
+ TRANSFER_TO_CONSTANT(DetSX);
+ TRANSFER_TO_CONSTANT(DetSY);
+ TRANSFER_TO_CONSTANT(DetUX);
+ TRANSFER_TO_CONSTANT(DetUY);
+
+#undef TRANSFER_TO_CONSTANT
+
+ dim3 dimBlock(g_blockSlices, g_blockSliceSize);
+ dim3 dimGrid((dims.iVolWidth+g_blockSlices-1)/g_blockSlices,
+ (dims.iVolHeight+g_blockSliceSize-1)/g_blockSliceSize);
+
+ devFanBP_SART<<<dimGrid, dimBlock>>>(D_volumeData, volumePitch, dims);
+ cudaThreadSynchronize();
+
+ cudaTextForceKernelsCompletion();
+
+ return true;
+}
+
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA;
+
+int main()
+{
+ float* D_volumeData;
+ float* D_projData;
+
+ SDimensions dims;
+ dims.iVolWidth = 128;
+ dims.iVolHeight = 128;
+ dims.iProjAngles = 180;
+ dims.iProjDets = 256;
+ dims.fDetScale = 1.0f;
+ dims.iRaysPerDet = 1;
+ unsigned int volumePitch, projPitch;
+
+ SFanProjection projs[180];
+
+ projs[0].fSrcX = 0.0f;
+ projs[0].fSrcY = 1536.0f;
+ projs[0].fDetSX = 128.0f;
+ projs[0].fDetSY = -512.0f;
+ projs[0].fDetUX = -1.0f;
+ projs[0].fDetUY = 0.0f;
+
+#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = projs[0].f##name##X * cos(alpha) - projs[0].f##name##Y * sin(alpha); projs[i].f##name##Y = projs[0].f##name##X * sin(alpha) + projs[0].f##name##Y * cos(alpha); } while(0)
+
+ for (int i = 1; i < 180; ++i) {
+ ROTATE0(Src, i, i*2*M_PI/180);
+ ROTATE0(DetS, i, i*2*M_PI/180);
+ ROTATE0(DetU, i, i*2*M_PI/180);
+ }
+
+#undef ROTATE0
+
+ allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ printf("pitch: %u\n", volumePitch);
+
+ allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch);
+ printf("pitch: %u\n", projPitch);
+
+ unsigned int y, x;
+ float* sino = loadImage("sino.png", y, x);
+
+ float* img = new float[dims.iVolWidth*dims.iVolHeight];
+
+ memset(img, 0, dims.iVolWidth*dims.iVolHeight*sizeof(float));
+
+ copyVolumeToDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+ copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch);
+
+ FanBP(D_volumeData, volumePitch, D_projData, projPitch, dims, projs);
+
+ copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+
+ saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img);
+
+ return 0;
+}
+#endif
diff --git a/cuda/2d/fan_bp.h b/cuda/2d/fan_bp.h
new file mode 100644
index 0000000..a4e62be
--- /dev/null
+++ b/cuda/2d/fan_bp.h
@@ -0,0 +1,45 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_FAN_BP_H
+#define _CUDA_FAN_BP_H
+
+namespace astraCUDA {
+
+_AstraExport bool FanBP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const SFanProjection* angles);
+
+_AstraExport bool FanBP_SART(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ unsigned int angle,
+ const SDimensions& dims, const SFanProjection* angles);
+
+}
+
+#endif
diff --git a/cuda/2d/fan_fp.cu b/cuda/2d/fan_fp.cu
new file mode 100644
index 0000000..cf9f352
--- /dev/null
+++ b/cuda/2d/fan_fp.cu
@@ -0,0 +1,370 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+#include <list>
+
+#include "util.h"
+#include "arith.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+
+typedef texture<float, 2, cudaReadModeElementType> texture2D;
+
+static texture2D gT_FanVolumeTexture;
+
+
+namespace astraCUDA {
+
+static const unsigned g_MaxAngles = 2560;
+__constant__ float gC_SrcX[g_MaxAngles];
+__constant__ float gC_SrcY[g_MaxAngles];
+__constant__ float gC_DetSX[g_MaxAngles];
+__constant__ float gC_DetSY[g_MaxAngles];
+__constant__ float gC_DetUX[g_MaxAngles];
+__constant__ float gC_DetUY[g_MaxAngles];
+
+
+// optimization parameters
+static const unsigned int g_anglesPerBlock = 16;
+static const unsigned int g_detBlockSize = 32;
+static const unsigned int g_blockSlices = 64;
+
+static bool bindVolumeDataTexture(float* data, cudaArray*& dataArray, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+ dataArray = 0;
+ cudaMallocArray(&dataArray, &channelDesc, width, height);
+ cudaMemcpy2DToArray(dataArray, 0, 0, data, pitch*sizeof(float), width*sizeof(float), height, cudaMemcpyDeviceToDevice);
+
+ gT_FanVolumeTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_FanVolumeTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_FanVolumeTexture.filterMode = cudaFilterModeLinear;
+ gT_FanVolumeTexture.normalized = false;
+
+ // TODO: For very small sizes (roughly <=512x128) with few angles (<=180)
+ // not using an array is more efficient.
+ //cudaBindTexture2D(0, gT_FanVolumeTexture, (const void*)data, channelDesc, width, height, sizeof(float)*pitch);
+ cudaBindTextureToArray(gT_FanVolumeTexture, dataArray, channelDesc);
+
+ // TODO: error value?
+
+ return true;
+}
+
+// projection for angles that are roughly horizontal
+// (detector roughly vertical)
+__global__ void FanFPhorizontal(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions dims, float outputScale)
+{
+ float* projData = (float*)D_projData;
+ const int relDet = threadIdx.x;
+ const int relAngle = threadIdx.y;
+
+ const int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle;
+ if (angle >= endAngle)
+ return;
+
+ const int detector = blockIdx.y * g_detBlockSize + relDet;
+
+ if (detector < 0 || detector >= dims.iProjDets)
+ return;
+
+ const float fSrcX = gC_SrcX[angle];
+ const float fSrcY = gC_SrcY[angle];
+ const float fDetSX = gC_DetSX[angle];
+ const float fDetSY = gC_DetSY[angle];
+ const float fDetUX = gC_DetUX[angle];
+ const float fDetUY = gC_DetUY[angle];
+
+ float fVal = 0.0f;
+
+ const float fdx = fabsf(fDetSX + detector*fDetUX + 0.5f - fSrcX);
+ const float fdy = fabsf(fDetSY + detector*fDetUY + 0.5f - fSrcY);
+
+ if (fdy > fdx)
+ return;
+
+
+ for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) {
+ const float fDet = detector + (0.5f + iSubT) / dims.iRaysPerDet;
+
+ const float fDetX = fDetSX + fDet * fDetUX;
+ const float fDetY = fDetSY + fDet * fDetUY;
+
+ // ray: y = alpha * x + beta
+ const float alpha = (fSrcY - fDetY) / (fSrcX - fDetX);
+ const float beta = fSrcY - alpha * fSrcX;
+
+ const float fDistCorr = sqrt(alpha*alpha+1.0f) * outputScale / dims.iRaysPerDet;
+
+ // intersect ray with first slice
+
+ float fY = -alpha * (startSlice - 0.5f*dims.iVolWidth + 0.5f) - beta + 0.5f*dims.iVolHeight - 0.5f + 1.5f;
+ float fX = startSlice + 1.5f;
+
+ int endSlice = startSlice + g_blockSlices;
+ if (endSlice > dims.iVolWidth)
+ endSlice = dims.iVolWidth;
+
+ float fV = 0.0f;
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ fV += tex2D(gT_FanVolumeTexture, fX, fY);
+ fY -= alpha;
+ fX += 1.0f;
+ }
+
+ fVal += fV * fDistCorr;
+
+ }
+
+ projData[angle*projPitch+detector+1] += fVal;
+}
+
+
+// projection for angles that are roughly vertical
+// (detector roughly horizontal)
+__global__ void FanFPvertical(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions dims, float outputScale)
+{
+ const int relDet = threadIdx.x;
+ const int relAngle = threadIdx.y;
+
+ const int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle;
+
+ if (angle >= endAngle)
+ return;
+
+ const int detector = blockIdx.y * g_detBlockSize + relDet;
+
+ if (detector < 0 || detector >= dims.iProjDets)
+ return;
+
+ float* projData = (float*)D_projData;
+
+ const float fSrcX = gC_SrcX[angle];
+ const float fSrcY = gC_SrcY[angle];
+ const float fDetSX = gC_DetSX[angle];
+ const float fDetSY = gC_DetSY[angle];
+ const float fDetUX = gC_DetUX[angle];
+ const float fDetUY = gC_DetUY[angle];
+
+ float fVal = 0.0f;
+
+ const float fdx = fabsf(fDetSX + detector*fDetUX + 0.5f - fSrcX);
+ const float fdy = fabsf(fDetSY + detector*fDetUY + 0.5f - fSrcY);
+
+ if (fdy <= fdx)
+ return;
+
+
+ for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) {
+ const float fDet = detector + (0.5f + iSubT) / dims.iRaysPerDet /*- gC_angle_offset[angle]*/;
+
+ const float fDetX = fDetSX + fDet * fDetUX;
+ const float fDetY = fDetSY + fDet * fDetUY;
+
+ // ray: x = alpha * y + beta
+ const float alpha = (fSrcX - fDetX) / (fSrcY - fDetY);
+ const float beta = fSrcX - alpha * fSrcY;
+
+ const float fDistCorr = sqrt(alpha*alpha+1) * outputScale / dims.iRaysPerDet;
+
+ // intersect ray with first slice
+
+ float fX = -alpha * (startSlice - 0.5f*dims.iVolHeight + 0.5f) + beta + 0.5f*dims.iVolWidth - 0.5f + 1.5f;
+ float fY = startSlice + 1.5f;
+
+ int endSlice = startSlice + g_blockSlices;
+ if (endSlice > dims.iVolHeight)
+ endSlice = dims.iVolHeight;
+
+ float fV = 0.0f;
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ fV += tex2D(gT_FanVolumeTexture, fX, fY);
+ fX -= alpha;
+ fY += 1.0f;
+ }
+
+ fVal += fV * fDistCorr;
+
+ }
+
+ projData[angle*projPitch+detector+1] += fVal;
+}
+
+bool FanFP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const SFanProjection* angles,
+ float outputScale)
+{
+ // TODO: load angles into constant memory in smaller blocks
+ assert(dims.iProjAngles <= g_MaxAngles);
+
+ cudaArray* D_dataArray;
+ bindVolumeDataTexture(D_volumeData, D_dataArray, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+ // transfer angles to constant memory
+ float* tmp = new float[dims.iProjAngles];
+
+#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
+
+ TRANSFER_TO_CONSTANT(SrcX);
+ TRANSFER_TO_CONSTANT(SrcY);
+ TRANSFER_TO_CONSTANT(DetSX);
+ TRANSFER_TO_CONSTANT(DetSY);
+ TRANSFER_TO_CONSTANT(DetUX);
+ TRANSFER_TO_CONSTANT(DetUY);
+
+#undef TRANSFER_TO_CONSTANT
+
+ delete[] tmp;
+
+ dim3 dimBlock(g_detBlockSize, g_anglesPerBlock); // region size, angles
+ const unsigned int g_blockSliceSize = g_detBlockSize;
+
+ std::list<cudaStream_t> streams;
+
+
+ unsigned int blockStart = 0;
+ unsigned int blockEnd = dims.iProjAngles;
+
+ dim3 dimGrid((blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock,
+ (dims.iProjDets+g_blockSliceSize-1)/g_blockSliceSize); // angle blocks, regions
+ cudaStream_t stream1;
+ cudaStreamCreate(&stream1);
+ streams.push_back(stream1);
+ for (unsigned int i = 0; i < dims.iVolWidth; i += g_blockSlices)
+ FanFPhorizontal<<<dimGrid, dimBlock, 0, stream1>>>(D_projData, projPitch, i, blockStart, blockEnd, dims, outputScale);
+
+ cudaStream_t stream2;
+ cudaStreamCreate(&stream2);
+ streams.push_back(stream2);
+ for (unsigned int i = 0; i < dims.iVolHeight; i += g_blockSlices)
+ FanFPvertical<<<dimGrid, dimBlock, 0, stream2>>>(D_projData, projPitch, i, blockStart, blockEnd, dims, outputScale);
+
+ cudaStreamDestroy(stream1);
+ cudaStreamDestroy(stream2);
+
+ cudaThreadSynchronize();
+
+ cudaTextForceKernelsCompletion();
+
+ cudaFreeArray(D_dataArray);
+
+ return true;
+}
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA;
+
+int main()
+{
+ float* D_volumeData;
+ float* D_projData;
+
+ SDimensions dims;
+ dims.iVolWidth = 128;
+ dims.iVolHeight = 128;
+ dims.iProjAngles = 180;
+ dims.iProjDets = 256;
+ dims.fDetScale = 1.0f;
+ dims.iRaysPerDet = 1;
+ unsigned int volumePitch, projPitch;
+
+ SFanProjection projs[180];
+
+ projs[0].fSrcX = 0.0f;
+ projs[0].fSrcY = 1536.0f;
+ projs[0].fDetSX = 128.0f;
+ projs[0].fDetSY = -512.0f;
+ projs[0].fDetUX = -1.0f;
+ projs[0].fDetUY = 0.0f;
+
+#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = projs[0].f##name##X * cos(alpha) - projs[0].f##name##Y * sin(alpha); projs[i].f##name##Y = projs[0].f##name##X * sin(alpha) + projs[0].f##name##Y * cos(alpha); } while(0)
+
+ for (int i = 1; i < 180; ++i) {
+ ROTATE0(Src, i, i*2*M_PI/180);
+ ROTATE0(DetS, i, i*2*M_PI/180);
+ ROTATE0(DetU, i, i*2*M_PI/180);
+ }
+
+#undef ROTATE0
+
+ allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ printf("pitch: %u\n", volumePitch);
+
+ allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch);
+ printf("pitch: %u\n", projPitch);
+
+ unsigned int y, x;
+ float* img = loadImage("phantom128.png", y, x);
+
+ float* sino = new float[dims.iProjAngles * dims.iProjDets];
+
+ memset(sino, 0, dims.iProjAngles * dims.iProjDets * sizeof(float));
+
+ copyVolumeToDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+ copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch);
+
+ float* angle = new float[dims.iProjAngles];
+
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i)
+ angle[i] = i*(M_PI/dims.iProjAngles);
+
+ FanFP(D_volumeData, volumePitch, D_projData, projPitch, dims, projs, 1.0f);
+
+ delete[] angle;
+
+ copySinogramFromDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch);
+
+ float s = 0.0f;
+ for (unsigned int y = 0; y < dims.iProjAngles; ++y)
+ for (unsigned int x = 0; x < dims.iProjDets; ++x)
+ s += sino[y*dims.iProjDets+x] * sino[y*dims.iProjDets+x];
+ printf("cpu norm: %f\n", s);
+
+ //zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles);
+ s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0);
+ printf("gpu norm: %f\n", s);
+
+ saveImage("sino.png",dims.iProjAngles,dims.iProjDets,sino);
+
+
+ return 0;
+}
+#endif
diff --git a/cuda/2d/fan_fp.h b/cuda/2d/fan_fp.h
new file mode 100644
index 0000000..0734f40
--- /dev/null
+++ b/cuda/2d/fan_fp.h
@@ -0,0 +1,41 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_FAN_FP_H
+#define _CUDA_FAN_FP_H
+
+namespace astraCUDA {
+
+_AstraExport bool FanFP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const SFanProjection* angles,
+ float outputScale);
+
+}
+
+#endif
diff --git a/cuda/2d/fbp_filters.h b/cuda/2d/fbp_filters.h
new file mode 100644
index 0000000..1232f8e
--- /dev/null
+++ b/cuda/2d/fbp_filters.h
@@ -0,0 +1,58 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef FBP_FILTERS_H
+#define FBP_FILTERS_H
+
+enum E_FBPFILTER
+{
+ FILTER_NONE, //< no filter (regular BP)
+ FILTER_RAMLAK, //< default FBP filter
+ FILTER_SHEPPLOGAN, //< Shepp-Logan
+ FILTER_COSINE, //< Cosine
+ FILTER_HAMMING, //< Hamming filter
+ FILTER_HANN, //< Hann filter
+ FILTER_TUKEY, //< Tukey filter
+ FILTER_LANCZOS, //< Lanczos filter
+ FILTER_TRIANGULAR, //< Triangular filter
+ FILTER_GAUSSIAN, //< Gaussian filter
+ FILTER_BARTLETTHANN, //< Bartlett-Hann filter
+ FILTER_BLACKMAN, //< Blackman filter
+ FILTER_NUTTALL, //< Nuttall filter, continuous first derivative
+ FILTER_BLACKMANHARRIS, //< Blackman-Harris filter
+ FILTER_BLACKMANNUTTALL, //< Blackman-Nuttall filter
+ FILTER_FLATTOP, //< Flat top filter
+ FILTER_KAISER, //< Kaiser filter
+ FILTER_PARZEN, //< Parzen filter
+ FILTER_PROJECTION, //< all projection directions share one filter
+ FILTER_SINOGRAM, //< every projection direction has its own filter
+ FILTER_RPROJECTION, //< projection filter in real space (as opposed to fourier space)
+ FILTER_RSINOGRAM, //< sinogram filter in real space
+};
+
+#endif /* FBP_FILTERS_H */
diff --git a/cuda/2d/fft.cu b/cuda/2d/fft.cu
new file mode 100644
index 0000000..79e4be7
--- /dev/null
+++ b/cuda/2d/fft.cu
@@ -0,0 +1,873 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "fft.h"
+#include "util.h"
+
+#include <cufft.h>
+#include <iostream>
+#include <cuda.h>
+#include <fstream>
+
+#include "../../include/astra/Logger.h"
+
+using namespace astra;
+
+// TODO: evaluate what we want to do in these situations:
+
+#define CHECK_ERROR(errorMessage) do { \
+ cudaError_t err = cudaThreadSynchronize(); \
+ if( cudaSuccess != err) { \
+ fprintf(stderr, "Cuda error: %s in file '%s' in line %i : %s.\n", \
+ errorMessage, __FILE__, __LINE__, cudaGetErrorString( err) );\
+ CLogger::writeTerminalCUDAError(__FILE__, __LINE__, cudaGetErrorString( err)); \
+ exit(EXIT_FAILURE); \
+ } } while (0)
+
+#define SAFE_CALL( call) do { \
+ cudaError err = call; \
+ if( cudaSuccess != err) { \
+ fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n", \
+ __FILE__, __LINE__, cudaGetErrorString( err) ); \
+ CLogger::writeTerminalCUDAError(__FILE__, __LINE__, cudaGetErrorString( err)); \
+ exit(EXIT_FAILURE); \
+ } \
+ err = cudaThreadSynchronize(); \
+ if( cudaSuccess != err) { \
+ fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n", \
+ __FILE__, __LINE__, cudaGetErrorString( err) ); \
+ CLogger::writeTerminalCUDAError(__FILE__, __LINE__, cudaGetErrorString( err)); \
+ exit(EXIT_FAILURE); \
+ } } while (0)
+
+
+__global__ static void applyFilter_kernel(int _iProjectionCount,
+ int _iFreqBinCount,
+ cufftComplex * _pSinogram,
+ cufftComplex * _pFilter)
+{
+ int iIndex = threadIdx.x + blockIdx.x * blockDim.x;
+ int iProjectionIndex = iIndex / _iFreqBinCount;
+
+ if(iProjectionIndex >= _iProjectionCount)
+ {
+ return;
+ }
+
+ float fA = _pSinogram[iIndex].x;
+ float fB = _pSinogram[iIndex].y;
+ float fC = _pFilter[iIndex].x;
+ float fD = _pFilter[iIndex].y;
+
+ _pSinogram[iIndex].x = fA * fC - fB * fD;
+ _pSinogram[iIndex].y = fA * fD + fC * fB;
+}
+
+__global__ static void rescaleInverseFourier_kernel(int _iProjectionCount,
+ int _iDetectorCount,
+ float* _pfInFourierOutput)
+{
+ int iIndex = threadIdx.x + blockIdx.x * blockDim.x;
+ int iProjectionIndex = iIndex / _iDetectorCount;
+ int iDetectorIndex = iIndex % _iDetectorCount;
+
+ if(iProjectionIndex >= _iProjectionCount)
+ {
+ return;
+ }
+
+ _pfInFourierOutput[iProjectionIndex * _iDetectorCount + iDetectorIndex] /= (float)_iDetectorCount;
+}
+
+static void rescaleInverseFourier(int _iProjectionCount, int _iDetectorCount,
+ float * _pfInFourierOutput)
+{
+ const int iBlockSize = 256;
+ int iElementCount = _iProjectionCount * _iDetectorCount;
+ int iBlockCount = (iElementCount + iBlockSize - 1) / iBlockSize;
+
+ rescaleInverseFourier_kernel<<< iBlockCount, iBlockSize >>>(_iProjectionCount,
+ _iDetectorCount,
+ _pfInFourierOutput);
+ CHECK_ERROR("rescaleInverseFourier_kernel failed");
+}
+
+void applyFilter(int _iProjectionCount, int _iFreqBinCount,
+ cufftComplex * _pSinogram, cufftComplex * _pFilter)
+{
+ const int iBlockSize = 256;
+ int iElementCount = _iProjectionCount * _iFreqBinCount;
+ int iBlockCount = (iElementCount + iBlockSize - 1) / iBlockSize;
+
+ applyFilter_kernel<<< iBlockCount, iBlockSize >>>(_iProjectionCount,
+ _iFreqBinCount,
+ _pSinogram, _pFilter);
+ CHECK_ERROR("applyFilter_kernel failed");
+}
+
+static bool invokeCudaFFT(int _iProjectionCount, int _iDetectorCount,
+ const float * _pfDevSource,
+ cufftComplex * _pDevTargetComplex)
+{
+ cufftHandle plan;
+ cufftResult result;
+
+ result = cufftPlan1d(&plan, _iDetectorCount, CUFFT_R2C, _iProjectionCount);
+ if(result != CUFFT_SUCCESS)
+ {
+ std::cerr << "Failed to plan 1d r2c fft" << std::endl;
+ return false;
+ }
+
+ result = cufftExecR2C(plan, (cufftReal *)_pfDevSource, _pDevTargetComplex);
+ cufftDestroy(plan);
+
+ if(result != CUFFT_SUCCESS)
+ {
+ std::cerr << "Failed to exec 1d r2c fft" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+static bool invokeCudaIFFT(int _iProjectionCount, int _iDetectorCount,
+ const cufftComplex * _pDevSourceComplex,
+ float * _pfDevTarget)
+{
+ cufftHandle plan;
+ cufftResult result;
+
+ result = cufftPlan1d(&plan, _iDetectorCount, CUFFT_C2R, _iProjectionCount);
+ if(result != CUFFT_SUCCESS)
+ {
+ std::cerr << "Failed to plan 1d c2r fft" << std::endl;
+ return false;
+ }
+
+ // todo: why do we have to get rid of the const qualifier?
+ result = cufftExecC2R(plan, (cufftComplex *)_pDevSourceComplex,
+ (cufftReal *)_pfDevTarget);
+ cufftDestroy(plan);
+
+ if(result != CUFFT_SUCCESS)
+ {
+ std::cerr << "Failed to exec 1d c2r fft" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool allocateComplexOnDevice(int _iProjectionCount, int _iDetectorCount,
+ cufftComplex ** _ppDevComplex)
+{
+ size_t bufferSize = sizeof(cufftComplex) * _iProjectionCount * _iDetectorCount;
+ SAFE_CALL(cudaMalloc((void **)_ppDevComplex, bufferSize));
+ return true;
+}
+
+bool freeComplexOnDevice(cufftComplex * _pDevComplex)
+{
+ SAFE_CALL(cudaFree(_pDevComplex));
+ return true;
+}
+
+bool uploadComplexArrayToDevice(int _iProjectionCount, int _iDetectorCount,
+ cufftComplex * _pHostComplexSource,
+ cufftComplex * _pDevComplexTarget)
+{
+ size_t memSize = sizeof(cufftComplex) * _iProjectionCount * _iDetectorCount;
+ SAFE_CALL(cudaMemcpy(_pDevComplexTarget, _pHostComplexSource, memSize, cudaMemcpyHostToDevice));
+
+ return true;
+}
+
+bool runCudaFFT(int _iProjectionCount, const float * _pfDevRealSource,
+ int _iSourcePitch, int _iSourcePadX, int _iProjDets,
+ int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount,
+ cufftComplex * _pDevTargetComplex)
+{
+ float * pfDevRealFFTSource = NULL;
+ size_t bufferMemSize = sizeof(float) * _iProjectionCount * _iFFTRealDetectorCount;
+
+ SAFE_CALL(cudaMalloc((void **)&pfDevRealFFTSource, bufferMemSize));
+ SAFE_CALL(cudaMemset(pfDevRealFFTSource, 0, bufferMemSize));
+
+ for(int iProjectionIndex = 0; iProjectionIndex < _iProjectionCount; iProjectionIndex++)
+ {
+ const float * pfSourceLocation = _pfDevRealSource + iProjectionIndex * _iSourcePitch + _iSourcePadX;
+ float * pfTargetLocation = pfDevRealFFTSource + iProjectionIndex * _iFFTRealDetectorCount;
+
+ SAFE_CALL(cudaMemcpy(pfTargetLocation, pfSourceLocation, sizeof(float) * _iProjDets, cudaMemcpyDeviceToDevice));
+ }
+
+ bool bResult = invokeCudaFFT(_iProjectionCount, _iFFTRealDetectorCount,
+ pfDevRealFFTSource, _pDevTargetComplex);
+ if(!bResult)
+ {
+ return false;
+ }
+
+ SAFE_CALL(cudaFree(pfDevRealFFTSource));
+
+ return true;
+}
+
+bool runCudaIFFT(int _iProjectionCount, const cufftComplex* _pDevSourceComplex,
+ float * _pfRealTarget,
+ int _iTargetPitch, int _iTargetPadX, int _iProjDets,
+ int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount)
+{
+ float * pfDevRealFFTTarget = NULL;
+ size_t bufferMemSize = sizeof(float) * _iProjectionCount * _iFFTRealDetectorCount;
+
+ SAFE_CALL(cudaMalloc((void **)&pfDevRealFFTTarget, bufferMemSize));
+
+ bool bResult = invokeCudaIFFT(_iProjectionCount, _iFFTRealDetectorCount,
+ _pDevSourceComplex, pfDevRealFFTTarget);
+ if(!bResult)
+ {
+ return false;
+ }
+
+ rescaleInverseFourier(_iProjectionCount, _iFFTRealDetectorCount,
+ pfDevRealFFTTarget);
+
+ SAFE_CALL(cudaMemset(_pfRealTarget, 0, sizeof(float) * _iProjectionCount * _iTargetPitch));
+
+ for(int iProjectionIndex = 0; iProjectionIndex < _iProjectionCount; iProjectionIndex++)
+ {
+ const float * pfSourceLocation = pfDevRealFFTTarget + iProjectionIndex * _iFFTRealDetectorCount;
+ float* pfTargetLocation = _pfRealTarget + iProjectionIndex * _iTargetPitch + _iTargetPadX;
+
+ SAFE_CALL(cudaMemcpy(pfTargetLocation, pfSourceLocation, sizeof(float) * _iProjDets, cudaMemcpyDeviceToDevice));
+ }
+
+ SAFE_CALL(cudaFree(pfDevRealFFTTarget));
+
+ return true;
+}
+
+
+// Because the input is real, the Fourier transform is symmetric.
+// CUFFT only outputs the first half (ignoring the redundant second half),
+// and expects the same as input for the IFFT.
+int calcFFTFourSize(int _iFFTRealSize)
+{
+ int iFFTFourSize = _iFFTRealSize / 2 + 1;
+
+ return iFFTFourSize;
+}
+
+void genIdenFilter(int _iProjectionCount, cufftComplex * _pFilter,
+ int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount)
+{
+ for(int iProjectionIndex = 0; iProjectionIndex < _iProjectionCount; iProjectionIndex++)
+ {
+ for(int iDetectorIndex = 0; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ int iIndex = iDetectorIndex + iProjectionIndex * _iFFTFourierDetectorCount;
+ _pFilter[iIndex].x = 1.0f;
+ _pFilter[iIndex].y = 0.0f;
+ }
+ }
+}
+
+void genFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount,
+ cufftComplex * _pFilter, int _iFFTRealDetectorCount,
+ int _iFFTFourierDetectorCount, float _fParameter /* = -1.0f */)
+{
+ float * pfFilt = new float[_iFFTFourierDetectorCount];
+ float * pfW = new float[_iFFTFourierDetectorCount];
+
+ for(int iDetectorIndex = 0; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fRelIndex = (float)iDetectorIndex / (float)_iFFTRealDetectorCount;
+
+ // filt = 2*( 0:(order/2) )./order;
+ pfFilt[iDetectorIndex] = 2.0f * fRelIndex;
+ //pfFilt[iDetectorIndex] = 1.0f;
+
+ // w = 2*pi*(0:size(filt,2)-1)/order
+ pfW[iDetectorIndex] = 3.1415f * 2.0f * fRelIndex;
+ }
+
+ switch(_eFilter)
+ {
+ case FILTER_RAMLAK:
+ {
+ // do nothing
+ break;
+ }
+ case FILTER_SHEPPLOGAN:
+ {
+ // filt(2:end) = filt(2:end) .* (sin(w(2:end)/(2*d))./(w(2:end)/(2*d)))
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ pfFilt[iDetectorIndex] = pfFilt[iDetectorIndex] * (sinf(pfW[iDetectorIndex] / 2.0f / _fD) / (pfW[iDetectorIndex] / 2.0f / _fD));
+ }
+ break;
+ }
+ case FILTER_COSINE:
+ {
+ // filt(2:end) = filt(2:end) .* cos(w(2:end)/(2*d))
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ pfFilt[iDetectorIndex] = pfFilt[iDetectorIndex] * cosf(pfW[iDetectorIndex] / 2.0f / _fD);
+ }
+ break;
+ }
+ case FILTER_HAMMING:
+ {
+ // filt(2:end) = filt(2:end) .* (.54 + .46 * cos(w(2:end)/d))
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ pfFilt[iDetectorIndex] = pfFilt[iDetectorIndex] * ( 0.54f + 0.46f * cosf(pfW[iDetectorIndex] / _fD));
+ }
+ break;
+ }
+ case FILTER_HANN:
+ {
+ // filt(2:end) = filt(2:end) .*(1+cos(w(2:end)./d)) / 2
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ pfFilt[iDetectorIndex] = pfFilt[iDetectorIndex] * (1.0f + cosf(pfW[iDetectorIndex] / _fD)) / 2.0f;
+ }
+ break;
+ }
+ case FILTER_TUKEY:
+ {
+ float fAlpha = _fParameter;
+ if(_fParameter < 0.0f) fAlpha = 0.5f;
+ float fN = (float)_iFFTFourierDetectorCount;
+ float fHalfN = fN / 2.0f;
+ float fEnumTerm = fAlpha * fHalfN;
+ float fDenom = (1.0f - fAlpha) * fHalfN;
+ float fBlockStart = fHalfN - fEnumTerm;
+ float fBlockEnd = fHalfN + fEnumTerm;
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fAbsSmallN = fabs((float)iDetectorIndex);
+ float fStoredValue = 0.0f;
+
+ if((fBlockStart <= fAbsSmallN) && (fAbsSmallN <= fBlockEnd))
+ {
+ fStoredValue = 1.0f;
+ }
+ else
+ {
+ float fEnum = fAbsSmallN - fEnumTerm;
+ float fCosInput = M_PI * fEnum / fDenom;
+ fStoredValue = 0.5f * (1.0f + cosf(fCosInput));
+ }
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_LANCZOS:
+ {
+ float fDenum = (float)(_iFFTFourierDetectorCount - 1);
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fX = 2.0f * fSmallN / fDenum - 1.0f;
+ float fSinInput = M_PI * fX;
+ float fStoredValue = 0.0f;
+
+ if(fabsf(fSinInput) > 0.001f)
+ {
+ fStoredValue = sin(fSinInput)/fSinInput;
+ }
+ else
+ {
+ fStoredValue = 1.0f;
+ }
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_TRIANGULAR:
+ {
+ float fNMinusOne = (float)(_iFFTFourierDetectorCount - 1);
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fAbsInput = fSmallN - fNMinusOne / 2.0f;
+ float fParenInput = fNMinusOne / 2.0f - fabsf(fAbsInput);
+ float fStoredValue = 2.0f / fNMinusOne * fParenInput;
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_GAUSSIAN:
+ {
+ float fSigma = _fParameter;
+ if(_fParameter < 0.0f) fSigma = 0.4f;
+ float fN = (float)_iFFTFourierDetectorCount;
+ float fQuotient = (fN - 1.0f) / 2.0f;
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fEnum = fSmallN - fQuotient;
+ float fDenom = fSigma * fQuotient;
+ float fPower = -0.5f * (fEnum / fDenom) * (fEnum / fDenom);
+ float fStoredValue = expf(fPower);
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_BARTLETTHANN:
+ {
+ const float fA0 = 0.62f;
+ const float fA1 = 0.48f;
+ const float fA2 = 0.38f;
+ float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f;
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fAbsInput = fSmallN / fNMinusOne - 0.5f;
+ float fFirstTerm = fA1 * fabsf(fAbsInput);
+ float fCosInput = 2.0f * M_PI * fSmallN / fNMinusOne;
+ float fSecondTerm = fA2 * cosf(fCosInput);
+ float fStoredValue = fA0 - fFirstTerm - fSecondTerm;
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_BLACKMAN:
+ {
+ float fAlpha = _fParameter;
+ if(_fParameter < 0.0f) fAlpha = 0.16f;
+ float fA0 = (1.0f - fAlpha) / 2.0f;
+ float fA1 = 0.5f;
+ float fA2 = fAlpha / 2.0f;
+ float fNMinusOne = (float)(_iFFTFourierDetectorCount - 1);
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fCosInput1 = 2.0f * M_PI * 0.5f * fSmallN / fNMinusOne;
+ float fCosInput2 = 4.0f * M_PI * 0.5f * fSmallN / fNMinusOne;
+ float fStoredValue = fA0 - fA1 * cosf(fCosInput1) + fA2 * cosf(fCosInput2);
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_NUTTALL:
+ {
+ const float fA0 = 0.355768f;
+ const float fA1 = 0.487396f;
+ const float fA2 = 0.144232f;
+ const float fA3 = 0.012604f;
+ float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f;
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fBaseCosInput = M_PI * fSmallN / fNMinusOne;
+ float fFirstTerm = fA1 * cosf(2.0f * fBaseCosInput);
+ float fSecondTerm = fA2 * cosf(4.0f * fBaseCosInput);
+ float fThirdTerm = fA3 * cosf(6.0f * fBaseCosInput);
+ float fStoredValue = fA0 - fFirstTerm + fSecondTerm - fThirdTerm;
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_BLACKMANHARRIS:
+ {
+ const float fA0 = 0.35875f;
+ const float fA1 = 0.48829f;
+ const float fA2 = 0.14128f;
+ const float fA3 = 0.01168f;
+ float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f;
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fBaseCosInput = M_PI * fSmallN / fNMinusOne;
+ float fFirstTerm = fA1 * cosf(2.0f * fBaseCosInput);
+ float fSecondTerm = fA2 * cosf(4.0f * fBaseCosInput);
+ float fThirdTerm = fA3 * cosf(6.0f * fBaseCosInput);
+ float fStoredValue = fA0 - fFirstTerm + fSecondTerm - fThirdTerm;
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_BLACKMANNUTTALL:
+ {
+ const float fA0 = 0.3635819f;
+ const float fA1 = 0.4891775f;
+ const float fA2 = 0.1365995f;
+ const float fA3 = 0.0106411f;
+ float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f;
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fBaseCosInput = M_PI * fSmallN / fNMinusOne;
+ float fFirstTerm = fA1 * cosf(2.0f * fBaseCosInput);
+ float fSecondTerm = fA2 * cosf(4.0f * fBaseCosInput);
+ float fThirdTerm = fA3 * cosf(6.0f * fBaseCosInput);
+ float fStoredValue = fA0 - fFirstTerm + fSecondTerm - fThirdTerm;
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_FLATTOP:
+ {
+ const float fA0 = 1.0f;
+ const float fA1 = 1.93f;
+ const float fA2 = 1.29f;
+ const float fA3 = 0.388f;
+ const float fA4 = 0.032f;
+ float fNMinusOne = (float)(_iFFTFourierDetectorCount) - 1.0f;
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fBaseCosInput = M_PI * fSmallN / fNMinusOne;
+ float fFirstTerm = fA1 * cosf(2.0f * fBaseCosInput);
+ float fSecondTerm = fA2 * cosf(4.0f * fBaseCosInput);
+ float fThirdTerm = fA3 * cosf(6.0f * fBaseCosInput);
+ float fFourthTerm = fA4 * cosf(8.0f * fBaseCosInput);
+ float fStoredValue = fA0 - fFirstTerm + fSecondTerm - fThirdTerm + fFourthTerm;
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_KAISER:
+ {
+ float fAlpha = _fParameter;
+ if(_fParameter < 0.0f) fAlpha = 3.0f;
+ float fPiTimesAlpha = M_PI * fAlpha;
+ float fNMinusOne = (float)(_iFFTFourierDetectorCount - 1);
+ float fDenom = (float)j0((double)fPiTimesAlpha);
+
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fSquareInput = 2.0f * fSmallN / fNMinusOne - 1;
+ float fSqrtInput = 1.0f - fSquareInput * fSquareInput;
+ float fBesselInput = fPiTimesAlpha * sqrt(fSqrtInput);
+ float fEnum = (float)j0((double)fBesselInput);
+ float fStoredValue = fEnum / fDenom;
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ case FILTER_PARZEN:
+ {
+ for(int iDetectorIndex = 1; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fSmallN = (float)iDetectorIndex;
+ float fQ = fSmallN / (float)(_iFFTFourierDetectorCount - 1);
+ float fStoredValue = 0.0f;
+
+ if(fQ <= 0.5f)
+ {
+ fStoredValue = 1.0f - 6.0f * fQ * fQ * (1.0f - fQ);
+ }
+ else
+ {
+ float fCubedValue = 1.0f - fQ;
+ fStoredValue = 2.0f * fCubedValue * fCubedValue * fCubedValue;
+ }
+
+ pfFilt[iDetectorIndex] *= fStoredValue;
+ }
+
+ break;
+ }
+ default:
+ {
+ std::cerr << "Cannot serve requested filter" << std::endl;
+ }
+ }
+
+ // filt(w>pi*d) = 0;
+ float fPiTimesD = M_PI * _fD;
+ for(int iDetectorIndex = 0; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fWValue = pfW[iDetectorIndex];
+
+ if(fWValue > fPiTimesD)
+ {
+ pfFilt[iDetectorIndex] = 0.0f;
+ }
+ }
+
+ for(int iDetectorIndex = 0; iDetectorIndex < _iFFTFourierDetectorCount; iDetectorIndex++)
+ {
+ float fFilterValue = pfFilt[iDetectorIndex];
+
+ for(int iProjectionIndex = 0; iProjectionIndex < _iProjectionCount; iProjectionIndex++)
+ {
+ int iIndex = iDetectorIndex + iProjectionIndex * _iFFTFourierDetectorCount;
+ _pFilter[iIndex].x = fFilterValue;
+ _pFilter[iIndex].y = 0.0f;
+ }
+ }
+
+ delete[] pfFilt;
+ delete[] pfW;
+}
+
+#ifdef STANDALONE
+
+__global__ static void doubleFourierOutput_kernel(int _iProjectionCount,
+ int _iDetectorCount,
+ cufftComplex* _pFourierOutput)
+{
+ int iIndex = threadIdx.x + blockIdx.x * blockDim.x;
+ int iProjectionIndex = iIndex / _iDetectorCount;
+ int iDetectorIndex = iIndex % _iDetectorCount;
+
+ if(iProjectionIndex >= _iProjectionCount)
+ {
+ return;
+ }
+
+ if(iDetectorIndex <= (_iDetectorCount / 2))
+ {
+ return;
+ }
+
+ int iOtherDetectorIndex = _iDetectorCount - iDetectorIndex;
+
+ _pFourierOutput[iProjectionIndex * _iDetectorCount + iDetectorIndex].x = _pFourierOutput[iProjectionIndex * _iDetectorCount + iOtherDetectorIndex].x;
+ _pFourierOutput[iProjectionIndex * _iDetectorCount + iDetectorIndex].y = -_pFourierOutput[iProjectionIndex * _iDetectorCount + iOtherDetectorIndex].y;
+}
+
+static void doubleFourierOutput(int _iProjectionCount, int _iDetectorCount,
+ cufftComplex * _pFourierOutput)
+{
+ const int iBlockSize = 256;
+ int iElementCount = _iProjectionCount * _iDetectorCount;
+ int iBlockCount = (iElementCount + iBlockSize - 1) / iBlockSize;
+
+ doubleFourierOutput_kernel<<< iBlockCount, iBlockSize >>>(_iProjectionCount,
+ _iDetectorCount,
+ _pFourierOutput);
+ CHECK_ERROR("doubleFourierOutput_kernel failed");
+}
+
+
+
+static void writeToMatlabFile(const char * _fileName, const float * _pfData,
+ int _iRowCount, int _iColumnCount)
+{
+ std::ofstream out(_fileName);
+
+ for(int iRowIndex = 0; iRowIndex < _iRowCount; iRowIndex++)
+ {
+ for(int iColumnIndex = 0; iColumnIndex < _iColumnCount; iColumnIndex++)
+ {
+ out << _pfData[iColumnIndex + iRowIndex * _iColumnCount] << " ";
+ }
+
+ out << std::endl;
+ }
+}
+
+static void convertComplexToRealImg(const cufftComplex * _pComplex,
+ int _iElementCount,
+ float * _pfReal, float * _pfImaginary)
+{
+ for(int iIndex = 0; iIndex < _iElementCount; iIndex++)
+ {
+ _pfReal[iIndex] = _pComplex[iIndex].x;
+ _pfImaginary[iIndex] = _pComplex[iIndex].y;
+ }
+}
+
+void testCudaFFT()
+{
+ const int iProjectionCount = 2;
+ const int iDetectorCount = 1024;
+ const int iTotalElementCount = iProjectionCount * iDetectorCount;
+
+ float * pfHostProj = new float[iTotalElementCount];
+ memset(pfHostProj, 0, sizeof(float) * iTotalElementCount);
+
+ for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
+ {
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorCount; iDetectorIndex++)
+ {
+// int
+
+// pfHostProj[iIndex] = (float)rand() / (float)RAND_MAX;
+ }
+ }
+
+ writeToMatlabFile("proj.mat", pfHostProj, iProjectionCount, iDetectorCount);
+
+ float * pfDevProj = NULL;
+ SAFE_CALL(cudaMalloc((void **)&pfDevProj, sizeof(float) * iTotalElementCount));
+ SAFE_CALL(cudaMemcpy(pfDevProj, pfHostProj, sizeof(float) * iTotalElementCount, cudaMemcpyHostToDevice));
+
+ cufftComplex * pDevFourProj = NULL;
+ SAFE_CALL(cudaMalloc((void **)&pDevFourProj, sizeof(cufftComplex) * iTotalElementCount));
+
+ cufftHandle plan;
+ cufftResult result;
+
+ result = cufftPlan1d(&plan, iDetectorCount, CUFFT_R2C, iProjectionCount);
+ if(result != CUFFT_SUCCESS)
+ {
+ cerr << "Failed to plan 1d r2c fft" << endl;
+ }
+
+ result = cufftExecR2C(plan, pfDevProj, pDevFourProj);
+ if(result != CUFFT_SUCCESS)
+ {
+ cerr << "Failed to exec 1d r2c fft" << endl;
+ }
+
+ cufftDestroy(plan);
+
+ doubleFourierOutput(iProjectionCount, iDetectorCount, pDevFourProj);
+
+ cufftComplex * pHostFourProj = new cufftComplex[iTotalElementCount];
+ SAFE_CALL(cudaMemcpy(pHostFourProj, pDevFourProj, sizeof(cufftComplex) * iTotalElementCount, cudaMemcpyDeviceToHost));
+
+ float * pfHostFourProjReal = new float[iTotalElementCount];
+ float * pfHostFourProjImaginary = new float[iTotalElementCount];
+
+ convertComplexToRealImg(pHostFourProj, iTotalElementCount, pfHostFourProjReal, pfHostFourProjImaginary);
+
+ writeToMatlabFile("proj_four_real.mat", pfHostFourProjReal, iProjectionCount, iDetectorCount);
+ writeToMatlabFile("proj_four_imaginary.mat", pfHostFourProjImaginary, iProjectionCount, iDetectorCount);
+
+ float * pfDevInFourProj = NULL;
+ SAFE_CALL(cudaMalloc((void **)&pfDevInFourProj, sizeof(float) * iTotalElementCount));
+
+ result = cufftPlan1d(&plan, iDetectorCount, CUFFT_C2R, iProjectionCount);
+ if(result != CUFFT_SUCCESS)
+ {
+ cerr << "Failed to plan 1d c2r fft" << endl;
+ }
+
+ result = cufftExecC2R(plan, pDevFourProj, pfDevInFourProj);
+ if(result != CUFFT_SUCCESS)
+ {
+ cerr << "Failed to exec 1d c2r fft" << endl;
+ }
+
+ cufftDestroy(plan);
+
+ rescaleInverseFourier(iProjectionCount, iDetectorCount, pfDevInFourProj);
+
+ float * pfHostInFourProj = new float[iTotalElementCount];
+ SAFE_CALL(cudaMemcpy(pfHostInFourProj, pfDevInFourProj, sizeof(float) * iTotalElementCount, cudaMemcpyDeviceToHost));
+
+ writeToMatlabFile("in_four.mat", pfHostInFourProj, iProjectionCount, iDetectorCount);
+
+ SAFE_CALL(cudaFree(pDevFourProj));
+ SAFE_CALL(cudaFree(pfDevProj));
+
+ delete [] pfHostInFourProj;
+ delete [] pfHostFourProjReal;
+ delete [] pfHostFourProjImaginary;
+ delete [] pfHostProj;
+ delete [] pHostFourProj;
+}
+
+void downloadDebugFilterComplex(float * _pfHostSinogram, int _iProjectionCount,
+ int _iDetectorCount,
+ cufftComplex * _pDevFilter,
+ int _iFilterDetCount)
+{
+ cufftComplex * pHostFilter = NULL;
+ size_t complMemSize = sizeof(cufftComplex) * _iFilterDetCount * _iProjectionCount;
+ pHostFilter = (cufftComplex *)malloc(complMemSize);
+ SAFE_CALL(cudaMemcpy(pHostFilter, _pDevFilter, complMemSize, cudaMemcpyDeviceToHost));
+
+ for(int iTargetProjIndex = 0; iTargetProjIndex < _iProjectionCount; iTargetProjIndex++)
+ {
+ for(int iTargetDetIndex = 0; iTargetDetIndex < min(_iDetectorCount, _iFilterDetCount); iTargetDetIndex++)
+ {
+ cufftComplex source = pHostFilter[iTargetDetIndex + iTargetProjIndex * _iFilterDetCount];
+ float fReadValue = sqrtf(source.x * source.x + source.y * source.y);
+ _pfHostSinogram[iTargetDetIndex + iTargetProjIndex * _iDetectorCount] = fReadValue;
+ }
+ }
+
+ free(pHostFilter);
+}
+
+void downloadDebugFilterReal(float * _pfHostSinogram, int _iProjectionCount,
+ int _iDetectorCount, float * _pfDevFilter,
+ int _iFilterDetCount)
+{
+ float * pfHostFilter = NULL;
+ size_t memSize = sizeof(float) * _iFilterDetCount * _iProjectionCount;
+ pfHostFilter = (float *)malloc(memSize);
+ SAFE_CALL(cudaMemcpy(pfHostFilter, _pfDevFilter, memSize, cudaMemcpyDeviceToHost));
+
+ for(int iTargetProjIndex = 0; iTargetProjIndex < _iProjectionCount; iTargetProjIndex++)
+ {
+ for(int iTargetDetIndex = 0; iTargetDetIndex < min(_iDetectorCount, _iFilterDetCount); iTargetDetIndex++)
+ {
+ float fSource = pfHostFilter[iTargetDetIndex + iTargetProjIndex * _iFilterDetCount];
+ _pfHostSinogram[iTargetDetIndex + iTargetProjIndex * _iDetectorCount] = fSource;
+ }
+ }
+
+ free(pfHostFilter);
+}
+
+
+#endif
diff --git a/cuda/2d/fft.h b/cuda/2d/fft.h
new file mode 100644
index 0000000..55324e5
--- /dev/null
+++ b/cuda/2d/fft.h
@@ -0,0 +1,69 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef FFT_H
+#define FFT_H
+
+#include <cufft.h>
+#include <cuda.h>
+
+#include "fbp_filters.h"
+
+bool allocateComplexOnDevice(int _iProjectionCount,
+ int _iDetectorCount,
+ cufftComplex ** _ppDevComplex);
+
+bool freeComplexOnDevice(cufftComplex * _pDevComplex);
+
+bool uploadComplexArrayToDevice(int _iProjectionCount, int _iDetectorCount,
+ cufftComplex * _pHostComplexSource,
+ cufftComplex * _pDevComplexTarget);
+
+bool runCudaFFT(int _iProjectionCount, const float * _pfDevRealSource,
+ int _iSourcePitch, int _iSourcePadX, int _iProjDets,
+ int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount,
+ cufftComplex * _pDevTargetComplex);
+
+bool runCudaIFFT(int _iProjectionCount, const cufftComplex* _pDevSourceComplex,
+ float * _pfRealTarget,
+ int _iTargetPitch, int _iTargetPadX, int _iProjDets,
+ int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount);
+
+void applyFilter(int _iProjectionCount, int _iFreqBinCount,
+ cufftComplex * _pSinogram, cufftComplex * _pFilter);
+
+int calcFFTFourSize(int _iFFTRealSize);
+
+void genFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount,
+ cufftComplex * _pFilter, int _iFFTRealDetectorCount,
+ int _iFFTFourierDetectorCount, float _fParameter = -1.0f);
+
+void genIdenFilter(int _iProjectionCount, cufftComplex * _pFilter,
+ int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount);
+
+#endif /* FFT_H */
diff --git a/cuda/2d/par_bp.cu b/cuda/2d/par_bp.cu
new file mode 100644
index 0000000..1057879
--- /dev/null
+++ b/cuda/2d/par_bp.cu
@@ -0,0 +1,357 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+
+#include "util.h"
+#include "arith.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+#define PIXELTRACE
+
+
+typedef texture<float, 2, cudaReadModeElementType> texture2D;
+
+static texture2D gT_projTexture;
+
+
+namespace astraCUDA {
+
+const unsigned int g_anglesPerBlock = 16;
+const unsigned int g_blockSliceSize = 32;
+const unsigned int g_blockSlices = 16;
+
+const unsigned int g_MaxAngles = 2560;
+
+__constant__ float gC_angle_sin[g_MaxAngles];
+__constant__ float gC_angle_cos[g_MaxAngles];
+__constant__ float gC_angle_offset[g_MaxAngles];
+
+static bool bindProjDataTexture(float* data, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+
+ gT_projTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_projTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_projTexture.filterMode = cudaFilterModeLinear;
+ gT_projTexture.normalized = false;
+
+ cudaBindTexture2D(0, gT_projTexture, (const void*)data, channelDesc, width, height, sizeof(float)*pitch);
+
+ // TODO: error value?
+
+ return true;
+}
+
+__global__ void devBP(float* D_volData, unsigned int volPitch, unsigned int startAngle, bool offsets, const SDimensions dims)
+{
+ const int relX = threadIdx.x;
+ const int relY = threadIdx.y;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+ const int X = blockIdx.x * g_blockSlices + relX;
+ const int Y = blockIdx.y * g_blockSliceSize + relY;
+
+ if (X >= dims.iVolWidth || Y >= dims.iVolHeight)
+ return;
+
+ const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f ) / dims.fDetScale;
+ const float fY = ( Y - 0.5f*dims.iVolHeight + 0.5f ) / dims.fDetScale;
+
+ float* volData = (float*)D_volData;
+
+ float fVal = 0.0f;
+ float fA = startAngle + 0.5f;
+ const float fT_base = 0.5f*dims.iProjDets - 0.5f + 1.5f;
+
+ if (offsets) {
+
+ for (int angle = startAngle; angle < endAngle; ++angle)
+ {
+ const float cos_theta = gC_angle_cos[angle];
+ const float sin_theta = gC_angle_sin[angle];
+ const float TOffset = gC_angle_offset[angle];
+
+ const float fT = fT_base + fX * cos_theta - fY * sin_theta + TOffset;
+ fVal += tex2D(gT_projTexture, fT, fA);
+ fA += 1.0f;
+ }
+
+ } else {
+
+ for (int angle = startAngle; angle < endAngle; ++angle)
+ {
+ const float cos_theta = gC_angle_cos[angle];
+ const float sin_theta = gC_angle_sin[angle];
+
+ const float fT = fT_base + fX * cos_theta - fY * sin_theta;
+ fVal += tex2D(gT_projTexture, fT, fA);
+ fA += 1.0f;
+ }
+
+ }
+
+ volData[(Y+1)*volPitch+X+1] += fVal;
+}
+
+// supersampling version
+__global__ void devBP_SS(float* D_volData, unsigned int volPitch, unsigned int startAngle, bool offsets, const SDimensions dims)
+{
+ const int relX = threadIdx.x;
+ const int relY = threadIdx.y;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+ const int X = blockIdx.x * g_blockSlices + relX;
+ const int Y = blockIdx.y * g_blockSliceSize + relY;
+
+ if (X >= dims.iVolWidth || Y >= dims.iVolHeight)
+ return;
+
+ const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f - 0.5f + 0.5f/dims.iRaysPerPixelDim) / dims.fDetScale;
+ const float fY = ( Y - 0.5f*dims.iVolHeight + 0.5f - 0.5f + 0.5f/dims.iRaysPerPixelDim) / dims.fDetScale;
+
+ const float fSubStep = 1.0f/(dims.iRaysPerPixelDim * dims.fDetScale);
+
+ float* volData = (float*)D_volData;
+
+ float fVal = 0.0f;
+ float fA = startAngle + 0.5f;
+ const float fT_base = 0.5f*dims.iProjDets - 0.5f + 1.5f;
+
+ if (offsets) {
+
+ for (int angle = startAngle; angle < endAngle; ++angle)
+ {
+ const float cos_theta = gC_angle_cos[angle];
+ const float sin_theta = gC_angle_sin[angle];
+ const float TOffset = gC_angle_offset[angle];
+
+ float fT = fT_base + fX * cos_theta - fY * sin_theta + TOffset;
+
+ for (int iSubX = 0; iSubX < dims.iRaysPerPixelDim; ++iSubX) {
+ float fTy = fT;
+ fT += fSubStep * cos_theta;
+ for (int iSubY = 0; iSubY < dims.iRaysPerPixelDim; ++iSubY) {
+ fVal += tex2D(gT_projTexture, fTy, fA);
+ fTy -= fSubStep * sin_theta;
+ }
+ }
+ fA += 1.0f;
+ }
+
+ } else {
+
+ for (int angle = startAngle; angle < endAngle; ++angle)
+ {
+ const float cos_theta = gC_angle_cos[angle];
+ const float sin_theta = gC_angle_sin[angle];
+
+ float fT = fT_base + fX * cos_theta - fY * sin_theta;
+
+ for (int iSubX = 0; iSubX < dims.iRaysPerPixelDim; ++iSubX) {
+ float fTy = fT;
+ fT += fSubStep * cos_theta;
+ for (int iSubY = 0; iSubY < dims.iRaysPerPixelDim; ++iSubY) {
+ fVal += tex2D(gT_projTexture, fTy, fA);
+ fTy -= fSubStep * sin_theta;
+ }
+ }
+ fA += 1.0f;
+
+ }
+
+ }
+
+ volData[(Y+1)*volPitch+X+1] += fVal / (dims.iRaysPerPixelDim * dims.iRaysPerPixelDim);
+}
+
+__global__ void devBP_SART(float* D_volData, unsigned int volPitch, float offset, float angle_sin, float angle_cos, const SDimensions dims)
+{
+ const int relX = threadIdx.x;
+ const int relY = threadIdx.y;
+
+ const int X = blockIdx.x * g_blockSlices + relX;
+ const int Y = blockIdx.y * g_blockSliceSize + relY;
+
+ if (X >= dims.iVolWidth || Y >= dims.iVolHeight)
+ return;
+
+ const float fX = ( X - 0.5f*dims.iVolWidth + 0.5f ) / dims.fDetScale;
+ const float fY = ( Y - 0.5f*dims.iVolHeight + 0.5f ) / dims.fDetScale;
+
+ const float fT_base = 0.5f*dims.iProjDets - 0.5f + 0.5f;
+
+ const float fT = fT_base + fX * angle_cos - fY * angle_sin + offset;
+ const float fVal = tex2D(gT_projTexture, fT, 0.5f);
+
+ D_volData[(Y+1)*volPitch+X+1] += fVal;
+}
+
+
+bool BP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const float* angles, const float* TOffsets)
+{
+ // TODO: process angles block by block
+ assert(dims.iProjAngles <= g_MaxAngles);
+
+ float* angle_sin = new float[dims.iProjAngles];
+ float* angle_cos = new float[dims.iProjAngles];
+
+ bindProjDataTexture(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles);
+
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i) {
+ angle_sin[i] = sinf(angles[i]);
+ angle_cos[i] = cosf(angles[i]);
+ }
+ cudaError_t e1 = cudaMemcpyToSymbol(gC_angle_sin, angle_sin, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ cudaError_t e2 = cudaMemcpyToSymbol(gC_angle_cos, angle_cos, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ assert(e1 == cudaSuccess);
+ assert(e2 == cudaSuccess);
+
+ if (TOffsets) {
+ cudaError_t e3 = cudaMemcpyToSymbol(gC_angle_offset, TOffsets, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ assert(e3 == cudaSuccess);
+ }
+
+ delete[] angle_sin;
+ delete[] angle_cos;
+
+ dim3 dimBlock(g_blockSlices, g_blockSliceSize);
+ dim3 dimGrid((dims.iVolWidth+g_blockSlices-1)/g_blockSlices,
+ (dims.iVolHeight+g_blockSliceSize-1)/g_blockSliceSize);
+
+ cudaStream_t stream;
+ cudaStreamCreate(&stream);
+
+ for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) {
+
+ if (dims.iRaysPerPixelDim > 1)
+ devBP_SS<<<dimGrid, dimBlock, 0, stream>>>(D_volumeData, volumePitch, i, (TOffsets != 0), dims);
+ else
+ devBP<<<dimGrid, dimBlock, 0, stream>>>(D_volumeData, volumePitch, i, (TOffsets != 0), dims);
+ }
+ cudaThreadSynchronize();
+
+ cudaTextForceKernelsCompletion();
+
+ cudaStreamDestroy(stream);
+
+ return true;
+}
+
+bool BP_SART(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ unsigned int angle, const SDimensions& dims,
+ const float* angles, const float* TOffsets)
+{
+ // only one angle
+ bindProjDataTexture(D_projData, projPitch, dims.iProjDets, 1);
+
+ float angle_sin = sinf(angles[angle]);
+ float angle_cos = cosf(angles[angle]);
+
+ float offset = 0.0f;
+ if (TOffsets)
+ offset = TOffsets[angle];
+
+ dim3 dimBlock(g_blockSlices, g_blockSliceSize);
+ dim3 dimGrid((dims.iVolWidth+g_blockSlices-1)/g_blockSlices,
+ (dims.iVolHeight+g_blockSliceSize-1)/g_blockSliceSize);
+
+ devBP_SART<<<dimGrid, dimBlock>>>(D_volumeData, volumePitch, offset, angle_sin, angle_cos, dims);
+ cudaThreadSynchronize();
+
+ cudaTextForceKernelsCompletion();
+
+ return true;
+}
+
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA;
+
+int main()
+{
+ float* D_volumeData;
+ float* D_projData;
+
+ SDimensions dims;
+ dims.iVolWidth = 1024;
+ dims.iVolHeight = 1024;
+ dims.iProjAngles = 512;
+ dims.iProjDets = 1536;
+ dims.fDetScale = 1.0f;
+ dims.iRaysPerDet = 1;
+
+ unsigned int volumePitch, projPitch;
+
+ allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ printf("pitch: %u\n", volumePitch);
+
+ allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch);
+ printf("pitch: %u\n", projPitch);
+
+ unsigned int y, x;
+ float* sino = loadImage("sino.png", y, x);
+
+ float* img = new float[dims.iVolWidth*dims.iVolHeight];
+
+ memset(img, 0, dims.iVolWidth*dims.iVolHeight*sizeof(float));
+
+ copyVolumeToDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+ copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch);
+
+ float* angle = new float[dims.iProjAngles];
+
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i)
+ angle[i] = i*(M_PI/dims.iProjAngles);
+
+ BP(D_volumeData, volumePitch, D_projData, projPitch, dims, angle, 0);
+
+ delete[] angle;
+
+ copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+
+ saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img);
+
+ return 0;
+}
+#endif
diff --git a/cuda/2d/par_bp.h b/cuda/2d/par_bp.h
new file mode 100644
index 0000000..c6dbd59
--- /dev/null
+++ b/cuda/2d/par_bp.h
@@ -0,0 +1,48 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_PAR_BP_H
+#define _CUDA_PAR_BP_H
+
+#include "dims.h"
+
+namespace astraCUDA {
+
+_AstraExport bool BP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets);
+
+_AstraExport bool BP_SART(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ unsigned int angle, const SDimensions& dims,
+ const float* angles, const float* TOffsets);
+
+}
+
+#endif
diff --git a/cuda/2d/par_fp.cu b/cuda/2d/par_fp.cu
new file mode 100644
index 0000000..585cb06
--- /dev/null
+++ b/cuda/2d/par_fp.cu
@@ -0,0 +1,704 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+#include <list>
+
+#include "util.h"
+#include "arith.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+#define PIXELTRACE
+
+
+typedef texture<float, 2, cudaReadModeElementType> texture2D;
+
+static texture2D gT_volumeTexture;
+
+
+namespace astraCUDA {
+
+static const unsigned g_MaxAngles = 2560;
+__constant__ float gC_angle[g_MaxAngles];
+__constant__ float gC_angle_offset[g_MaxAngles];
+
+
+// optimization parameters
+static const unsigned int g_anglesPerBlock = 16;
+static const unsigned int g_detBlockSize = 32;
+static const unsigned int g_blockSlices = 64;
+
+// fixed point scaling factor
+#define fPREC_FACTOR 16.0f
+#define iPREC_FACTOR 16
+
+
+// if necessary, a buffer of zeroes of size g_MaxAngles
+static float* g_pfZeroes = 0;
+
+
+static bool bindVolumeDataTexture(float* data, cudaArray*& dataArray, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+ dataArray = 0;
+ cudaMallocArray(&dataArray, &channelDesc, width, height);
+ cudaMemcpy2DToArray(dataArray, 0, 0, data, pitch*sizeof(float), width*sizeof(float), height, cudaMemcpyDeviceToDevice);
+
+ gT_volumeTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_volumeTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_volumeTexture.filterMode = cudaFilterModeLinear;
+ gT_volumeTexture.normalized = false;
+
+ // TODO: For very small sizes (roughly <=512x128) with few angles (<=180)
+ // not using an array is more efficient.
+// cudaBindTexture2D(0, gT_volumeTexture, (const void*)data, channelDesc, width, height, sizeof(float)*pitch);
+ cudaBindTextureToArray(gT_volumeTexture, dataArray, channelDesc);
+
+ // TODO: error value?
+
+ return true;
+}
+
+// projection for angles that are roughly horizontal
+// theta between 45 and 135 degrees
+__global__ void FPhorizontal(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, int regionOffset, const SDimensions dims, float outputScale)
+{
+ const int relDet = threadIdx.x;
+ const int relAngle = threadIdx.y;
+
+ int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle;
+
+ if (angle >= endAngle)
+ return;
+
+ const float theta = gC_angle[angle];
+ const float cos_theta = __cosf(theta);
+ const float sin_theta = __sinf(theta);
+
+ // compute start detector for this block/angle:
+ // (The same for all threadIdx.x)
+ // -------------------------------------
+
+ const int midSlice = startSlice + g_blockSlices / 2;
+
+ // ASSUMPTION: fDetScale >= 1.0f
+ // problem: detector regions get skipped because slice blocks aren't large
+ // enough
+ const unsigned int g_blockSliceSize = g_detBlockSize;
+
+ // project (midSlice,midRegion) on this thread's detector
+
+ const float fBase = 0.5f*dims.iProjDets - 0.5f +
+ (
+ (midSlice - 0.5f*dims.iVolWidth + 0.5f) * cos_theta
+ - (g_blockSliceSize/2 - 0.5f*dims.iVolHeight + 0.5f) * sin_theta
+ + gC_angle_offset[angle]
+ ) / dims.fDetScale;
+ int iBase = (int)floorf(fBase * fPREC_FACTOR);
+ int iInc = (int)floorf(g_blockSliceSize * sin_theta / dims.fDetScale * -fPREC_FACTOR);
+
+ // ASSUMPTION: 16 > regionOffset / fDetScale
+ const int detRegion = (iBase + (blockIdx.y - regionOffset)*iInc + 16*iPREC_FACTOR*g_detBlockSize) / (iPREC_FACTOR * g_detBlockSize) - 16;
+ const int detPrevRegion = (iBase + (blockIdx.y - regionOffset - 1)*iInc + 16*iPREC_FACTOR*g_detBlockSize) / (iPREC_FACTOR * g_detBlockSize) - 16;
+
+ if (blockIdx.y > 0 && detRegion == detPrevRegion)
+ return;
+
+ const int detector = detRegion * g_detBlockSize + relDet;
+
+ // Now project the part of the ray to angle,detector through
+ // slices startSlice to startSlice+g_blockSlices-1
+
+ if (detector < 0 || detector >= dims.iProjDets)
+ return;
+
+ const float fDetStep = -dims.fDetScale / sin_theta;
+ float fSliceStep = cos_theta / sin_theta;
+ float fDistCorr;
+ if (sin_theta > 0.0f)
+ fDistCorr = -fDetStep;
+ else
+ fDistCorr = fDetStep;
+ fDistCorr *= outputScale;
+
+ float fVal = 0.0f;
+ // project detector on slice
+ float fP = (detector - 0.5f*dims.iProjDets + 0.5f - gC_angle_offset[angle]) * fDetStep + (startSlice - 0.5f*dims.iVolWidth + 0.5f) * fSliceStep + 0.5f*dims.iVolHeight - 0.5f + 1.5f;
+ float fS = startSlice + 1.5f;
+ int endSlice = startSlice + g_blockSlices;
+ if (endSlice > dims.iVolWidth)
+ endSlice = dims.iVolWidth;
+
+ if (dims.iRaysPerDet > 1) {
+
+ fP += (-0.5f*dims.iRaysPerDet + 0.5f)/dims.iRaysPerDet * fDetStep;
+ const float fSubDetStep = fDetStep / dims.iRaysPerDet;
+ fDistCorr /= dims.iRaysPerDet;
+
+ fSliceStep -= dims.iRaysPerDet * fSubDetStep;
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) {
+ fVal += tex2D(gT_volumeTexture, fS, fP);
+ fP += fSubDetStep;
+ }
+ fP += fSliceStep;
+ fS += 1.0f;
+ }
+
+ } else {
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ fVal += tex2D(gT_volumeTexture, fS, fP);
+ fP += fSliceStep;
+ fS += 1.0f;
+ }
+
+
+ }
+
+ D_projData[angle*projPitch+detector+1] += fVal * fDistCorr;
+}
+
+// projection for angles that are roughly vertical
+// theta between 0 and 45, or 135 and 180 degrees
+__global__ void FPvertical(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, int regionOffset, const SDimensions dims, float outputScale)
+{
+ const int relDet = threadIdx.x;
+ const int relAngle = threadIdx.y;
+
+ int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle;
+
+ if (angle >= endAngle)
+ return;
+
+ const float theta = gC_angle[angle];
+ const float cos_theta = __cosf(theta);
+ const float sin_theta = __sinf(theta);
+
+ // compute start detector for this block/angle:
+ // (The same for all threadIdx.x)
+ // -------------------------------------
+
+ const int midSlice = startSlice + g_blockSlices / 2;
+
+ // project (midSlice,midRegion) on this thread's detector
+
+ // ASSUMPTION: fDetScale >= 1.0f
+ // problem: detector regions get skipped because slice blocks aren't large
+ // enough
+ const unsigned int g_blockSliceSize = g_detBlockSize;
+
+ const float fBase = 0.5f*dims.iProjDets - 0.5f +
+ (
+ (g_blockSliceSize/2 - 0.5f*dims.iVolWidth + 0.5f) * cos_theta
+ - (midSlice - 0.5f*dims.iVolHeight + 0.5f) * sin_theta
+ + gC_angle_offset[angle]
+ ) / dims.fDetScale;
+ int iBase = (int)floorf(fBase * fPREC_FACTOR);
+ int iInc = (int)floorf(g_blockSliceSize * cos_theta / dims.fDetScale * fPREC_FACTOR);
+
+ // ASSUMPTION: 16 > regionOffset / fDetScale
+ const int detRegion = (iBase + (blockIdx.y - regionOffset)*iInc + 16*iPREC_FACTOR*g_detBlockSize) / (iPREC_FACTOR * g_detBlockSize) - 16;
+ const int detPrevRegion = (iBase + (blockIdx.y - regionOffset-1)*iInc + 16*iPREC_FACTOR*g_detBlockSize) / (iPREC_FACTOR * g_detBlockSize) - 16;
+
+ if (blockIdx.y > 0 && detRegion == detPrevRegion)
+ return;
+
+ const int detector = detRegion * g_detBlockSize + relDet;
+
+ // Now project the part of the ray to angle,detector through
+ // slices startSlice to startSlice+g_blockSlices-1
+
+ if (detector < 0 || detector >= dims.iProjDets)
+ return;
+
+ const float fDetStep = dims.fDetScale / cos_theta;
+ float fSliceStep = sin_theta / cos_theta;
+ float fDistCorr;
+ if (cos_theta < 0.0f)
+ fDistCorr = -fDetStep;
+ else
+ fDistCorr = fDetStep;
+ fDistCorr *= outputScale;
+
+ float fVal = 0.0f;
+ float fP = (detector - 0.5f*dims.iProjDets + 0.5f - gC_angle_offset[angle]) * fDetStep + (startSlice - 0.5f*dims.iVolHeight + 0.5f) * fSliceStep + 0.5f*dims.iVolWidth - 0.5f + 1.5f;
+ float fS = startSlice+1.5f;
+ int endSlice = startSlice + g_blockSlices;
+ if (endSlice > dims.iVolHeight)
+ endSlice = dims.iVolHeight;
+
+ if (dims.iRaysPerDet > 1) {
+
+ fP += (-0.5f*dims.iRaysPerDet + 0.5f)/dims.iRaysPerDet * fDetStep;
+ const float fSubDetStep = fDetStep / dims.iRaysPerDet;
+ fDistCorr /= dims.iRaysPerDet;
+
+ fSliceStep -= dims.iRaysPerDet * fSubDetStep;
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) {
+ fVal += tex2D(gT_volumeTexture, fP, fS);
+ fP += fSubDetStep;
+ }
+ fP += fSliceStep;
+ fS += 1.0f;
+ }
+
+ } else {
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ fVal += tex2D(gT_volumeTexture, fP, fS);
+ fP += fSliceStep;
+ fS += 1.0f;
+ }
+
+ }
+
+ D_projData[angle*projPitch+detector+1] += fVal * fDistCorr;
+}
+
+// projection for angles that are roughly horizontal
+// (detector roughly vertical)
+__global__ void FPhorizontal_simple(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions dims, float outputScale)
+{
+ const int relDet = threadIdx.x;
+ const int relAngle = threadIdx.y;
+
+ int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle;
+
+ if (angle >= endAngle)
+ return;
+
+ const float theta = gC_angle[angle];
+ const float cos_theta = __cosf(theta);
+ const float sin_theta = __sinf(theta);
+
+ // compute start detector for this block/angle:
+ const int detRegion = blockIdx.y;
+
+ const int detector = detRegion * g_detBlockSize + relDet;
+
+ // Now project the part of the ray to angle,detector through
+ // slices startSlice to startSlice+g_blockSlices-1
+
+ if (detector < 0 || detector >= dims.iProjDets)
+ return;
+
+ const float fDetStep = -dims.fDetScale / sin_theta;
+ float fSliceStep = cos_theta / sin_theta;
+ float fDistCorr;
+ if (sin_theta > 0.0f)
+ fDistCorr = -fDetStep;
+ else
+ fDistCorr = fDetStep;
+ fDistCorr *= outputScale;
+
+ float fVal = 0.0f;
+ // project detector on slice
+ float fP = (detector - 0.5f*dims.iProjDets + 0.5f - gC_angle_offset[angle]) * fDetStep + (startSlice - 0.5f*dims.iVolWidth + 0.5f) * fSliceStep + 0.5f*dims.iVolHeight - 0.5f + 1.5f;
+ float fS = startSlice + 1.5f;
+ int endSlice = startSlice + g_blockSlices;
+ if (endSlice > dims.iVolWidth)
+ endSlice = dims.iVolWidth;
+
+ if (dims.iRaysPerDet > 1) {
+
+ fP += (-0.5f*dims.iRaysPerDet + 0.5f)/dims.iRaysPerDet * fDetStep;
+ const float fSubDetStep = fDetStep / dims.iRaysPerDet;
+ fDistCorr /= dims.iRaysPerDet;
+
+ fSliceStep -= dims.iRaysPerDet * fSubDetStep;
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) {
+ fVal += tex2D(gT_volumeTexture, fS, fP);
+ fP += fSubDetStep;
+ }
+ fP += fSliceStep;
+ fS += 1.0f;
+ }
+
+ } else {
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ fVal += tex2D(gT_volumeTexture, fS, fP);
+ fP += fSliceStep;
+ fS += 1.0f;
+ }
+
+
+ }
+
+ D_projData[angle*projPitch+detector+1] += fVal * fDistCorr;
+}
+
+
+// projection for angles that are roughly vertical
+// (detector roughly horizontal)
+__global__ void FPvertical_simple(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions dims, float outputScale)
+{
+ const int relDet = threadIdx.x;
+ const int relAngle = threadIdx.y;
+
+ int angle = startAngle + blockIdx.x * g_anglesPerBlock + relAngle;
+
+ if (angle >= endAngle)
+ return;
+
+ const float theta = gC_angle[angle];
+ const float cos_theta = __cosf(theta);
+ const float sin_theta = __sinf(theta);
+
+ // compute start detector for this block/angle:
+ const int detRegion = blockIdx.y;
+
+ const int detector = detRegion * g_detBlockSize + relDet;
+
+ // Now project the part of the ray to angle,detector through
+ // slices startSlice to startSlice+g_blockSlices-1
+
+ if (detector < 0 || detector >= dims.iProjDets)
+ return;
+
+ const float fDetStep = dims.fDetScale / cos_theta;
+ float fSliceStep = sin_theta / cos_theta;
+ float fDistCorr;
+ if (cos_theta < 0.0f)
+ fDistCorr = -fDetStep;
+ else
+ fDistCorr = fDetStep;
+ fDistCorr *= outputScale;
+
+ float fVal = 0.0f;
+ float fP = (detector - 0.5f*dims.iProjDets + 0.5f - gC_angle_offset[angle]) * fDetStep + (startSlice - 0.5f*dims.iVolHeight + 0.5f) * fSliceStep + 0.5f*dims.iVolWidth - 0.5f + 1.5f;
+ float fS = startSlice+1.5f;
+ int endSlice = startSlice + g_blockSlices;
+ if (endSlice > dims.iVolHeight)
+ endSlice = dims.iVolHeight;
+
+ if (dims.iRaysPerDet > 1) {
+
+ fP += (-0.5f*dims.iRaysPerDet + 0.5f)/dims.iRaysPerDet * fDetStep;
+ const float fSubDetStep = fDetStep / dims.iRaysPerDet;
+ fDistCorr /= dims.iRaysPerDet;
+
+ fSliceStep -= dims.iRaysPerDet * fSubDetStep;
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ for (int iSubT = 0; iSubT < dims.iRaysPerDet; ++iSubT) {
+ fVal += tex2D(gT_volumeTexture, fP, fS);
+ fP += fSubDetStep;
+ }
+ fP += fSliceStep;
+ fS += 1.0f;
+ }
+
+ } else {
+
+ for (int slice = startSlice; slice < endSlice; ++slice)
+ {
+ fVal += tex2D(gT_volumeTexture, fP, fS);
+ fP += fSliceStep;
+ fS += 1.0f;
+ }
+
+ }
+
+ D_projData[angle*projPitch+detector+1] += fVal * fDistCorr;
+}
+
+
+
+bool FP_simple(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets, float outputScale)
+{
+ // TODO: load angles into constant memory in smaller blocks
+ assert(dims.iProjAngles <= g_MaxAngles);
+
+ cudaArray* D_dataArray;
+ bindVolumeDataTexture(D_volumeData, D_dataArray, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+ cudaMemcpyToSymbol(gC_angle, angles, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+
+ if (TOffsets) {
+ cudaMemcpyToSymbol(gC_angle_offset, TOffsets, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ } else {
+ if (!g_pfZeroes) {
+ g_pfZeroes = new float[g_MaxAngles];
+ memset(g_pfZeroes, 0, g_MaxAngles * sizeof(float));
+ }
+ cudaMemcpyToSymbol(gC_angle_offset, g_pfZeroes, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ }
+
+ dim3 dimBlock(g_detBlockSize, g_anglesPerBlock); // detector block size, angles
+
+ std::list<cudaStream_t> streams;
+
+
+ // Run over all angles, grouping them into groups of the same
+ // orientation (roughly horizontal vs. roughly vertical).
+ // Start a stream of grids for each such group.
+
+ // TODO: Check if it's worth it to store this info instead
+ // of recomputing it every FP.
+
+ unsigned int blockStart = 0;
+ unsigned int blockEnd = 0;
+ bool blockVertical = false;
+ for (unsigned int a = 0; a <= dims.iProjAngles; ++a) {
+ bool vertical;
+ // TODO: Having <= instead of < below causes a 5% speedup.
+ // Maybe we should detect corner cases and put them in the optimal
+ // group of angles.
+ if (a != dims.iProjAngles)
+ vertical = (fabsf(sinf(angles[a])) <= fabsf(cosf(angles[a])));
+ if (a == dims.iProjAngles || vertical != blockVertical) {
+ // block done
+
+ blockEnd = a;
+ if (blockStart != blockEnd) {
+ dim3 dimGrid((blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock,
+ (dims.iProjDets+g_detBlockSize-1)/g_detBlockSize); // angle blocks, detector blocks
+
+ // TODO: check if we can't immediately
+ // destroy the stream after use
+ cudaStream_t stream;
+ cudaStreamCreate(&stream);
+ streams.push_back(stream);
+ //printf("angle block: %d to %d, %d\n", blockStart, blockEnd, blockVertical);
+ if (!blockVertical)
+ for (unsigned int i = 0; i < dims.iVolWidth; i += g_blockSlices)
+ FPhorizontal_simple<<<dimGrid, dimBlock, 0, stream>>>(D_projData, projPitch, i, blockStart, blockEnd, dims, outputScale);
+ else
+ for (unsigned int i = 0; i < dims.iVolHeight; i += g_blockSlices)
+ FPvertical_simple<<<dimGrid, dimBlock, 0, stream>>>(D_projData, projPitch, i, blockStart, blockEnd, dims, outputScale);
+ }
+ blockVertical = vertical;
+ blockStart = a;
+ }
+ }
+
+ for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter)
+ cudaStreamDestroy(*iter);
+
+ streams.clear();
+
+ cudaThreadSynchronize();
+
+ cudaTextForceKernelsCompletion();
+
+ cudaFreeArray(D_dataArray);
+
+
+ return true;
+}
+
+bool FP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets, float outputScale)
+{
+ return FP_simple(D_volumeData, volumePitch, D_projData, projPitch,
+ dims, angles, TOffsets, outputScale);
+
+ // TODO: Fix bug in this non-simple FP with large detscale and TOffsets
+#if 0
+
+ // TODO: load angles into constant memory in smaller blocks
+ assert(dims.iProjAngles <= g_MaxAngles);
+
+ // TODO: compute region size dynamically to resolve these two assumptions
+ // ASSUMPTION: 16 > regionOffset / fDetScale
+ const unsigned int g_blockSliceSize = g_detBlockSize;
+ assert(16 > (g_blockSlices / g_blockSliceSize) / dims.fDetScale);
+ // ASSUMPTION: fDetScale >= 1.0f
+ assert(dims.fDetScale > 0.9999f);
+
+ cudaArray* D_dataArray;
+ bindVolumeDataTexture(D_volumeData, D_dataArray, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+ cudaMemcpyToSymbol(gC_angle, angles, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+
+ if (TOffsets) {
+ cudaMemcpyToSymbol(gC_angle_offset, TOffsets, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ } else {
+ if (!g_pfZeroes) {
+ g_pfZeroes = new float[g_MaxAngles];
+ memset(g_pfZeroes, 0, g_MaxAngles * sizeof(float));
+ }
+ cudaMemcpyToSymbol(gC_angle_offset, g_pfZeroes, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ }
+
+ int regionOffset = g_blockSlices / g_blockSliceSize;
+
+ dim3 dimBlock(g_detBlockSize, g_anglesPerBlock); // region size, angles
+
+ std::list<cudaStream_t> streams;
+
+
+ // Run over all angles, grouping them into groups of the same
+ // orientation (roughly horizontal vs. roughly vertical).
+ // Start a stream of grids for each such group.
+
+ // TODO: Check if it's worth it to store this info instead
+ // of recomputing it every FP.
+
+ unsigned int blockStart = 0;
+ unsigned int blockEnd = 0;
+ bool blockVertical = false;
+ for (unsigned int a = 0; a <= dims.iProjAngles; ++a) {
+ bool vertical;
+ // TODO: Having <= instead of < below causes a 5% speedup.
+ // Maybe we should detect corner cases and put them in the optimal
+ // group of angles.
+ if (a != dims.iProjAngles)
+ vertical = (fabsf(sinf(angles[a])) <= fabsf(cosf(angles[a])));
+ if (a == dims.iProjAngles || vertical != blockVertical) {
+ // block done
+
+ blockEnd = a;
+ if (blockStart != blockEnd) {
+ unsigned int length = dims.iVolHeight;
+ if (blockVertical)
+ length = dims.iVolWidth;
+ dim3 dimGrid((blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock,
+ (length+g_blockSliceSize-1)/g_blockSliceSize+2*regionOffset); // angle blocks, regions
+ // TODO: check if we can't immediately
+ // destroy the stream after use
+ cudaStream_t stream;
+ cudaStreamCreate(&stream);
+ streams.push_back(stream);
+ //printf("angle block: %d to %d, %d\n", blockStart, blockEnd, blockVertical);
+ if (!blockVertical)
+ for (unsigned int i = 0; i < dims.iVolWidth; i += g_blockSlices)
+ FPhorizontal<<<dimGrid, dimBlock, 0, stream>>>(D_projData, projPitch, i, blockStart, blockEnd, regionOffset, dims, outputScale);
+ else
+ for (unsigned int i = 0; i < dims.iVolHeight; i += g_blockSlices)
+ FPvertical<<<dimGrid, dimBlock, 0, stream>>>(D_projData, projPitch, i, blockStart, blockEnd, regionOffset, dims, outputScale);
+ }
+ blockVertical = vertical;
+ blockStart = a;
+ }
+ }
+
+ for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter)
+ cudaStreamDestroy(*iter);
+
+ streams.clear();
+
+ cudaThreadSynchronize();
+
+ cudaTextForceKernelsCompletion();
+
+ cudaFreeArray(D_dataArray);
+
+
+ return true;
+#endif
+}
+
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA;
+
+int main()
+{
+ float* D_volumeData;
+ float* D_projData;
+
+ SDimensions dims;
+ dims.iVolWidth = 1024;
+ dims.iVolHeight = 1024;
+ dims.iProjAngles = 512;
+ dims.iProjDets = 1536;
+ dims.fDetScale = 1.0f;
+ dims.iRaysPerDet = 1;
+ unsigned int volumePitch, projPitch;
+
+ allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ printf("pitch: %u\n", volumePitch);
+
+ allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch);
+ printf("pitch: %u\n", projPitch);
+
+ unsigned int y, x;
+ float* img = loadImage("phantom.png", y, x);
+
+ float* sino = new float[dims.iProjAngles * dims.iProjDets];
+
+ memset(sino, 0, dims.iProjAngles * dims.iProjDets * sizeof(float));
+
+ copyVolumeToDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+ copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch);
+
+ float* angle = new float[dims.iProjAngles];
+
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i)
+ angle[i] = i*(M_PI/dims.iProjAngles);
+
+ FP(D_volumeData, volumePitch, D_projData, projPitch, dims, angle, 0, 1.0f);
+
+ delete[] angle;
+
+ copySinogramFromDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_projData, projPitch);
+
+ float s = 0.0f;
+ for (unsigned int y = 0; y < dims.iProjAngles; ++y)
+ for (unsigned int x = 0; x < dims.iProjDets; ++x)
+ s += sino[y*dims.iProjDets+x] * sino[y*dims.iProjDets+x];
+ printf("cpu norm: %f\n", s);
+
+ //zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles);
+ s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0);
+ printf("gpu norm: %f\n", s);
+
+ saveImage("sino.png",dims.iProjAngles,dims.iProjDets,sino);
+
+
+ return 0;
+}
+#endif
diff --git a/cuda/2d/par_fp.h b/cuda/2d/par_fp.h
new file mode 100644
index 0000000..3213b14
--- /dev/null
+++ b/cuda/2d/par_fp.h
@@ -0,0 +1,41 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_PAR_FP_H
+#define _CUDA_PAR_FP_H
+
+namespace astraCUDA {
+
+_AstraExport bool FP(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets, float fOutputScale);
+
+}
+
+#endif
diff --git a/cuda/2d/sart.cu b/cuda/2d/sart.cu
new file mode 100644
index 0000000..a40176d
--- /dev/null
+++ b/cuda/2d/sart.cu
@@ -0,0 +1,283 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+
+#include "sart.h"
+#include "util.h"
+#include "arith.h"
+#include "fan_fp.h"
+#include "fan_bp.h"
+#include "par_fp.h"
+#include "par_bp.h"
+
+namespace astraCUDA {
+
+
+__global__ void devMUL_SART(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ // Copy result down and left one pixel.
+ pfOut[x + pitch] = pfOut[x + 1] * pfIn[x + 1];
+}
+
+void MUL_SART(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, 1);
+
+ devMUL_SART<<<gridSize, blockSize>>>(pfOut, pfIn, pitch, width);
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+
+SART::SART() : ReconAlgo()
+{
+ D_projData = 0;
+ D_tmpData = 0;
+
+ D_lineWeight = 0;
+
+ projectionOrder = 0;
+ projectionCount = 0;
+ iteration = 0;
+ customOrder = false;
+}
+
+
+SART::~SART()
+{
+ reset();
+}
+
+void SART::reset()
+{
+ cudaFree(D_projData);
+ cudaFree(D_tmpData);
+ cudaFree(D_lineWeight);
+
+ D_projData = 0;
+ D_tmpData = 0;
+
+ D_lineWeight = 0;
+
+ useVolumeMask = false;
+ useSinogramMask = false;
+
+ if (projectionOrder != NULL) delete[] projectionOrder;
+ projectionOrder = 0;
+ projectionCount = 0;
+ iteration = 0;
+ customOrder = false;
+
+ ReconAlgo::reset();
+}
+
+bool SART::init()
+{
+ if (useVolumeMask) {
+ allocateVolume(D_tmpData, dims.iVolWidth+2, dims.iVolHeight+2, tmpPitch);
+ zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ }
+
+ // HACK: D_projData consists of two lines. The first is used padded,
+ // the second unpadded. This is to satisfy the alignment requirements
+ // of resp. FP and BP_SART.
+ allocateVolume(D_projData, dims.iProjDets+2, 2, projPitch);
+ zeroVolume(D_projData, projPitch, dims.iProjDets+2, 1);
+
+ allocateVolume(D_lineWeight, dims.iProjDets+2, dims.iProjAngles, linePitch);
+ zeroVolume(D_lineWeight, linePitch, dims.iProjDets+2, dims.iProjAngles);
+
+ // We can't precompute lineWeights when using a mask
+ if (!useVolumeMask)
+ precomputeWeights();
+
+ // TODO: check if allocations succeeded
+ return true;
+}
+
+bool SART::setProjectionOrder(int* _projectionOrder, int _projectionCount)
+{
+ customOrder = true;
+ projectionCount = _projectionCount;
+ projectionOrder = new int[projectionCount];
+ for (int i = 0; i < projectionCount; i++) {
+ projectionOrder[i] = _projectionOrder[i];
+ }
+
+ return true;
+}
+
+
+bool SART::precomputeWeights()
+{
+ zeroVolume(D_lineWeight, linePitch, dims.iProjDets+2, dims.iProjAngles);
+ if (useVolumeMask) {
+ callFP(D_maskData, maskPitch, D_lineWeight, linePitch, 1.0f);
+ } else {
+ // Allocate tmpData temporarily
+ allocateVolume(D_tmpData, dims.iVolWidth+2, dims.iVolHeight+2, tmpPitch);
+ zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+
+ processVol<opSet, VOL>(D_tmpData, 1.0f, tmpPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP(D_tmpData, tmpPitch, D_lineWeight, linePitch, 1.0f);
+
+
+ cudaFree(D_tmpData);
+ D_tmpData = 0;
+ }
+ processVol<opInvert, SINO>(D_lineWeight, linePitch, dims.iProjDets, dims.iProjAngles);
+
+ return true;
+}
+
+bool SART::iterate(unsigned int iterations)
+{
+ shouldAbort = false;
+
+ if (useVolumeMask)
+ precomputeWeights();
+
+ // iteration
+ for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) {
+
+ int angle;
+ if (customOrder) {
+ angle = projectionOrder[iteration % projectionCount];
+ } else {
+ angle = iteration % dims.iProjAngles;
+ }
+
+ // copy one line of sinogram to projection data
+ cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData + angle*sinoPitch, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), 1, cudaMemcpyDeviceToDevice);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice);
+ processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP_SART(D_tmpData, tmpPitch, D_projData, projPitch, angle, -1.0f);
+ } else {
+ callFP_SART(D_volumeData, volumePitch, D_projData, projPitch, angle, -1.0f);
+ }
+
+ MUL_SART(D_projData, D_lineWeight + angle*linePitch, projPitch, dims.iProjDets);
+
+ if (useVolumeMask) {
+ // BP, mask, and add back
+ // TODO: Try putting the masking directly in the BP
+ zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ callBP_SART(D_tmpData, tmpPitch, D_projData, projPitch, angle);
+ processVol<opAddMul, VOL>(D_volumeData, D_maskData, D_tmpData, volumePitch, dims.iVolWidth, dims.iVolHeight);
+ } else {
+ callBP_SART(D_volumeData, volumePitch, D_projData, projPitch, angle);
+ }
+
+ if (useMinConstraint)
+ processVol<opClampMin, VOL>(D_volumeData, fMinConstraint, volumePitch, dims.iVolWidth, dims.iVolHeight);
+ if (useMaxConstraint)
+ processVol<opClampMax, VOL>(D_volumeData, fMaxConstraint, volumePitch, dims.iVolWidth, dims.iVolHeight);
+
+ iteration++;
+
+ }
+
+ return true;
+}
+
+float SART::computeDiffNorm()
+{
+ unsigned int pPitch;
+ float *D_p;
+ allocateVolume(D_p, dims.iProjDets+2, dims.iProjAngles, pPitch);
+ zeroVolume(D_p, pPitch, dims.iProjDets+2, dims.iProjAngles);
+
+ // copy sinogram to D_p
+ cudaMemcpy2D(D_p, sizeof(float)*pPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice);
+ processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP(D_tmpData, tmpPitch, D_projData, projPitch, -1.0f);
+ } else {
+ callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f);
+ }
+
+
+ // compute norm of D_p
+ float s = dotProduct2D(D_p, pPitch, dims.iProjDets, dims.iProjAngles, 1, 0);
+
+ cudaFree(D_p);
+
+ return sqrt(s);
+}
+
+bool SART::callFP_SART(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ unsigned int angle, float outputScale)
+{
+ SDimensions d = dims;
+ d.iProjAngles = 1;
+ if (angles) {
+ assert(!fanProjs);
+ return FP(D_volumeData, volumePitch, D_projData, projPitch,
+ d, &angles[angle], TOffsets, outputScale);
+ } else {
+ assert(fanProjs);
+ return FanFP(D_volumeData, volumePitch, D_projData, projPitch,
+ d, &fanProjs[angle], outputScale);
+ }
+}
+
+bool SART::callBP_SART(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ unsigned int angle)
+{
+ if (angles) {
+ assert(!fanProjs);
+ return BP_SART(D_volumeData, volumePitch, D_projData + projPitch, projPitch,
+ angle, dims, angles, TOffsets);
+ } else {
+ assert(fanProjs);
+ return FanBP_SART(D_volumeData, volumePitch, D_projData + projPitch, projPitch,
+ angle, dims, fanProjs);
+ }
+
+}
+
+
+}
+
+
diff --git a/cuda/2d/sart.h b/cuda/2d/sart.h
new file mode 100644
index 0000000..ad80259
--- /dev/null
+++ b/cuda/2d/sart.h
@@ -0,0 +1,85 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_SART_H
+#define _CUDA_SART_H
+
+#include "util.h"
+#include "algo.h"
+
+namespace astraCUDA {
+
+class _AstraExport SART : public ReconAlgo {
+public:
+ SART();
+ ~SART();
+
+ // disable some features
+ virtual bool enableSinogramMask() { return false; }
+
+ virtual bool init();
+
+ virtual bool setProjectionOrder(int* projectionOrder, int projectionCount);
+
+ virtual bool iterate(unsigned int iterations);
+
+ virtual float computeDiffNorm();
+
+protected:
+ void reset();
+ bool precomputeWeights();
+
+ bool callFP_SART(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ unsigned int angle, float outputScale);
+ bool callBP_SART(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ unsigned int angle);
+
+
+ // projection angle variables
+ bool customOrder;
+ int* projectionOrder;
+ int projectionCount;
+ int iteration;
+
+ // Temporary buffers
+ float* D_projData;
+ unsigned int projPitch;
+
+ float* D_tmpData; // Only used when there's a volume mask
+ unsigned int tmpPitch;
+
+ // Geometry-specific precomputed data
+ float* D_lineWeight;
+ unsigned int linePitch;
+};
+
+}
+
+#endif
diff --git a/cuda/2d/sirt.cu b/cuda/2d/sirt.cu
new file mode 100644
index 0000000..31954e4
--- /dev/null
+++ b/cuda/2d/sirt.cu
@@ -0,0 +1,342 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+
+#include "sirt.h"
+#include "util.h"
+#include "arith.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+namespace astraCUDA {
+
+SIRT::SIRT() : ReconAlgo()
+{
+ D_projData = 0;
+ D_tmpData = 0;
+
+ D_lineWeight = 0;
+ D_pixelWeight = 0;
+
+ D_minMaskData = 0;
+ D_maxMaskData = 0;
+
+ freeMinMaxMasks = false;
+}
+
+
+SIRT::~SIRT()
+{
+ reset();
+}
+
+void SIRT::reset()
+{
+ cudaFree(D_projData);
+ cudaFree(D_tmpData);
+ cudaFree(D_lineWeight);
+ cudaFree(D_pixelWeight);
+ if (freeMinMaxMasks) {
+ cudaFree(D_minMaskData);
+ cudaFree(D_maxMaskData);
+ }
+
+ D_projData = 0;
+ D_tmpData = 0;
+
+ D_lineWeight = 0;
+ D_pixelWeight = 0;
+
+ freeMinMaxMasks = false;
+ D_minMaskData = 0;
+ D_maxMaskData = 0;
+
+ useVolumeMask = false;
+ useSinogramMask = false;
+
+ ReconAlgo::reset();
+}
+
+bool SIRT::init()
+{
+ allocateVolume(D_pixelWeight, dims.iVolWidth+2, dims.iVolHeight+2, pixelPitch);
+ zeroVolume(D_pixelWeight, pixelPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+ allocateVolume(D_tmpData, dims.iVolWidth+2, dims.iVolHeight+2, tmpPitch);
+ zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+ allocateVolume(D_projData, dims.iProjDets+2, dims.iProjAngles, projPitch);
+ zeroVolume(D_projData, projPitch, dims.iProjDets+2, dims.iProjAngles);
+
+ allocateVolume(D_lineWeight, dims.iProjDets+2, dims.iProjAngles, linePitch);
+ zeroVolume(D_lineWeight, linePitch, dims.iProjDets+2, dims.iProjAngles);
+
+ // We can't precompute lineWeights and pixelWeights when using a mask
+ if (!useVolumeMask && !useSinogramMask)
+ precomputeWeights();
+
+ // TODO: check if allocations succeeded
+ return true;
+}
+
+bool SIRT::precomputeWeights()
+{
+ zeroVolume(D_lineWeight, linePitch, dims.iProjDets+2, dims.iProjAngles);
+ if (useVolumeMask) {
+ callFP(D_maskData, maskPitch, D_lineWeight, linePitch, 1.0f);
+ } else {
+ processVol<opSet, VOL>(D_tmpData, 1.0f, tmpPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP(D_tmpData, tmpPitch, D_lineWeight, linePitch, 1.0f);
+ }
+ processVol<opInvert, SINO>(D_lineWeight, linePitch, dims.iProjDets, dims.iProjAngles);
+
+ if (useSinogramMask) {
+ // scale line weights with sinogram mask to zero out masked sinogram pixels
+ processVol<opMul, SINO>(D_lineWeight, D_smaskData, linePitch, dims.iProjDets, dims.iProjAngles);
+ }
+
+
+ zeroVolume(D_pixelWeight, pixelPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ if (useSinogramMask) {
+ callBP(D_pixelWeight, pixelPitch, D_smaskData, smaskPitch);
+ } else {
+ processVol<opSet, SINO>(D_projData, 1.0f, projPitch, dims.iProjDets, dims.iProjAngles);
+ callBP(D_pixelWeight, pixelPitch, D_projData, projPitch);
+ }
+ processVol<opInvert, VOL>(D_pixelWeight, pixelPitch, dims.iVolWidth, dims.iVolHeight);
+
+ if (useVolumeMask) {
+ // scale pixel weights with mask to zero out masked pixels
+ processVol<opMul, VOL>(D_pixelWeight, D_maskData, pixelPitch, dims.iVolWidth, dims.iVolHeight);
+ }
+
+ return true;
+}
+
+bool SIRT::setMinMaxMasks(float* D_minMaskData_, float* D_maxMaskData_,
+ unsigned int iPitch)
+{
+ D_minMaskData = D_minMaskData_;
+ D_maxMaskData = D_maxMaskData_;
+ minMaskPitch = iPitch;
+ maxMaskPitch = iPitch;
+
+ freeMinMaxMasks = false;
+ return true;
+}
+
+bool SIRT::uploadMinMaxMasks(const float* pfMinMaskData, const float* pfMaxMaskData,
+ unsigned int iPitch)
+{
+ freeMinMaxMasks = true;
+ bool ok = true;
+ if (pfMinMaskData) {
+ allocateVolume(D_minMaskData, dims.iVolWidth+2, dims.iVolHeight+2, minMaskPitch);
+ ok = copyVolumeToDevice(pfMinMaskData, iPitch,
+ dims.iVolWidth, dims.iVolHeight,
+ D_minMaskData, minMaskPitch);
+ }
+ if (!ok)
+ return false;
+
+ if (pfMaxMaskData) {
+ allocateVolume(D_maxMaskData, dims.iVolWidth+2, dims.iVolHeight+2, maxMaskPitch);
+ ok = copyVolumeToDevice(pfMaxMaskData, iPitch,
+ dims.iVolWidth, dims.iVolHeight,
+ D_maxMaskData, maxMaskPitch);
+ }
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+bool SIRT::iterate(unsigned int iterations)
+{
+ shouldAbort = false;
+
+ if (useVolumeMask || useSinogramMask)
+ precomputeWeights();
+
+ // iteration
+ for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) {
+
+ // copy sinogram to projection data
+ cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice);
+ processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP(D_tmpData, tmpPitch, D_projData, projPitch, -1.0f);
+ } else {
+ callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f);
+ }
+
+ processVol<opMul, SINO>(D_projData, D_lineWeight, projPitch, dims.iProjDets, dims.iProjAngles);
+
+ zeroVolume(D_tmpData, tmpPitch, dims.iVolWidth+2, dims.iVolHeight+2);
+
+ callBP(D_tmpData, tmpPitch, D_projData, projPitch);
+
+ processVol<opAddMul, VOL>(D_volumeData, D_pixelWeight, D_tmpData, volumePitch, dims.iVolWidth, dims.iVolHeight);
+
+ if (useMinConstraint)
+ processVol<opClampMin, VOL>(D_volumeData, fMinConstraint, volumePitch, dims.iVolWidth, dims.iVolHeight);
+ if (useMaxConstraint)
+ processVol<opClampMax, VOL>(D_volumeData, fMaxConstraint, volumePitch, dims.iVolWidth, dims.iVolHeight);
+ if (D_minMaskData)
+ processVol<opClampMinMask, VOL>(D_volumeData, D_minMaskData, volumePitch, dims.iVolWidth, dims.iVolHeight);
+ if (D_maxMaskData)
+ processVol<opClampMaxMask, VOL>(D_volumeData, D_maxMaskData, volumePitch, dims.iVolWidth, dims.iVolHeight);
+ }
+
+ return true;
+}
+
+float SIRT::computeDiffNorm()
+{
+ // copy sinogram to projection data
+ cudaMemcpy2D(D_projData, sizeof(float)*projPitch, D_sinoData, sizeof(float)*sinoPitch, sizeof(float)*(dims.iProjDets+2), dims.iProjAngles, cudaMemcpyDeviceToDevice);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ cudaMemcpy2D(D_tmpData, sizeof(float)*tmpPitch, D_volumeData, sizeof(float)*volumePitch, sizeof(float)*(dims.iVolWidth+2), dims.iVolHeight+2, cudaMemcpyDeviceToDevice);
+ processVol<opMul, VOL>(D_tmpData, D_maskData, tmpPitch, dims.iVolWidth, dims.iVolHeight);
+ callFP(D_tmpData, tmpPitch, D_projData, projPitch, -1.0f);
+ } else {
+ callFP(D_volumeData, volumePitch, D_projData, projPitch, -1.0f);
+ }
+
+
+ // compute norm of D_projData
+
+ float s = dotProduct2D(D_projData, projPitch, dims.iProjDets, dims.iProjAngles, 1, 0);
+
+ return sqrt(s);
+}
+
+
+bool doSIRT(float* D_volumeData, unsigned int volumePitch,
+ float* D_sinoData, unsigned int sinoPitch,
+ float* D_maskData, unsigned int maskPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets, unsigned int iterations)
+{
+ SIRT sirt;
+ bool ok = true;
+
+ ok &= sirt.setGeometry(dims, angles);
+ if (D_maskData)
+ ok &= sirt.enableVolumeMask();
+ if (TOffsets)
+ ok &= sirt.setTOffsets(TOffsets);
+
+ if (!ok)
+ return false;
+
+ ok = sirt.init();
+ if (!ok)
+ return false;
+
+ if (D_maskData)
+ ok &= sirt.setVolumeMask(D_maskData, maskPitch);
+
+ ok &= sirt.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch);
+ if (!ok)
+ return false;
+
+ ok = sirt.iterate(iterations);
+
+ return ok;
+}
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA;
+
+int main()
+{
+ float* D_volumeData;
+ float* D_sinoData;
+
+ SDimensions dims;
+ dims.iVolWidth = 1024;
+ dims.iVolHeight = 1024;
+ dims.iProjAngles = 512;
+ dims.iProjDets = 1536;
+ dims.fDetScale = 1.0f;
+ dims.iRaysPerDet = 1;
+ unsigned int volumePitch, sinoPitch;
+
+ allocateVolume(D_volumeData, dims.iVolWidth+2, dims.iVolHeight+2, volumePitch);
+ zeroVolume(D_volumeData, volumePitch, dims.iVolWidth+2, dims.iVolHeight+2);
+ printf("pitch: %u\n", volumePitch);
+
+ allocateVolume(D_sinoData, dims.iProjDets+2, dims.iProjAngles, sinoPitch);
+ zeroVolume(D_sinoData, sinoPitch, dims.iProjDets+2, dims.iProjAngles);
+ printf("pitch: %u\n", sinoPitch);
+
+ unsigned int y, x;
+ float* sino = loadImage("sino.png", y, x);
+
+ float* img = new float[dims.iVolWidth*dims.iVolHeight];
+
+ copySinogramToDevice(sino, dims.iProjDets, dims.iProjDets, dims.iProjAngles, D_sinoData, sinoPitch);
+
+ float* angle = new float[dims.iProjAngles];
+
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i)
+ angle[i] = i*(M_PI/dims.iProjAngles);
+
+ SIRT sirt;
+
+ sirt.setGeometry(dims, angle);
+ sirt.init();
+
+ sirt.setBuffers(D_volumeData, volumePitch, D_sinoData, sinoPitch);
+
+ sirt.iterate(25);
+
+
+ delete[] angle;
+
+ copyVolumeFromDevice(img, dims.iVolWidth, dims.iVolWidth, dims.iVolHeight, D_volumeData, volumePitch);
+
+ saveImage("vol.png",dims.iVolHeight,dims.iVolWidth,img);
+
+ return 0;
+}
+#endif
+
diff --git a/cuda/2d/sirt.h b/cuda/2d/sirt.h
new file mode 100644
index 0000000..5592616
--- /dev/null
+++ b/cuda/2d/sirt.h
@@ -0,0 +1,90 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_SIRT_H
+#define _CUDA_SIRT_H
+
+#include "util.h"
+#include "algo.h"
+
+namespace astraCUDA {
+
+class _AstraExport SIRT : public ReconAlgo {
+public:
+ SIRT();
+ ~SIRT();
+
+ virtual bool init();
+
+ // Set min/max masks to existing GPU memory buffers
+ bool setMinMaxMasks(float* D_minMaskData, float* D_maxMaskData,
+ unsigned int pitch);
+
+ // Set min/max masks from RAM buffers
+ bool uploadMinMaxMasks(const float* minMaskData, const float* maxMaskData,
+ unsigned int pitch);
+
+ virtual bool iterate(unsigned int iterations);
+
+ virtual float computeDiffNorm();
+
+protected:
+ void reset();
+ bool precomputeWeights();
+
+ // Temporary buffers
+ float* D_projData;
+ unsigned int projPitch;
+
+ float* D_tmpData;
+ unsigned int tmpPitch;
+
+ // Geometry-specific precomputed data
+ float* D_lineWeight;
+ unsigned int linePitch;
+
+ float* D_pixelWeight;
+ unsigned int pixelPitch;
+
+ // Masks
+ bool freeMinMaxMasks;
+ float* D_minMaskData;
+ unsigned int minMaskPitch;
+ float* D_maxMaskData;
+ unsigned int maxMaskPitch;
+};
+
+bool doSIRT(float* D_volumeData, unsigned int volumePitch,
+ float* D_projData, unsigned int projPitch,
+ float* D_maskData, unsigned int maskPitch,
+ const SDimensions& dims, const float* angles,
+ const float* TOffsets, unsigned int iterations);
+
+}
+
+#endif
diff --git a/cuda/2d/util.cu b/cuda/2d/util.cu
new file mode 100644
index 0000000..06f6714
--- /dev/null
+++ b/cuda/2d/util.cu
@@ -0,0 +1,244 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include "util.h"
+
+namespace astraCUDA {
+
+bool copyVolumeToDevice(const float* in_data, unsigned int in_pitch,
+ unsigned int width, unsigned int height,
+ float* outD_data, unsigned int out_pitch)
+{
+ // TODO: a full memset isn't necessary. Only the edges.
+ cudaError_t err;
+ err = cudaMemset2D(outD_data, sizeof(float)*out_pitch, 0, sizeof(float)*(width+2), height+2);
+ ASTRA_CUDA_ASSERT(err);
+ err = cudaMemcpy2D(outD_data + out_pitch + 1, sizeof(float)*out_pitch, in_data, sizeof(float)*in_pitch, sizeof(float)*width, height, cudaMemcpyHostToDevice);
+ ASTRA_CUDA_ASSERT(err);
+ assert(err == cudaSuccess);
+ return true;
+}
+
+bool copyVolumeFromDevice(float* out_data, unsigned int out_pitch,
+ unsigned int width, unsigned int height,
+ float* inD_data, unsigned int in_pitch)
+{
+ cudaError_t err = cudaMemcpy2D(out_data, sizeof(float)*out_pitch, inD_data + (in_pitch + 1), sizeof(float)*in_pitch, sizeof(float)*width, height, cudaMemcpyDeviceToHost);
+ ASTRA_CUDA_ASSERT(err);
+ return true;
+}
+
+
+bool copySinogramFromDevice(float* out_data, unsigned int out_pitch,
+ unsigned int width, unsigned int height,
+ float* inD_data, unsigned int in_pitch)
+{
+ cudaError_t err = cudaMemcpy2D(out_data, sizeof(float)*out_pitch, inD_data + 1, sizeof(float)*in_pitch, sizeof(float)*width, height, cudaMemcpyDeviceToHost);
+ ASTRA_CUDA_ASSERT(err);
+ return true;
+}
+
+bool copySinogramToDevice(const float* in_data, unsigned int in_pitch,
+ unsigned int width, unsigned int height,
+ float* outD_data, unsigned int out_pitch)
+{
+ // TODO: a full memset isn't necessary. Only the edges.
+ cudaError_t err;
+ err = cudaMemset2D(outD_data, sizeof(float)*out_pitch, 0, (width+2)*sizeof(float), height);
+ ASTRA_CUDA_ASSERT(err);
+ err = cudaMemcpy2D(outD_data + 1, sizeof(float)*out_pitch, in_data, sizeof(float)*in_pitch, sizeof(float)*width, height, cudaMemcpyHostToDevice);
+ ASTRA_CUDA_ASSERT(err);
+ return true;
+}
+
+
+bool allocateVolume(float*& ptr, unsigned int width, unsigned int height, unsigned int& pitch)
+{
+ size_t p;
+ cudaError_t ret = cudaMallocPitch((void**)&ptr, &p, sizeof(float)*width, height);
+ if (ret != cudaSuccess) {
+ reportCudaError(ret);
+ fprintf(stderr, "Failed to allocate %dx%d GPU buffer\n", width, height);
+ return false;
+ }
+
+ assert(p % sizeof(float) == 0);
+
+ pitch = p / sizeof(float);
+
+ return true;
+}
+
+void zeroVolume(float* data, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ cudaError_t err;
+ err = cudaMemset2D(data, sizeof(float)*pitch, 0, sizeof(float)*width, height);
+ ASTRA_CUDA_ASSERT(err);
+}
+
+
+template <unsigned int blockSize>
+__global__ void reduce1D(float *g_idata, float *g_odata, unsigned int n)
+{
+ extern __shared__ float sdata[];
+ unsigned int tid = threadIdx.x;
+
+ unsigned int i = blockIdx.x*(blockSize*2) + tid;
+ unsigned int gridSize = blockSize*gridDim.x;
+ sdata[tid] = 0;
+ while (i < n) { sdata[tid] += g_idata[i]; i += gridSize; }
+ __syncthreads();
+ if (blockSize >= 512) { if (tid < 256) { sdata[tid] += sdata[tid + 256]; } __syncthreads(); }
+ if (blockSize >= 256) { if (tid < 128) { sdata[tid] += sdata[tid + 128]; } __syncthreads(); }
+ if (blockSize >= 128) { if (tid < 64) { sdata[tid] += sdata[tid + 64]; } __syncthreads(); }
+ if (tid < 32) {
+ volatile float* smem = sdata;
+ if (blockSize >= 64) smem[tid] += smem[tid + 32];
+ if (blockSize >= 32) smem[tid] += smem[tid + 16];
+ if (blockSize >= 16) smem[tid] += smem[tid + 8];
+ if (blockSize >= 8) smem[tid] += smem[tid + 4];
+ if (blockSize >= 4) smem[tid] += smem[tid + 2];
+ if (blockSize >= 2) smem[tid] += smem[tid + 1];
+ }
+ if (tid == 0) g_odata[blockIdx.x] = sdata[0];
+}
+
+__global__ void reduce2D(float *g_idata, float *g_odata,
+ unsigned int pitch,
+ unsigned int nx, unsigned int ny,
+ unsigned int padX, unsigned int padY)
+{
+ extern __shared__ float sdata[];
+ const unsigned int tidx = threadIdx.x;
+ const unsigned int tidy = threadIdx.y;
+ const unsigned int tid = tidy * 16 + tidx;
+
+ unsigned int x = blockIdx.x*16 + tidx;
+ unsigned int y = blockIdx.y*16 + tidy;
+
+ sdata[tid] = 0;
+
+ if (x >= padX && x < padX + nx) {
+
+ while (y < padY + ny) {
+ if (y >= padY)
+ sdata[tid] += (g_idata[pitch*y+x] * g_idata[pitch*y+x]);
+ y += 16 * gridDim.y;
+ }
+
+ }
+
+ __syncthreads();
+
+ if (tid < 128)
+ sdata[tid] += sdata[tid + 128];
+ __syncthreads();
+
+ if (tid < 64)
+ sdata[tid] += sdata[tid + 64];
+ __syncthreads();
+
+ if (tid < 32) { // 32 is warp size
+ volatile float* smem = sdata;
+ smem[tid] += smem[tid + 32];
+ smem[tid] += smem[tid + 16];
+ smem[tid] += smem[tid + 8];
+ smem[tid] += smem[tid + 4];
+ smem[tid] += smem[tid + 2];
+ smem[tid] += smem[tid + 1];
+ }
+
+ if (tid == 0)
+ g_odata[blockIdx.y * gridDim.x + blockIdx.x] = sdata[0];
+}
+
+float dotProduct2D(float* D_data, unsigned int pitch,
+ unsigned int width, unsigned int height,
+ unsigned int padX, unsigned int padY)
+{
+ unsigned int bx = ((width+padX) + 15) / 16;
+ unsigned int by = ((height+padY) + 127) / 128;
+ unsigned int shared_mem2 = sizeof(float) * 16 * 16;
+
+ dim3 dimBlock2(16, 16);
+ dim3 dimGrid2(bx, by);
+
+ float* D_buf;
+ cudaMalloc(&D_buf, sizeof(float) * (bx * by + 1) );
+
+ // Step 1: reduce 2D from image to a single vector, taking sum of squares
+
+ reduce2D<<< dimGrid2, dimBlock2, shared_mem2>>>(D_data, D_buf, pitch, width, height, padX, padY);
+ cudaTextForceKernelsCompletion();
+
+ // Step 2: reduce 1D: add up elements in vector
+ if (bx * by > 512)
+ reduce1D<512><<< 1, 512, sizeof(float)*512>>>(D_buf, D_buf+(bx*by), bx*by);
+ else if (bx * by > 128)
+ reduce1D<128><<< 1, 128, sizeof(float)*128>>>(D_buf, D_buf+(bx*by), bx*by);
+ else if (bx * by > 32)
+ reduce1D<32><<< 1, 32, sizeof(float)*32*2>>>(D_buf, D_buf+(bx*by), bx*by);
+ else if (bx * by > 8)
+ reduce1D<8><<< 1, 8, sizeof(float)*8*2>>>(D_buf, D_buf+(bx*by), bx*by);
+ else
+ reduce1D<1><<< 1, 1, sizeof(float)*1*2>>>(D_buf, D_buf+(bx*by), bx*by);
+
+ float x;
+ cudaMemcpy(&x, D_buf+(bx*by), 4, cudaMemcpyDeviceToHost);
+
+ cudaTextForceKernelsCompletion();
+
+ cudaFree(D_buf);
+
+ return x;
+}
+
+
+bool cudaTextForceKernelsCompletion()
+{
+ cudaError_t returnedCudaError = cudaThreadSynchronize();
+
+ if(returnedCudaError != cudaSuccess) {
+ fprintf(stderr, "Failed to force completion of cuda kernels: %d: %s.\n", returnedCudaError, cudaGetErrorString(returnedCudaError));
+ return false;
+ }
+
+ return true;
+}
+
+void reportCudaError(cudaError_t err)
+{
+ if(err != cudaSuccess)
+ fprintf(stderr, "CUDA error %d: %s.\n", err, cudaGetErrorString(err));
+}
+
+
+
+}
diff --git a/cuda/2d/util.h b/cuda/2d/util.h
new file mode 100644
index 0000000..d31e2eb
--- /dev/null
+++ b/cuda/2d/util.h
@@ -0,0 +1,90 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_UTIL_H
+#define _CUDA_UTIL_H
+
+#include <cuda.h>
+#include <driver_types.h>
+
+#ifdef _MSC_VER
+
+#ifdef DLL_EXPORTS
+#define _AstraExport __declspec(dllexport)
+#define EXPIMP_TEMPLATE
+#else
+#define _AstraExport __declspec(dllimport)
+#define EXPIMP_TEMPLATE extern
+#endif
+
+#else
+
+#define _AstraExport
+
+#endif
+
+#include "dims.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define ASTRA_CUDA_ASSERT(err) do { if (err != cudaSuccess) { astraCUDA::reportCudaError(err); assert(err == cudaSuccess); } } while(0)
+
+
+namespace astraCUDA {
+
+bool copyVolumeToDevice(const float* in_data, unsigned int in_pitch,
+ unsigned int width, unsigned int height,
+ float* outD_data, unsigned int out_pitch);
+bool copyVolumeFromDevice(float* out_data, unsigned int out_pitch,
+ unsigned int width, unsigned int height,
+ float* inD_data, unsigned int in_pitch);
+bool copySinogramFromDevice(float* out_data, unsigned int out_pitch,
+ unsigned int width, unsigned int height,
+ float* inD_data, unsigned int in_pitch);
+bool copySinogramToDevice(const float* in_data, unsigned int in_pitch,
+ unsigned int width, unsigned int height,
+ float* outD_data, unsigned int out_pitch);
+
+bool allocateVolume(float*& D_ptr, unsigned int width, unsigned int height, unsigned int& pitch);
+
+void zeroVolume(float* D_data, unsigned int pitch, unsigned int width, unsigned int height);
+
+bool cudaTextForceKernelsCompletion();
+void reportCudaError(cudaError_t err);
+
+
+
+float dotProduct2D(float* D_data, unsigned int pitch,
+ unsigned int width, unsigned int height,
+ unsigned int padX, unsigned int padY);
+
+}
+
+#endif
diff --git a/cuda/3d/algo3d.cu b/cuda/3d/algo3d.cu
new file mode 100644
index 0000000..20e7381
--- /dev/null
+++ b/cuda/3d/algo3d.cu
@@ -0,0 +1,108 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cassert>
+
+#include "algo3d.h"
+#include "cone_fp.h"
+#include "cone_bp.h"
+#include "par3d_fp.h"
+#include "par3d_bp.h"
+
+namespace astraCUDA3d {
+
+ReconAlgo3D::ReconAlgo3D()
+{
+ coneProjs = 0;
+ par3DProjs = 0;
+ shouldAbort = false;
+}
+
+ReconAlgo3D::~ReconAlgo3D()
+{
+ reset();
+}
+
+void ReconAlgo3D::reset()
+{
+ delete[] coneProjs;
+ coneProjs = 0;
+ delete[] par3DProjs;
+ par3DProjs = 0;
+ shouldAbort = false;
+}
+
+bool ReconAlgo3D::setConeGeometry(const SDimensions3D& _dims, const SConeProjection* _angles)
+{
+ dims = _dims;
+
+ coneProjs = new SConeProjection[dims.iProjAngles];
+ par3DProjs = 0;
+
+ memcpy(coneProjs, _angles, sizeof(coneProjs[0]) * dims.iProjAngles);
+
+ return true;
+}
+
+bool ReconAlgo3D::setPar3DGeometry(const SDimensions3D& _dims, const SPar3DProjection* _angles)
+{
+ dims = _dims;
+
+ par3DProjs = new SPar3DProjection[dims.iProjAngles];
+ coneProjs = 0;
+
+ memcpy(par3DProjs, _angles, sizeof(par3DProjs[0]) * dims.iProjAngles);
+
+ return true;
+}
+
+
+bool ReconAlgo3D::callFP(cudaPitchedPtr& D_volumeData,
+ cudaPitchedPtr& D_projData,
+ float outputScale)
+{
+ if (coneProjs) {
+ return ConeFP(D_volumeData, D_projData, dims, coneProjs, outputScale);
+ } else {
+ return Par3DFP(D_volumeData, D_projData, dims, par3DProjs, outputScale);
+ }
+}
+
+bool ReconAlgo3D::callBP(cudaPitchedPtr& D_volumeData,
+ cudaPitchedPtr& D_projData)
+{
+ if (coneProjs) {
+ return ConeBP(D_volumeData, D_projData, dims, coneProjs);
+ } else {
+ return Par3DBP(D_volumeData, D_projData, dims, par3DProjs);
+ }
+}
+
+
+
+}
diff --git a/cuda/3d/algo3d.h b/cuda/3d/algo3d.h
new file mode 100644
index 0000000..2b44f6f
--- /dev/null
+++ b/cuda/3d/algo3d.h
@@ -0,0 +1,68 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_ALGO_H
+#define _CUDA_ALGO_H
+
+#include "dims3d.h"
+#include "util3d.h"
+
+namespace astraCUDA3d {
+
+class _AstraExport ReconAlgo3D {
+public:
+ ReconAlgo3D();
+ ~ReconAlgo3D();
+
+ bool setConeGeometry(const SDimensions3D& dims, const SConeProjection* projs);
+ bool setPar3DGeometry(const SDimensions3D& dims, const SPar3DProjection* projs);
+
+ void signalAbort() { shouldAbort = true; }
+
+protected:
+ void reset();
+
+ bool callFP(cudaPitchedPtr& D_volumeData,
+ cudaPitchedPtr& D_projData,
+ float outputScale);
+ bool callBP(cudaPitchedPtr& D_volumeData,
+ cudaPitchedPtr& D_projData);
+
+ SDimensions3D dims;
+ SConeProjection* coneProjs;
+ SPar3DProjection* par3DProjs;
+
+ volatile bool shouldAbort;
+
+};
+
+
+}
+
+#endif
+
diff --git a/cuda/3d/arith3d.cu b/cuda/3d/arith3d.cu
new file mode 100644
index 0000000..9a19be0
--- /dev/null
+++ b/cuda/3d/arith3d.cu
@@ -0,0 +1,610 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "util3d.h"
+#include "arith3d.h"
+#include <cassert>
+
+namespace astraCUDA3d {
+
+struct opAddScaled {
+ __device__ void operator()(float& out, const float in, const float inp) {
+ out += in * inp;
+ }
+};
+struct opScaleAndAdd {
+ __device__ void operator()(float& out, const float in, const float inp) {
+ out = in + out * inp;
+ }
+};
+struct opAddMulScaled {
+ __device__ void operator()(float& out, const float in1, const float in2, const float inp) {
+ out += in1 * in2 * inp;
+ }
+};
+struct opAddMul {
+ __device__ void operator()(float& out, const float in1, const float in2) {
+ out += in1 * in2;
+ }
+};
+struct opMul {
+ __device__ void operator()(float& out, const float in) {
+ out *= in;
+ }
+};
+struct opMul2 {
+ __device__ void operator()(float& out, const float in1, const float in2) {
+ out *= in1 * in2;
+ }
+};
+struct opDividedBy {
+ __device__ void operator()(float& out, const float in) {
+ if (out > 0.000001f) // out is assumed to be positive
+ out = in / out;
+ else
+ out = 0.0f;
+ }
+};
+struct opInvert {
+ __device__ void operator()(float& out) {
+ if (out > 0.000001f) // out is assumed to be positive
+ out = 1 / out;
+ else
+ out = 0.0f;
+ }
+};
+struct opSet {
+ __device__ void operator()(float& out, const float inp) {
+ out = inp;
+ }
+};
+struct opClampMin {
+ __device__ void operator()(float& out, const float inp) {
+ if (out < inp)
+ out = inp;
+ }
+};
+struct opClampMax {
+ __device__ void operator()(float& out, const float inp) {
+ if (out > inp)
+ out = inp;
+ }
+};
+
+
+
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devtoD(float* pfOut, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off]);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devFtoD(float* pfOut, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], fParam);
+ off += pitch;
+ y++;
+ }
+}
+
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devDtoD(float* pfOut, const float* pfIn, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], pfIn[off]);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devDFtoD(float* pfOut, const float* pfIn, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], pfIn[off], fParam);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devDDtoD(float* pfOut, const float* pfIn1, const float* pfIn2, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], pfIn1[off], pfIn2[off]);
+ off += pitch;
+ y++;
+ }
+}
+
+template<class op, unsigned int padX, unsigned int padY, unsigned int repeat>
+__global__ void devDDFtoD(float* pfOut, const float* pfIn1, const float* pfIn2, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ if (x >= width) return;
+
+ unsigned int y = (threadIdx.y + 16*blockIdx.y)*repeat;
+ unsigned int off = (y+padY)*pitch+x+padX;
+ for (unsigned int i = 0; i < repeat; ++i) {
+ if (y >= height)
+ break;
+ op()(pfOut[off], pfIn1[off], pfIn2[off], fParam);
+ off += pitch;
+ y++;
+ }
+}
+
+
+
+
+
+
+
+
+
+template<typename op, VolType t>
+void processVol(CUdeviceptr* out, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+511)/512);
+
+ float *pfOut = (float*)out;
+
+ devtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(CUdeviceptr* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ float *pfOut = (float*)out;
+
+ devFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, fParam, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(CUdeviceptr* out, const CUdeviceptr* in, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ float *pfOut = (float*)out;
+ const float *pfIn = (const float*)in;
+
+ devDtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(CUdeviceptr* out, const CUdeviceptr* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ float *pfOut = (float*)out;
+ const float *pfIn = (const float*)in;
+
+ devDFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ float *pfOut = (float*)out;
+ const float *pfIn1 = (const float*)in1;
+ const float *pfIn2 = (const float*)in2;
+
+ devDDFtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op, VolType t>
+void processVol(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, unsigned int pitch, unsigned int width, unsigned int height)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((width+15)/16, (height+15)/16);
+
+ float *pfOut = (float*)out;
+ const float *pfIn1 = (const float*)in1;
+ const float *pfIn2 = (const float*)in2;
+
+ devDDtoD<op, 1, t, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, pitch, width, height);
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn = (float*)in.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ pfIn += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn = (float*)in.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ pfIn += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn1 = (float*)in1.ptr;
+ float *pfIn2 = (float*)in2.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devDDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ pfIn1 += step;
+ pfIn2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn1 = (float*)in1.ptr;
+ float *pfIn2 = (float*)in2.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iVolY;
+
+ for (unsigned int i = 0; i < dims.iVolZ; ++i) {
+ devDDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, out.pitch/sizeof(float), dims.iVolX, dims.iVolY);
+ pfOut += step;
+ pfIn1 += step;
+ pfIn2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn = (float*)in.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ pfIn += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn = (float*)in.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ pfIn += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn1 = (float*)in1.ptr;
+ float *pfIn2 = (float*)in2.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devDDFtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, fParam, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ pfIn1 += step;
+ pfIn2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+template<typename op>
+void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims)
+{
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iProjU+15)/16, (dims.iProjAngles+511)/512);
+ float *pfOut = (float*)out.ptr;
+ float *pfIn1 = (float*)in1.ptr;
+ float *pfIn2 = (float*)in2.ptr;
+ unsigned int step = out.pitch/sizeof(float) * dims.iProjAngles;
+
+ for (unsigned int i = 0; i < dims.iProjV; ++i) {
+ devDDtoD<op, 0, 0, 32><<<gridSize, blockSize>>>(pfOut, pfIn1, pfIn2, out.pitch/sizeof(float), dims.iProjU, dims.iProjAngles);
+ pfOut += step;
+ pfIn1 += step;
+ pfIn2 += step;
+ }
+
+ cudaTextForceKernelsCompletion();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define INST_DFtoD(name) \
+ template void processVol<name, VOL>(CUdeviceptr* out, const CUdeviceptr* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(CUdeviceptr* out, const CUdeviceptr* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims);
+
+#define INST_DtoD(name) \
+ template void processVol<name, VOL>(CUdeviceptr* out, const CUdeviceptr* in, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(CUdeviceptr* out, const CUdeviceptr* in, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims);
+
+#define INST_DDtoD(name) \
+ template void processVol<name, VOL>(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims);
+
+#define INST_DDFtoD(name) \
+ template void processVol<name, VOL>(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims);
+
+
+#define INST_toD(name) \
+ template void processVol<name, VOL>(CUdeviceptr* out, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(CUdeviceptr* out, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, const SDimensions3D& dims);
+
+#define INST_FtoD(name) \
+ template void processVol<name, VOL>(CUdeviceptr* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol<name, SINO>(CUdeviceptr* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height); \
+ template void processVol3D<name>(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims); \
+ template void processSino3D<name>(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims);
+
+
+
+INST_DFtoD(opAddScaled)
+INST_DFtoD(opScaleAndAdd)
+INST_DDFtoD(opAddMulScaled)
+INST_DDtoD(opAddMul)
+INST_DDtoD(opMul2)
+INST_DtoD(opMul)
+INST_DtoD(opDividedBy)
+INST_toD(opInvert)
+INST_FtoD(opSet)
+INST_FtoD(opClampMin)
+INST_FtoD(opClampMax)
+
+
+}
diff --git a/cuda/3d/arith3d.h b/cuda/3d/arith3d.h
new file mode 100644
index 0000000..53c9b79
--- /dev/null
+++ b/cuda/3d/arith3d.h
@@ -0,0 +1,79 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_ARITH3D_H
+#define _CUDA_ARITH3D_H
+
+#include <cuda.h>
+
+namespace astraCUDA3d {
+
+struct opAddScaled;
+struct opScaleAndAdd;
+struct opAddMulScaled;
+struct opAddMul;
+struct opMul;
+struct opMul2;
+struct opDividedBy;
+struct opInvert;
+struct opSet;
+struct opClampMin;
+struct opClampMax;
+
+enum VolType {
+ SINO = 0,
+ VOL = 1
+};
+
+
+template<typename op, VolType t> void processVol(CUdeviceptr* out, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(CUdeviceptr* out, float fParam, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(CUdeviceptr* out, const CUdeviceptr* in, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(CUdeviceptr* out, const CUdeviceptr* in, float fParam, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, float fParam, unsigned int pitch, unsigned int width, unsigned int height);
+template<typename op, VolType t> void processVol(CUdeviceptr* out, const CUdeviceptr* in1, const CUdeviceptr* in2, unsigned int pitch, unsigned int width, unsigned int height);
+
+template<typename op> void processVol3D(cudaPitchedPtr& out, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims);
+template<typename op> void processVol3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims);
+
+template<typename op> void processSino3D(cudaPitchedPtr& out, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, float fParam, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in, float fParam, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, float fParam, const SDimensions3D& dims);
+template<typename op> void processSino3D(cudaPitchedPtr& out, const cudaPitchedPtr& in1, const cudaPitchedPtr& in2, const SDimensions3D& dims);
+
+
+
+}
+
+#endif
diff --git a/cuda/3d/astra3d.cu b/cuda/3d/astra3d.cu
new file mode 100644
index 0000000..fd4b370
--- /dev/null
+++ b/cuda/3d/astra3d.cu
@@ -0,0 +1,1620 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+
+#include "cgls3d.h"
+#include "sirt3d.h"
+#include "util3d.h"
+#include "cone_fp.h"
+#include "cone_bp.h"
+#include "par3d_fp.h"
+#include "par3d_bp.h"
+#include "fdk.h"
+#include "arith3d.h"
+#include "astra3d.h"
+
+#include <iostream>
+
+using namespace astraCUDA3d;
+
+namespace astra {
+
+enum CUDAProjectionType3d {
+ PROJ_PARALLEL,
+ PROJ_CONE
+};
+
+
+static SConeProjection* genConeProjections(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ double fOriginSourceDistance,
+ double fOriginDetectorDistance,
+ double fDetUSize,
+ double fDetVSize,
+ const float *pfAngles)
+{
+ SConeProjection base;
+ base.fSrcX = 0.0f;
+ base.fSrcY = -fOriginSourceDistance;
+ base.fSrcZ = 0.0f;
+
+ base.fDetSX = iProjU * fDetUSize * -0.5f;
+ base.fDetSY = fOriginDetectorDistance;
+ base.fDetSZ = iProjV * fDetVSize * -0.5f;
+
+ base.fDetUX = fDetUSize;
+ base.fDetUY = 0.0f;
+ base.fDetUZ = 0.0f;
+
+ base.fDetVX = 0.0f;
+ base.fDetVY = 0.0f;
+ base.fDetVZ = fDetVSize;
+
+ SConeProjection* p = new SConeProjection[iProjAngles];
+
+#define ROTATE0(name,i,alpha) do { p[i].f##name##X = base.f##name##X * cos(alpha) - base.f##name##Y * sin(alpha); p[i].f##name##Y = base.f##name##X * sin(alpha) + base.f##name##Y * cos(alpha); p[i].f##name##Z = base.f##name##Z; } while(0)
+
+ for (unsigned int i = 0; i < iProjAngles; ++i) {
+ ROTATE0(Src, i, pfAngles[i]);
+ ROTATE0(DetS, i, pfAngles[i]);
+ ROTATE0(DetU, i, pfAngles[i]);
+ ROTATE0(DetV, i, pfAngles[i]);
+ }
+
+#undef ROTATE0
+
+ return p;
+}
+
+static SPar3DProjection* genPar3DProjections(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ double fDetUSize,
+ double fDetVSize,
+ const float *pfAngles)
+{
+ SPar3DProjection base;
+ base.fRayX = 0.0f;
+ base.fRayY = 1.0f;
+ base.fRayZ = 0.0f;
+
+ base.fDetSX = iProjU * fDetUSize * -0.5f;
+ base.fDetSY = 0.0f;
+ base.fDetSZ = iProjV * fDetVSize * -0.5f;
+
+ base.fDetUX = fDetUSize;
+ base.fDetUY = 0.0f;
+ base.fDetUZ = 0.0f;
+
+ base.fDetVX = 0.0f;
+ base.fDetVY = 0.0f;
+ base.fDetVZ = fDetVSize;
+
+ SPar3DProjection* p = new SPar3DProjection[iProjAngles];
+
+#define ROTATE0(name,i,alpha) do { p[i].f##name##X = base.f##name##X * cos(alpha) - base.f##name##Y * sin(alpha); p[i].f##name##Y = base.f##name##X * sin(alpha) + base.f##name##Y * cos(alpha); p[i].f##name##Z = base.f##name##Z; } while(0)
+
+ for (unsigned int i = 0; i < iProjAngles; ++i) {
+ ROTATE0(Ray, i, pfAngles[i]);
+ ROTATE0(DetS, i, pfAngles[i]);
+ ROTATE0(DetU, i, pfAngles[i]);
+ ROTATE0(DetV, i, pfAngles[i]);
+ }
+
+#undef ROTATE0
+
+ return p;
+}
+
+
+
+
+class AstraSIRT3d_internal {
+public:
+ SDimensions3D dims;
+ CUDAProjectionType3d projType;
+
+ float* angles;
+ float fOriginSourceDistance;
+ float fOriginDetectorDistance;
+ float fSourceZ;
+ float fDetSize;
+
+ SConeProjection* projs;
+ SPar3DProjection* parprojs;
+
+ float fPixelSize;
+
+ bool initialized;
+ bool setStartReconstruction;
+
+ bool useVolumeMask;
+ bool useSinogramMask;
+
+ // Input/output
+ cudaPitchedPtr D_projData;
+ cudaPitchedPtr D_volumeData;
+ cudaPitchedPtr D_maskData;
+ cudaPitchedPtr D_smaskData;
+
+ SIRT sirt;
+};
+
+AstraSIRT3d::AstraSIRT3d()
+{
+ pData = new AstraSIRT3d_internal();
+
+ pData->angles = 0;
+ pData->D_projData.ptr = 0;
+ pData->D_volumeData.ptr = 0;
+ pData->D_maskData.ptr = 0;
+ pData->D_smaskData.ptr = 0;
+
+ pData->dims.iVolX = 0;
+ pData->dims.iVolY = 0;
+ pData->dims.iVolZ = 0;
+ pData->dims.iProjAngles = 0;
+ pData->dims.iProjU = 0;
+ pData->dims.iProjV = 0;
+ pData->dims.iRaysPerDetDim = 1;
+ pData->dims.iRaysPerVoxelDim = 1;
+
+ pData->projs = 0;
+
+ pData->initialized = false;
+ pData->setStartReconstruction = false;
+
+ pData->useVolumeMask = false;
+ pData->useSinogramMask = false;
+}
+
+AstraSIRT3d::~AstraSIRT3d()
+{
+ delete[] pData->angles;
+ pData->angles = 0;
+
+ delete[] pData->projs;
+ pData->projs = 0;
+
+ cudaFree(pData->D_projData.ptr);
+ pData->D_projData.ptr = 0;
+
+ cudaFree(pData->D_volumeData.ptr);
+ pData->D_volumeData.ptr = 0;
+
+ cudaFree(pData->D_maskData.ptr);
+ pData->D_maskData.ptr = 0;
+
+ cudaFree(pData->D_smaskData.ptr);
+ pData->D_smaskData.ptr = 0;
+
+ delete pData;
+ pData = 0;
+}
+
+bool AstraSIRT3d::setReconstructionGeometry(unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ/*,
+ float fPixelSize = 1.0f*/)
+{
+ if (pData->initialized)
+ return false;
+
+ pData->dims.iVolX = iVolX;
+ pData->dims.iVolY = iVolY;
+ pData->dims.iVolZ = iVolZ;
+
+ return (iVolX > 0 && iVolY > 0 && iVolZ > 0);
+}
+
+
+bool AstraSIRT3d::setPar3DGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SPar3DProjection* projs)
+{
+ if (pData->initialized)
+ return false;
+
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjU = iProjU;
+ pData->dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || projs == 0)
+ return false;
+
+ pData->parprojs = new SPar3DProjection[iProjAngles];
+ memcpy(pData->parprojs, projs, iProjAngles * sizeof(projs[0]));
+
+ pData->projType = PROJ_PARALLEL;
+
+ return true;
+}
+
+bool AstraSIRT3d::setPar3DGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles)
+{
+ if (pData->initialized)
+ return false;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ SPar3DProjection* p = genPar3DProjections(iProjAngles,
+ iProjU, iProjV,
+ fDetUSize, fDetVSize,
+ pfAngles);
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjU = iProjU;
+ pData->dims.iProjV = iProjV;
+
+ pData->parprojs = p;
+ pData->projType = PROJ_PARALLEL;
+
+ return true;
+}
+
+
+
+bool AstraSIRT3d::setConeGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SConeProjection* projs)
+{
+ if (pData->initialized)
+ return false;
+
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjU = iProjU;
+ pData->dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || projs == 0)
+ return false;
+
+ pData->projs = new SConeProjection[iProjAngles];
+ memcpy(pData->projs, projs, iProjAngles * sizeof(projs[0]));
+
+ pData->projType = PROJ_CONE;
+
+ return true;
+}
+
+bool AstraSIRT3d::setConeGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles)
+{
+ if (pData->initialized)
+ return false;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ SConeProjection* p = genConeProjections(iProjAngles,
+ iProjU, iProjV,
+ fOriginSourceDistance,
+ fOriginDetectorDistance,
+ fDetUSize, fDetVSize,
+ pfAngles);
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjU = iProjU;
+ pData->dims.iProjV = iProjV;
+
+ pData->projs = p;
+ pData->projType = PROJ_CONE;
+
+ return true;
+}
+
+bool AstraSIRT3d::enableSuperSampling(unsigned int iVoxelSuperSampling,
+ unsigned int iDetectorSuperSampling)
+{
+ if (pData->initialized)
+ return false;
+
+ if (iVoxelSuperSampling == 0 || iDetectorSuperSampling == 0)
+ return false;
+
+ pData->dims.iRaysPerVoxelDim = iVoxelSuperSampling;
+ pData->dims.iRaysPerDetDim = iDetectorSuperSampling;
+
+ return true;
+}
+
+bool AstraSIRT3d::enableVolumeMask()
+{
+ if (pData->initialized)
+ return false;
+
+ bool ok = pData->sirt.enableVolumeMask();
+ pData->useVolumeMask = ok;
+
+ return ok;
+}
+
+bool AstraSIRT3d::enableSinogramMask()
+{
+ if (pData->initialized)
+ return false;
+
+ bool ok = pData->sirt.enableSinogramMask();
+ pData->useSinogramMask = ok;
+
+ return ok;
+}
+
+bool AstraSIRT3d::setGPUIndex(int index)
+{
+ cudaSetDevice(index);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+ return true;
+}
+
+bool AstraSIRT3d::init()
+{
+ fprintf(stderr, "001: %d\n", true);
+ if (pData->initialized)
+ return false;
+ fprintf(stderr, "002: %d\n", true);
+
+ if (pData->dims.iVolX == 0 || pData->dims.iProjAngles == 0)
+ return false;
+ fprintf(stderr, "003: %d\n", true);
+
+ bool ok;
+
+ if (pData->projType == PROJ_PARALLEL) {
+ ok = pData->sirt.setPar3DGeometry(pData->dims, pData->parprojs);
+ } else {
+ ok = pData->sirt.setConeGeometry(pData->dims, pData->projs);
+ }
+ fprintf(stderr, "004: %d\n", ok);
+
+ if (!ok)
+ return false;
+
+ ok = pData->sirt.init();
+ if (!ok)
+ return false;
+ fprintf(stderr, "005: %d\n", ok);
+
+ pData->D_volumeData = allocateVolumeData(pData->dims);
+ ok = pData->D_volumeData.ptr;
+ if (!ok)
+ return false;
+ fprintf(stderr, "006: %d\n", ok);
+
+ fprintf(stderr, "proj: %d %d %d\n", pData->dims.iProjAngles, pData->dims.iProjU, pData->dims.iProjV);
+ pData->D_projData = allocateProjectionData(pData->dims);
+ ok = pData->D_projData.ptr;
+ if (!ok) {
+ cudaFree(pData->D_volumeData.ptr);
+ pData->D_volumeData.ptr = 0;
+ return false;
+ }
+ fprintf(stderr, "007: %d\n", ok);
+
+ if (pData->useVolumeMask) {
+ pData->D_maskData = allocateVolumeData(pData->dims);
+ ok = pData->D_maskData.ptr;
+ if (!ok) {
+ cudaFree(pData->D_volumeData.ptr);
+ cudaFree(pData->D_projData.ptr);
+ pData->D_volumeData.ptr = 0;
+ pData->D_projData.ptr = 0;
+ return false;
+ }
+ }
+
+ if (pData->useSinogramMask) {
+ pData->D_smaskData = allocateProjectionData(pData->dims);
+ ok = pData->D_smaskData.ptr;
+ if (!ok) {
+ cudaFree(pData->D_volumeData.ptr);
+ cudaFree(pData->D_projData.ptr);
+ cudaFree(pData->D_maskData.ptr);
+ pData->D_volumeData.ptr = 0;
+ pData->D_projData.ptr = 0;
+ pData->D_maskData.ptr = 0;
+ return false;
+ }
+ }
+ fprintf(stderr, "008: %d\n", ok);
+
+ pData->initialized = true;
+
+ return true;
+}
+
+bool AstraSIRT3d::setMinConstraint(float fMin)
+{
+ if (!pData->initialized)
+ return false;
+ return pData->sirt.setMinConstraint(fMin);
+}
+
+bool AstraSIRT3d::setMaxConstraint(float fMax)
+{
+ if (!pData->initialized)
+ return false;
+ return pData->sirt.setMaxConstraint(fMax);
+}
+
+bool AstraSIRT3d::setSinogram(const float* pfSinogram,
+ unsigned int iSinogramPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pfSinogram)
+ return false;
+
+ bool ok = copyProjectionsToDevice(pfSinogram, pData->D_projData, pData->dims, iSinogramPitch);
+
+ if (!ok)
+ return false;
+
+ ok = pData->sirt.setBuffers(pData->D_volumeData, pData->D_projData);
+ if (!ok)
+ return false;
+
+ pData->setStartReconstruction = false;
+
+ return true;
+}
+
+bool AstraSIRT3d::setVolumeMask(const float* pfMask, unsigned int iMaskPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pData->useVolumeMask)
+ return false;
+ if (!pfMask)
+ return false;
+
+ bool ok = copyVolumeToDevice(pfMask, pData->D_maskData,
+ pData->dims, iMaskPitch);
+ if (!ok)
+ return false;
+
+ ok = pData->sirt.setVolumeMask(pData->D_maskData);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+bool AstraSIRT3d::setSinogramMask(const float* pfMask, unsigned int iMaskPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pData->useSinogramMask)
+ return false;
+ if (!pfMask)
+ return false;
+
+ bool ok = copyProjectionsToDevice(pfMask, pData->D_smaskData, pData->dims, iMaskPitch);
+
+ if (!ok)
+ return false;
+
+ ok = pData->sirt.setSinogramMask(pData->D_smaskData);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+bool AstraSIRT3d::setStartReconstruction(const float* pfReconstruction,
+ unsigned int iReconstructionPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pfReconstruction)
+ return false;
+
+ bool ok = copyVolumeToDevice(pfReconstruction, pData->D_volumeData,
+ pData->dims, iReconstructionPitch);
+ if (!ok)
+ return false;
+
+ pData->setStartReconstruction = true;
+
+ return true;
+}
+
+bool AstraSIRT3d::iterate(unsigned int iIterations)
+{
+ if (!pData->initialized)
+ return false;
+
+ if (!pData->setStartReconstruction)
+ zeroVolumeData(pData->D_volumeData, pData->dims);
+
+ bool ok = pData->sirt.iterate(iIterations);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+bool AstraSIRT3d::getReconstruction(float* pfReconstruction,
+ unsigned int iReconstructionPitch) const
+{
+ if (!pData->initialized)
+ return false;
+
+ bool ok = copyVolumeFromDevice(pfReconstruction, pData->D_volumeData,
+ pData->dims, iReconstructionPitch);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+void AstraSIRT3d::signalAbort()
+{
+ if (!pData->initialized)
+ return;
+
+ pData->sirt.signalAbort();
+}
+
+float AstraSIRT3d::computeDiffNorm()
+{
+ if (!pData->initialized)
+ return 0.0f; // FIXME: Error?
+
+ return pData->sirt.computeDiffNorm();
+}
+
+
+
+
+class AstraCGLS3d_internal {
+public:
+ SDimensions3D dims;
+ CUDAProjectionType3d projType;
+
+ float* angles;
+ float fOriginSourceDistance;
+ float fOriginDetectorDistance;
+ float fSourceZ;
+ float fDetSize;
+
+ SConeProjection* projs;
+ SPar3DProjection* parprojs;
+
+ float fPixelSize;
+
+ bool initialized;
+ bool setStartReconstruction;
+
+ bool useVolumeMask;
+ bool useSinogramMask;
+
+ // Input/output
+ cudaPitchedPtr D_projData;
+ cudaPitchedPtr D_volumeData;
+ cudaPitchedPtr D_maskData;
+ cudaPitchedPtr D_smaskData;
+
+ CGLS cgls;
+};
+
+AstraCGLS3d::AstraCGLS3d()
+{
+ pData = new AstraCGLS3d_internal();
+
+ pData->angles = 0;
+ pData->D_projData.ptr = 0;
+ pData->D_volumeData.ptr = 0;
+ pData->D_maskData.ptr = 0;
+ pData->D_smaskData.ptr = 0;
+
+ pData->dims.iVolX = 0;
+ pData->dims.iVolY = 0;
+ pData->dims.iVolZ = 0;
+ pData->dims.iProjAngles = 0;
+ pData->dims.iProjU = 0;
+ pData->dims.iProjV = 0;
+ pData->dims.iRaysPerDetDim = 1;
+ pData->dims.iRaysPerVoxelDim = 1;
+
+ pData->projs = 0;
+
+ pData->initialized = false;
+ pData->setStartReconstruction = false;
+
+ pData->useVolumeMask = false;
+ pData->useSinogramMask = false;
+}
+
+AstraCGLS3d::~AstraCGLS3d()
+{
+ delete[] pData->angles;
+ pData->angles = 0;
+
+ delete[] pData->projs;
+ pData->projs = 0;
+
+ cudaFree(pData->D_projData.ptr);
+ pData->D_projData.ptr = 0;
+
+ cudaFree(pData->D_volumeData.ptr);
+ pData->D_volumeData.ptr = 0;
+
+ cudaFree(pData->D_maskData.ptr);
+ pData->D_maskData.ptr = 0;
+
+ cudaFree(pData->D_smaskData.ptr);
+ pData->D_smaskData.ptr = 0;
+
+ delete pData;
+ pData = 0;
+}
+
+bool AstraCGLS3d::setReconstructionGeometry(unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ/*,
+ float fPixelSize = 1.0f*/)
+{
+ if (pData->initialized)
+ return false;
+
+ pData->dims.iVolX = iVolX;
+ pData->dims.iVolY = iVolY;
+ pData->dims.iVolZ = iVolZ;
+
+ return (iVolX > 0 && iVolY > 0 && iVolZ > 0);
+}
+
+
+bool AstraCGLS3d::setPar3DGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SPar3DProjection* projs)
+{
+ if (pData->initialized)
+ return false;
+
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjU = iProjU;
+ pData->dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || projs == 0)
+ return false;
+
+ pData->parprojs = new SPar3DProjection[iProjAngles];
+ memcpy(pData->parprojs, projs, iProjAngles * sizeof(projs[0]));
+
+ pData->projType = PROJ_PARALLEL;
+
+ return true;
+}
+
+bool AstraCGLS3d::setPar3DGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles)
+{
+ if (pData->initialized)
+ return false;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ SPar3DProjection* p = genPar3DProjections(iProjAngles,
+ iProjU, iProjV,
+ fDetUSize, fDetVSize,
+ pfAngles);
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjU = iProjU;
+ pData->dims.iProjV = iProjV;
+
+ pData->parprojs = p;
+ pData->projType = PROJ_PARALLEL;
+
+ return true;
+}
+
+
+
+bool AstraCGLS3d::setConeGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SConeProjection* projs)
+{
+ if (pData->initialized)
+ return false;
+
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjU = iProjU;
+ pData->dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || projs == 0)
+ return false;
+
+ pData->projs = new SConeProjection[iProjAngles];
+ memcpy(pData->projs, projs, iProjAngles * sizeof(projs[0]));
+
+ pData->projType = PROJ_CONE;
+
+ return true;
+}
+
+bool AstraCGLS3d::setConeGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles)
+{
+ if (pData->initialized)
+ return false;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ SConeProjection* p = genConeProjections(iProjAngles,
+ iProjU, iProjV,
+ fOriginSourceDistance,
+ fOriginDetectorDistance,
+ fDetUSize, fDetVSize,
+ pfAngles);
+
+ pData->dims.iProjAngles = iProjAngles;
+ pData->dims.iProjU = iProjU;
+ pData->dims.iProjV = iProjV;
+
+ pData->projs = p;
+ pData->projType = PROJ_CONE;
+
+ return true;
+}
+
+bool AstraCGLS3d::enableSuperSampling(unsigned int iVoxelSuperSampling,
+ unsigned int iDetectorSuperSampling)
+{
+ if (pData->initialized)
+ return false;
+
+ if (iVoxelSuperSampling == 0 || iDetectorSuperSampling == 0)
+ return false;
+
+ pData->dims.iRaysPerVoxelDim = iVoxelSuperSampling;
+ pData->dims.iRaysPerDetDim = iDetectorSuperSampling;
+
+ return true;
+}
+
+bool AstraCGLS3d::enableVolumeMask()
+{
+ if (pData->initialized)
+ return false;
+
+ bool ok = pData->cgls.enableVolumeMask();
+ pData->useVolumeMask = ok;
+
+ return ok;
+}
+
+#if 0
+bool AstraCGLS3d::enableSinogramMask()
+{
+ if (pData->initialized)
+ return false;
+
+ bool ok = pData->cgls.enableSinogramMask();
+ pData->useSinogramMask = ok;
+
+ return ok;
+}
+#endif
+
+bool AstraCGLS3d::setGPUIndex(int index)
+{
+ cudaSetDevice(index);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+ return true;
+}
+
+bool AstraCGLS3d::init()
+{
+ fprintf(stderr, "001: %d\n", true);
+ if (pData->initialized)
+ return false;
+ fprintf(stderr, "002: %d\n", true);
+
+ if (pData->dims.iVolX == 0 || pData->dims.iProjAngles == 0)
+ return false;
+ fprintf(stderr, "003: %d\n", true);
+
+ bool ok;
+
+ if (pData->projType == PROJ_PARALLEL) {
+ ok = pData->cgls.setPar3DGeometry(pData->dims, pData->parprojs);
+ } else {
+ ok = pData->cgls.setConeGeometry(pData->dims, pData->projs);
+ }
+ fprintf(stderr, "004: %d\n", ok);
+
+ if (!ok)
+ return false;
+
+ ok = pData->cgls.init();
+ if (!ok)
+ return false;
+ fprintf(stderr, "005: %d\n", ok);
+
+ pData->D_volumeData = allocateVolumeData(pData->dims);
+ ok = pData->D_volumeData.ptr;
+ if (!ok)
+ return false;
+ fprintf(stderr, "006: %d\n", ok);
+
+ fprintf(stderr, "proj: %d %d %d\n", pData->dims.iProjAngles, pData->dims.iProjU, pData->dims.iProjV);
+ pData->D_projData = allocateProjectionData(pData->dims);
+ ok = pData->D_projData.ptr;
+ if (!ok) {
+ cudaFree(pData->D_volumeData.ptr);
+ pData->D_volumeData.ptr = 0;
+ return false;
+ }
+ fprintf(stderr, "007: %d\n", ok);
+
+ if (pData->useVolumeMask) {
+ pData->D_maskData = allocateVolumeData(pData->dims);
+ ok = pData->D_maskData.ptr;
+ if (!ok) {
+ cudaFree(pData->D_volumeData.ptr);
+ cudaFree(pData->D_projData.ptr);
+ pData->D_volumeData.ptr = 0;
+ pData->D_projData.ptr = 0;
+ return false;
+ }
+ }
+
+ if (pData->useSinogramMask) {
+ pData->D_smaskData = allocateProjectionData(pData->dims);
+ ok = pData->D_smaskData.ptr;
+ if (!ok) {
+ cudaFree(pData->D_volumeData.ptr);
+ cudaFree(pData->D_projData.ptr);
+ cudaFree(pData->D_maskData.ptr);
+ pData->D_volumeData.ptr = 0;
+ pData->D_projData.ptr = 0;
+ pData->D_maskData.ptr = 0;
+ return false;
+ }
+ }
+ fprintf(stderr, "008: %d\n", ok);
+
+ pData->initialized = true;
+
+ return true;
+}
+
+#if 0
+bool AstraCGLS3d::setMinConstraint(float fMin)
+{
+ if (!pData->initialized)
+ return false;
+ return pData->cgls.setMinConstraint(fMin);
+}
+
+bool AstraCGLS3d::setMaxConstraint(float fMax)
+{
+ if (!pData->initialized)
+ return false;
+ return pData->cgls.setMaxConstraint(fMax);
+}
+#endif
+
+bool AstraCGLS3d::setSinogram(const float* pfSinogram,
+ unsigned int iSinogramPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pfSinogram)
+ return false;
+
+ bool ok = copyProjectionsToDevice(pfSinogram, pData->D_projData, pData->dims, iSinogramPitch);
+
+ if (!ok)
+ return false;
+
+ ok = pData->cgls.setBuffers(pData->D_volumeData, pData->D_projData);
+ if (!ok)
+ return false;
+
+ pData->setStartReconstruction = false;
+
+ return true;
+}
+
+bool AstraCGLS3d::setVolumeMask(const float* pfMask, unsigned int iMaskPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pData->useVolumeMask)
+ return false;
+ if (!pfMask)
+ return false;
+
+ bool ok = copyVolumeToDevice(pfMask, pData->D_maskData,
+ pData->dims, iMaskPitch);
+ if (!ok)
+ return false;
+
+ ok = pData->cgls.setVolumeMask(pData->D_maskData);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+#if 0
+bool AstraCGLS3d::setSinogramMask(const float* pfMask, unsigned int iMaskPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pData->useSinogramMask)
+ return false;
+ if (!pfMask)
+ return false;
+
+ bool ok = copyProjectionsToDevice(pfMask, pData->D_smaskData, pData->dims, iMaskPitch);
+
+ if (!ok)
+ return false;
+
+ ok = pData->cgls.setSinogramMask(pData->D_smaskData);
+ if (!ok)
+ return false;
+
+ return true;
+}
+#endif
+
+bool AstraCGLS3d::setStartReconstruction(const float* pfReconstruction,
+ unsigned int iReconstructionPitch)
+{
+ if (!pData->initialized)
+ return false;
+ if (!pfReconstruction)
+ return false;
+
+ bool ok = copyVolumeToDevice(pfReconstruction, pData->D_volumeData,
+ pData->dims, iReconstructionPitch);
+ if (!ok)
+ return false;
+
+ pData->setStartReconstruction = true;
+
+ return true;
+}
+
+bool AstraCGLS3d::iterate(unsigned int iIterations)
+{
+ if (!pData->initialized)
+ return false;
+
+ if (!pData->setStartReconstruction)
+ zeroVolumeData(pData->D_volumeData, pData->dims);
+
+ bool ok = pData->cgls.iterate(iIterations);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+bool AstraCGLS3d::getReconstruction(float* pfReconstruction,
+ unsigned int iReconstructionPitch) const
+{
+ if (!pData->initialized)
+ return false;
+
+ bool ok = copyVolumeFromDevice(pfReconstruction, pData->D_volumeData,
+ pData->dims, iReconstructionPitch);
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+void AstraCGLS3d::signalAbort()
+{
+ if (!pData->initialized)
+ return;
+
+ pData->cgls.signalAbort();
+}
+
+float AstraCGLS3d::computeDiffNorm()
+{
+ if (!pData->initialized)
+ return 0.0f; // FIXME: Error?
+
+ return pData->cgls.computeDiffNorm();
+}
+
+
+
+bool astraCudaConeFP(const float* pfVolume, float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ int iGPUIndex, int iDetectorSuperSampling)
+{
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ SConeProjection* p = genConeProjections(iProjAngles,
+ iProjU, iProjV,
+ fOriginSourceDistance,
+ fOriginDetectorDistance,
+ fDetUSize, fDetVSize,
+ pfAngles);
+
+ bool ok;
+ ok = astraCudaConeFP(pfVolume, pfProjections, iVolX, iVolY, iVolZ,
+ iProjAngles, iProjU, iProjV, p, iGPUIndex, iDetectorSuperSampling);
+
+ delete[] p;
+
+ return ok;
+}
+
+bool astraCudaConeFP(const float* pfVolume, float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SConeProjection *pfAngles,
+ int iGPUIndex, int iDetectorSuperSampling)
+{
+ SDimensions3D dims;
+
+ dims.iVolX = iVolX;
+ dims.iVolY = iVolY;
+ dims.iVolZ = iVolZ;
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+
+ dims.iProjAngles = iProjAngles;
+ dims.iProjU = iProjU;
+ dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ dims.iRaysPerDetDim = iDetectorSuperSampling;
+
+ if (iDetectorSuperSampling == 0)
+ return false;
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+
+ cudaPitchedPtr D_volumeData = allocateVolumeData(dims);
+ bool ok = D_volumeData.ptr;
+ if (!ok)
+ return false;
+
+ cudaPitchedPtr D_projData = allocateProjectionData(dims);
+ ok = D_projData.ptr;
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ return false;
+ }
+
+ ok &= copyVolumeToDevice(pfVolume, D_volumeData, dims, dims.iVolX);
+
+ ok &= zeroProjectionData(D_projData, dims);
+
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+ return false;
+ }
+
+ ok &= ConeFP(D_volumeData, D_projData, dims, pfAngles, 1.0f);
+
+ ok &= copyProjectionsFromDevice(pfProjections, D_projData,
+ dims, dims.iProjU);
+
+
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+
+ return ok;
+
+}
+
+bool astraCudaPar3DFP(const float* pfVolume, float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ int iGPUIndex, int iDetectorSuperSampling,
+ Cuda3DProjectionKernel projKernel)
+{
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ SPar3DProjection* p = genPar3DProjections(iProjAngles,
+ iProjU, iProjV,
+ fDetUSize, fDetVSize,
+ pfAngles);
+
+ bool ok;
+ ok = astraCudaPar3DFP(pfVolume, pfProjections, iVolX, iVolY, iVolZ,
+ iProjAngles, iProjU, iProjV, p, iGPUIndex, iDetectorSuperSampling,
+ projKernel);
+
+ delete[] p;
+
+ return ok;
+}
+
+
+bool astraCudaPar3DFP(const float* pfVolume, float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SPar3DProjection *pfAngles,
+ int iGPUIndex, int iDetectorSuperSampling,
+ Cuda3DProjectionKernel projKernel)
+{
+ SDimensions3D dims;
+
+ dims.iVolX = iVolX;
+ dims.iVolY = iVolY;
+ dims.iVolZ = iVolZ;
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+
+ dims.iProjAngles = iProjAngles;
+ dims.iProjU = iProjU;
+ dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ dims.iRaysPerDetDim = iDetectorSuperSampling;
+
+ if (iDetectorSuperSampling == 0)
+ return false;
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+
+
+ cudaPitchedPtr D_volumeData = allocateVolumeData(dims);
+ bool ok = D_volumeData.ptr;
+ if (!ok)
+ return false;
+
+ cudaPitchedPtr D_projData = allocateProjectionData(dims);
+ ok = D_projData.ptr;
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ return false;
+ }
+
+ ok &= copyVolumeToDevice(pfVolume, D_volumeData, dims, dims.iVolX);
+
+ ok &= zeroProjectionData(D_projData, dims);
+
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+ return false;
+ }
+
+ switch (projKernel) {
+ case ker3d_default:
+ ok &= Par3DFP(D_volumeData, D_projData, dims, pfAngles, 1.0f);
+ break;
+ case ker3d_sum_square_weights:
+ ok &= Par3DFP_SumSqW(D_volumeData, D_projData, dims, pfAngles, 1.0f);
+ break;
+ default:
+ assert(false);
+ }
+
+ ok &= copyProjectionsFromDevice(pfProjections, D_projData,
+ dims, dims.iProjU);
+
+
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+
+ return ok;
+
+}
+
+bool astraCudaConeBP(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ int iGPUIndex, int iVoxelSuperSampling)
+{
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ SConeProjection* p = genConeProjections(iProjAngles,
+ iProjU, iProjV,
+ fOriginSourceDistance,
+ fOriginDetectorDistance,
+ fDetUSize, fDetVSize,
+ pfAngles);
+
+ bool ok;
+ ok = astraCudaConeBP(pfVolume, pfProjections, iVolX, iVolY, iVolZ,
+ iProjAngles, iProjU, iProjV, p, iGPUIndex, iVoxelSuperSampling);
+
+ delete[] p;
+
+ return ok;
+}
+
+bool astraCudaConeBP(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SConeProjection *pfAngles,
+ int iGPUIndex, int iVoxelSuperSampling)
+{
+ SDimensions3D dims;
+
+ dims.iVolX = iVolX;
+ dims.iVolY = iVolY;
+ dims.iVolZ = iVolZ;
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+
+ dims.iProjAngles = iProjAngles;
+ dims.iProjU = iProjU;
+ dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ dims.iRaysPerVoxelDim = iVoxelSuperSampling;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+
+ cudaPitchedPtr D_volumeData = allocateVolumeData(dims);
+ bool ok = D_volumeData.ptr;
+ if (!ok)
+ return false;
+
+ cudaPitchedPtr D_projData = allocateProjectionData(dims);
+ ok = D_projData.ptr;
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ return false;
+ }
+
+ ok &= copyProjectionsToDevice(pfProjections, D_projData,
+ dims, dims.iProjU);
+
+ ok &= zeroVolumeData(D_volumeData, dims);
+
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+ return false;
+ }
+
+ ok &= ConeBP(D_volumeData, D_projData, dims, pfAngles);
+
+ ok &= copyVolumeFromDevice(pfVolume, D_volumeData, dims, dims.iVolX);
+
+
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+
+ return ok;
+
+}
+
+bool astraCudaPar3DBP(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ int iGPUIndex, int iVoxelSuperSampling)
+{
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ SPar3DProjection* p = genPar3DProjections(iProjAngles,
+ iProjU, iProjV,
+ fDetUSize, fDetVSize,
+ pfAngles);
+
+ bool ok;
+ ok = astraCudaPar3DBP(pfVolume, pfProjections, iVolX, iVolY, iVolZ,
+ iProjAngles, iProjU, iProjV, p, iGPUIndex, iVoxelSuperSampling);
+
+ delete[] p;
+
+ return ok;
+}
+
+
+bool astraCudaPar3DBP(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SPar3DProjection *pfAngles,
+ int iGPUIndex, int iVoxelSuperSampling)
+{
+ SDimensions3D dims;
+
+ dims.iVolX = iVolX;
+ dims.iVolY = iVolY;
+ dims.iVolZ = iVolZ;
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+
+ dims.iProjAngles = iProjAngles;
+ dims.iProjU = iProjU;
+ dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ dims.iRaysPerVoxelDim = iVoxelSuperSampling;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+
+
+ cudaPitchedPtr D_volumeData = allocateVolumeData(dims);
+ bool ok = D_volumeData.ptr;
+ if (!ok)
+ return false;
+
+ cudaPitchedPtr D_projData = allocateProjectionData(dims);
+ ok = D_projData.ptr;
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ return false;
+ }
+
+ ok &= copyProjectionsToDevice(pfProjections, D_projData,
+ dims, dims.iProjU);
+
+ ok &= zeroVolumeData(D_volumeData, dims);
+
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+ return false;
+ }
+
+ ok &= Par3DBP(D_volumeData, D_projData, dims, pfAngles);
+
+ ok &= copyVolumeFromDevice(pfVolume, D_volumeData, dims, dims.iVolX);
+
+
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+
+ return ok;
+
+}
+
+
+
+bool astraCudaFDK(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ bool bShortScan,
+ int iGPUIndex, int iVoxelSuperSampling)
+{
+ SDimensions3D dims;
+
+ dims.iVolX = iVolX;
+ dims.iVolY = iVolY;
+ dims.iVolZ = iVolZ;
+ if (iVolX == 0 || iVolY == 0 || iVolZ == 0)
+ return false;
+
+ dims.iProjAngles = iProjAngles;
+ dims.iProjU = iProjU;
+ dims.iProjV = iProjV;
+
+ if (iProjAngles == 0 || iProjU == 0 || iProjV == 0 || pfAngles == 0)
+ return false;
+
+ dims.iRaysPerVoxelDim = iVoxelSuperSampling;
+
+ if (iVoxelSuperSampling == 0)
+ return false;
+
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+
+
+ cudaPitchedPtr D_volumeData = allocateVolumeData(dims);
+ bool ok = D_volumeData.ptr;
+ if (!ok)
+ return false;
+
+ cudaPitchedPtr D_projData = allocateProjectionData(dims);
+ ok = D_projData.ptr;
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ return false;
+ }
+
+ ok &= copyProjectionsToDevice(pfProjections, D_projData, dims, dims.iProjU);
+
+ ok &= zeroVolumeData(D_volumeData, dims);
+
+ if (!ok) {
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+ return false;
+ }
+
+ // TODO: Offer interface for SrcZ, DetZ
+ ok &= FDK(D_volumeData, D_projData, fOriginSourceDistance,
+ fOriginDetectorDistance, 0, 0, fDetUSize, fDetVSize,
+ dims, pfAngles, bShortScan);
+
+ ok &= copyVolumeFromDevice(pfVolume, D_volumeData, dims, dims.iVolX);
+
+
+ cudaFree(D_volumeData.ptr);
+ cudaFree(D_projData.ptr);
+
+ return ok;
+
+}
+
+
+
+
+}
diff --git a/cuda/3d/astra3d.h b/cuda/3d/astra3d.h
new file mode 100644
index 0000000..5712f89
--- /dev/null
+++ b/cuda/3d/astra3d.h
@@ -0,0 +1,450 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_ASTRA3D_H
+#define _CUDA_ASTRA3D_H
+
+#include "dims3d.h"
+
+namespace astra {
+
+
+// TODO: Switch to a class hierarchy as with the 2D algorithms
+
+
+enum Cuda3DProjectionKernel {
+ ker3d_default = 0,
+ ker3d_sum_square_weights
+};
+
+
+class AstraSIRT3d_internal;
+
+
+class _AstraExport AstraSIRT3d {
+public:
+
+ AstraSIRT3d();
+ ~AstraSIRT3d();
+
+ // Set the number of pixels in the reconstruction rectangle,
+ // and the length of the edge of a pixel.
+ // Volume pixels are assumed to be square.
+ // This must be called before setting the projection geometry.
+ bool setReconstructionGeometry(unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ/*,
+ float fPixelSize = 1.0f*/);
+
+ bool setConeGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SConeProjection* projs);
+ bool setConeGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fSourceZ,
+ float fDetSize,
+ const float *pfAngles);
+ bool setPar3DGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SPar3DProjection* projs);
+ bool setPar3DGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fSourceZ,
+ float fDetSize,
+ const float *pfAngles);
+
+ // Enable supersampling.
+ //
+ // The number of rays used in FP is the square of iDetectorSuperSampling.
+ // The number of rays used in BP is the cube of iVoxelSuperSampling.
+ bool enableSuperSampling(unsigned int iVoxelSuperSampling,
+ unsigned int iDetectorSuperSampling);
+
+ // Enable volume/sinogram masks
+ //
+ // This may optionally be called before init().
+ // If it is called, setVolumeMask()/setSinogramMask() must be called between
+ // setSinogram() and iterate().
+ bool enableVolumeMask();
+ bool enableSinogramMask();
+
+ // Set GPU index
+ //
+ // This should be called before init(). Note that setting the GPU index
+ // in a thread which has already used the GPU may not work.
+ bool setGPUIndex(int index);
+
+ // Allocate GPU buffers and
+ // precompute geometry-specific data.
+ //
+ // This must be called after calling setReconstructionGeometry() and
+ // setProjectionGeometry() or setFanProjectionGeometry().
+ bool init();
+
+ // Setup input sinogram for a slice.
+ // pfSinogram must be a float array of size XXX
+ // NB: iSinogramPitch is measured in floats, not in bytes.
+ //
+ // This must be called after init(), and before iterate(). It may be
+ // called again after iterate()/getReconstruction() to start a new slice.
+ //
+ // pfSinogram will only be read from during this call.
+ bool setSinogram(const float* pfSinogram, unsigned int iSinogramPitch);
+
+ // Setup volume mask for a slice.
+ // pfMask must be a float array of size XXX
+ // NB: iMaskPitch is measured in floats, not in bytes.
+ //
+ // It may only contain the exact values 0.0f and 1.0f. Only volume pixels
+ // for which pfMask[z] is 1.0f are processed.
+ bool setVolumeMask(const float* pfMask, unsigned int iMaskPitch);
+
+ // Setup sinogram mask for a slice.
+ // pfMask must be a float array of size XXX
+ // NB: iMaskPitch is measured in floats, not in bytes.
+ //
+ // It may only contain the exact values 0.0f and 1.0f. Only sinogram pixels
+ // for which pfMask[z] is 1.0f are processed.
+ bool setSinogramMask(const float* pfMask, unsigned int iMaskPitch);
+
+ // Set the starting reconstruction for SIRT.
+ // pfReconstruction must be a float array of size XXX
+ // NB: iReconstructionPitch is measured in floats, not in bytes.
+ //
+ // This may be called between setSinogram() and iterate().
+ // If this function is not called before iterate(), SIRT will start
+ // from a zero reconstruction.
+ //
+ // pfReconstruction will only be read from during this call.
+ bool setStartReconstruction(const float* pfReconstruction,
+ unsigned int iReconstructionPitch);
+
+ // Enable min/max constraint.
+ //
+ // These may optionally be called between init() and iterate()
+ bool setMinConstraint(float fMin);
+ bool setMaxConstraint(float fMax);
+
+ // Perform a number of (additive) SIRT iterations.
+ // This must be called after setSinogram().
+ //
+ // If called multiple times, without calls to setSinogram() or
+ // setStartReconstruction() in between, iterate() will continue from
+ // the result of the previous call.
+ // Calls to getReconstruction() are allowed between calls to iterate() and
+ // do not change the state.
+ bool iterate(unsigned int iIterations);
+
+ // Get the reconstructed slice.
+ // pfReconstruction must be a float array of size XXX
+ // NB: iReconstructionPitch is measured in floats, not in bytes.
+ //
+ // This may be called after iterate().
+ bool getReconstruction(float* pfReconstruction,
+ unsigned int iReconstructionPitch) const;
+
+ // Compute the norm of the difference of the FP of the current
+ // reconstruction and the sinogram. (This performs one FP.)
+ // It can be called after iterate().
+ float computeDiffNorm();
+
+ // Signal the algorithm that it should abort after the current iteration.
+ // This is intended to be called from another thread.
+ void signalAbort();
+
+protected:
+ AstraSIRT3d_internal *pData;
+};
+
+
+class AstraCGLS3d_internal;
+
+
+class _AstraExport AstraCGLS3d {
+public:
+
+ AstraCGLS3d();
+ ~AstraCGLS3d();
+
+ // Set the number of pixels in the reconstruction rectangle,
+ // and the length of the edge of a pixel.
+ // Volume pixels are assumed to be square.
+ // This must be called before setting the projection geometry.
+ bool setReconstructionGeometry(unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ/*,
+ float fPixelSize = 1.0f*/);
+
+ bool setConeGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SConeProjection* projs);
+ bool setConeGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fSourceZ,
+ float fDetSize,
+ const float *pfAngles);
+ bool setPar3DGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SPar3DProjection* projs);
+ bool setPar3DGeometry(unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fSourceZ,
+ float fDetSize,
+ const float *pfAngles);
+
+ // Enable supersampling.
+ //
+ // The number of rays used in FP is the square of iDetectorSuperSampling.
+ // The number of rays used in BP is the cube of iVoxelSuperSampling.
+ bool enableSuperSampling(unsigned int iVoxelSuperSampling,
+ unsigned int iDetectorSuperSampling);
+
+ // Enable volume/sinogram masks
+ //
+ // This may optionally be called before init().
+ // If it is called, setVolumeMask()/setSinogramMask() must be called between
+ // setSinogram() and iterate().
+ bool enableVolumeMask();
+ //bool enableSinogramMask();
+
+ // Set GPU index
+ //
+ // This should be called before init(). Note that setting the GPU index
+ // in a thread which has already used the GPU may not work.
+ bool setGPUIndex(int index);
+
+ // Allocate GPU buffers and
+ // precompute geometry-specific data.
+ //
+ // This must be called after calling setReconstructionGeometry() and
+ // setProjectionGeometry() or setFanProjectionGeometry().
+ bool init();
+
+ // Setup input sinogram for a slice.
+ // pfSinogram must be a float array of size XXX
+ // NB: iSinogramPitch is measured in floats, not in bytes.
+ //
+ // This must be called after init(), and before iterate(). It may be
+ // called again after iterate()/getReconstruction() to start a new slice.
+ //
+ // pfSinogram will only be read from during this call.
+ bool setSinogram(const float* pfSinogram, unsigned int iSinogramPitch);
+
+ // Setup volume mask for a slice.
+ // pfMask must be a float array of size XXX
+ // NB: iMaskPitch is measured in floats, not in bytes.
+ //
+ // It may only contain the exact values 0.0f and 1.0f. Only volume pixels
+ // for which pfMask[z] is 1.0f are processed.
+ bool setVolumeMask(const float* pfMask, unsigned int iMaskPitch);
+
+ // Setup sinogram mask for a slice.
+ // pfMask must be a float array of size XXX
+ // NB: iMaskPitch is measured in floats, not in bytes.
+ //
+ // It may only contain the exact values 0.0f and 1.0f. Only sinogram pixels
+ // for which pfMask[z] is 1.0f are processed.
+ //bool setSinogramMask(const float* pfMask, unsigned int iMaskPitch);
+
+ // Set the starting reconstruction for SIRT.
+ // pfReconstruction must be a float array of size XXX
+ // NB: iReconstructionPitch is measured in floats, not in bytes.
+ //
+ // This may be called between setSinogram() and iterate().
+ // If this function is not called before iterate(), SIRT will start
+ // from a zero reconstruction.
+ //
+ // pfReconstruction will only be read from during this call.
+ bool setStartReconstruction(const float* pfReconstruction,
+ unsigned int iReconstructionPitch);
+
+ // Enable min/max constraint.
+ //
+ // These may optionally be called between init() and iterate()
+ //bool setMinConstraint(float fMin);
+ //bool setMaxConstraint(float fMax);
+
+ // Perform a number of (additive) SIRT iterations.
+ // This must be called after setSinogram().
+ //
+ // If called multiple times, without calls to setSinogram() or
+ // setStartReconstruction() in between, iterate() will continue from
+ // the result of the previous call.
+ // Calls to getReconstruction() are allowed between calls to iterate() and
+ // do not change the state.
+ bool iterate(unsigned int iIterations);
+
+ // Get the reconstructed slice.
+ // pfReconstruction must be a float array of size XXX
+ // NB: iReconstructionPitch is measured in floats, not in bytes.
+ //
+ // This may be called after iterate().
+ bool getReconstruction(float* pfReconstruction,
+ unsigned int iReconstructionPitch) const;
+
+ // Compute the norm of the difference of the FP of the current
+ // reconstruction and the sinogram. (This performs one FP.)
+ // It can be called after iterate().
+ float computeDiffNorm();
+
+ // Signal the algorithm that it should abort after the current iteration.
+ // This is intended to be called from another thread.
+ void signalAbort();
+
+protected:
+ AstraCGLS3d_internal *pData;
+};
+
+
+
+_AstraExport bool astraCudaConeFP(const float* pfVolume, float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ int iGPUIndex, int iDetectorSuperSampling);
+
+_AstraExport bool astraCudaConeFP(const float* pfVolume, float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SConeProjection *pfAngles,
+ int iGPUIndex, int iDetectorSuperSampling);
+
+_AstraExport bool astraCudaPar3DFP(const float* pfVolume, float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ int iGPUIndex, int iDetectorSuperSampling,
+ Cuda3DProjectionKernel projKernel);
+
+_AstraExport bool astraCudaPar3DFP(const float* pfVolume, float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SPar3DProjection *pfAngles,
+ int iGPUIndex, int iDetectorSuperSampling,
+ Cuda3DProjectionKernel projKernel);
+
+
+_AstraExport bool astraCudaConeBP(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ int iGPUIndex, int iVoxelSuperSampling);
+
+_AstraExport bool astraCudaConeBP(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SConeProjection *pfAngles,
+ int iGPUIndex, int iVoxelSuperSampling);
+
+_AstraExport bool astraCudaPar3DBP(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ int iGPUIndex, int iVoxelSuperSampling);
+
+_AstraExport bool astraCudaPar3DBP(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ const SPar3DProjection *pfAngles,
+ int iGPUIndex, int iVoxelSuperSampling);
+
+_AstraExport bool astraCudaFDK(float* pfVolume, const float* pfProjections,
+ unsigned int iVolX,
+ unsigned int iVolY,
+ unsigned int iVolZ,
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles,
+ bool bShortScan,
+ int iGPUIndex, int iVoxelSuperSampling);
+
+}
+
+
+#endif
diff --git a/cuda/3d/cgls3d.cu b/cuda/3d/cgls3d.cu
new file mode 100644
index 0000000..72bb9cd
--- /dev/null
+++ b/cuda/3d/cgls3d.cu
@@ -0,0 +1,428 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+
+#include "cgls3d.h"
+#include "util3d.h"
+#include "arith3d.h"
+#include "cone_fp.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+namespace astraCUDA3d {
+
+CGLS::CGLS() : ReconAlgo3D()
+{
+ D_maskData.ptr = 0;
+ D_smaskData.ptr = 0;
+
+ D_sinoData.ptr = 0;
+ D_volumeData.ptr = 0;
+
+ D_r.ptr = 0;
+ D_w.ptr = 0;
+ D_z.ptr = 0;
+ D_p.ptr = 0;
+
+ useVolumeMask = false;
+ useSinogramMask = false;
+}
+
+
+CGLS::~CGLS()
+{
+ reset();
+}
+
+void CGLS::reset()
+{
+ cudaFree(D_r.ptr);
+ cudaFree(D_w.ptr);
+ cudaFree(D_z.ptr);
+ cudaFree(D_p.ptr);
+
+ D_maskData.ptr = 0;
+ D_smaskData.ptr = 0;
+
+ D_sinoData.ptr = 0;
+ D_volumeData.ptr = 0;
+
+ D_r.ptr = 0;
+ D_w.ptr = 0;
+ D_z.ptr = 0;
+ D_p.ptr = 0;
+
+ useVolumeMask = false;
+ useSinogramMask = false;
+
+ sliceInitialized = false;
+
+ ReconAlgo3D::reset();
+}
+
+bool CGLS::enableVolumeMask()
+{
+ useVolumeMask = true;
+ return true;
+}
+
+bool CGLS::enableSinogramMask()
+{
+ useSinogramMask = true;
+ return true;
+}
+
+
+bool CGLS::init()
+{
+ D_z = allocateVolumeData(dims);
+ D_p = allocateVolumeData(dims);
+ D_r = allocateProjectionData(dims);
+ D_w = allocateProjectionData(dims);
+
+ // TODO: check if allocations succeeded
+ return true;
+}
+
+bool CGLS::setVolumeMask(cudaPitchedPtr& _D_maskData)
+{
+ assert(useVolumeMask);
+
+ D_maskData = _D_maskData;
+
+ return true;
+}
+
+bool CGLS::setSinogramMask(cudaPitchedPtr& _D_smaskData)
+{
+ return false;
+#if 0
+ // TODO: Implement this
+ assert(useSinogramMask);
+
+ D_smaskData = _D_smaskData;
+ return true;
+#endif
+}
+
+bool CGLS::setBuffers(cudaPitchedPtr& _D_volumeData,
+ cudaPitchedPtr& _D_projData)
+{
+ D_volumeData = _D_volumeData;
+ D_sinoData = _D_projData;
+
+ fprintf(stderr, "Reconstruction buffer: %p\n", (void*)D_volumeData.ptr);
+
+ sliceInitialized = false;
+
+ return true;
+}
+
+bool CGLS::iterate(unsigned int iterations)
+{
+ shouldAbort = false;
+
+ if (!sliceInitialized) {
+
+ // copy sinogram
+ duplicateProjectionData(D_r, D_sinoData, dims);
+
+ // r = sino - A*x
+ if (useVolumeMask) {
+ duplicateVolumeData(D_z, D_volumeData, dims);
+ processVol3D<opMul>(D_z, D_maskData, dims);
+ callFP(D_z, D_r, -1.0f);
+ } else {
+ callFP(D_volumeData, D_r, -1.0f);
+ }
+
+ // p = A'*r
+ zeroVolumeData(D_p, dims);
+ callBP(D_p, D_r);
+ if (useVolumeMask)
+ processVol3D<opMul>(D_p, D_maskData, dims);
+
+ gamma = dotProduct3D(D_p, dims.iVolX, dims.iVolY, dims.iVolZ);
+
+ sliceInitialized = true;
+
+ }
+
+
+ // iteration
+ for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) {
+
+ // w = A*p
+ zeroProjectionData(D_w, dims);
+ callFP(D_p, D_w, 1.0f);
+
+ // alpha = gamma / <w,w>
+ float ww = dotProduct3D(D_w, dims.iProjU, dims.iProjAngles, dims.iProjV);
+ float alpha = gamma / ww;
+
+ // x += alpha*p
+ processVol3D<opAddScaled>(D_volumeData, D_p, alpha, dims);
+
+ // r -= alpha*w
+ processSino3D<opAddScaled>(D_r, D_w, -alpha, dims);
+
+ // z = A'*r
+ zeroVolumeData(D_z, dims);
+ callBP(D_z, D_r);
+ if (useVolumeMask)
+ processVol3D<opMul>(D_z, D_maskData, dims);
+
+ float beta = 1.0f / gamma;
+ gamma = dotProduct3D(D_z, dims.iVolX, dims.iVolY, dims.iVolZ);
+
+ beta *= gamma;
+
+ // p = z + beta*p
+ processVol3D<opScaleAndAdd>(D_p, D_z, beta, dims);
+ }
+
+ return true;
+}
+
+float CGLS::computeDiffNorm()
+{
+ // We can use w and z as temporary storage here since they're not
+ // used outside of iterations.
+
+ // copy sinogram to w
+ duplicateProjectionData(D_w, D_sinoData, dims);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ duplicateVolumeData(D_z, D_volumeData, dims);
+ processVol3D<opMul>(D_z, D_maskData, dims);
+ callFP(D_z, D_w, -1.0f);
+ } else {
+ callFP(D_volumeData, D_w, -1.0f);
+ }
+
+ float s = dotProduct3D(D_w, dims.iProjU, dims.iProjAngles, dims.iProjV);
+ return sqrt(s);
+}
+
+
+bool doCGLS(cudaPitchedPtr& D_volumeData,
+ cudaPitchedPtr& D_sinoData,
+ cudaPitchedPtr& D_maskData,
+ const SDimensions3D& dims, const SConeProjection* angles,
+ unsigned int iterations)
+{
+ CGLS cgls;
+ bool ok = true;
+
+ ok &= cgls.setConeGeometry(dims, angles);
+ if (D_maskData.ptr)
+ ok &= cgls.enableVolumeMask();
+
+ if (!ok)
+ return false;
+
+ ok = cgls.init();
+ if (!ok)
+ return false;
+
+ if (D_maskData.ptr)
+ ok &= cgls.setVolumeMask(D_maskData);
+
+ ok &= cgls.setBuffers(D_volumeData, D_sinoData);
+ if (!ok)
+ return false;
+
+ ok = cgls.iterate(iterations);
+
+ return ok;
+}
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA3d;
+
+int main()
+{
+ SDimensions3D dims;
+ dims.iVolX = 256;
+ dims.iVolY = 256;
+ dims.iVolZ = 256;
+ dims.iProjAngles = 100;
+ dims.iProjU = 512;
+ dims.iProjV = 512;
+ dims.iRaysPerDet = 1;
+
+ SConeProjection angle[100];
+ angle[0].fSrcX = -2905.6;
+ angle[0].fSrcY = 0;
+ angle[0].fSrcZ = 0;
+
+ angle[0].fDetSX = 694.4;
+ angle[0].fDetSY = -122.4704;
+ angle[0].fDetSZ = -122.4704;
+
+ angle[0].fDetUX = 0;
+ angle[0].fDetUY = .4784;
+ //angle[0].fDetUY = .5;
+ angle[0].fDetUZ = 0;
+
+ angle[0].fDetVX = 0;
+ angle[0].fDetVY = 0;
+ angle[0].fDetVZ = .4784;
+
+#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0)
+ for (int i = 1; i < 100; ++i) {
+ angle[i] = angle[0];
+ ROTATE0(Src, i, i*2*M_PI/100);
+ ROTATE0(DetS, i, i*2*M_PI/100);
+ ROTATE0(DetU, i, i*2*M_PI/100);
+ ROTATE0(DetV, i, i*2*M_PI/100);
+ }
+#undef ROTATE0
+
+
+ cudaPitchedPtr volData = allocateVolumeData(dims);
+ cudaPitchedPtr projData = allocateProjectionData(dims);
+ zeroProjectionData(projData, dims);
+
+ float* pbuf = new float[100*512*512];
+ copyProjectionsFromDevice(pbuf, projData, dims);
+ copyProjectionsToDevice(pbuf, projData, dims);
+ delete[] pbuf;
+
+#if 0
+ float* slice = new float[256*256];
+ cudaPitchedPtr ptr;
+ ptr.ptr = slice;
+ ptr.pitch = 256*sizeof(float);
+ ptr.xsize = 256*sizeof(float);
+ ptr.ysize = 256;
+
+ for (unsigned int i = 0; i < 256; ++i) {
+ for (unsigned int y = 0; y < 256; ++y)
+ for (unsigned int x = 0; x < 256; ++x)
+ slice[y*256+x] = (i-127.5)*(i-127.5)+(y-127.5)*(y-127.5)+(x-127.5)*(x-127.5) < 4900 ? 1.0f : 0.0f;
+
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, i };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaMemcpy3D(&p);
+ }
+ astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f);
+
+#else
+
+ for (int i = 0; i < 100; ++i) {
+ char fname[32];
+ sprintf(fname, "Tiffs/%04d.png", 4*i);
+ unsigned int w,h;
+ float* bufp = loadImage(fname, w,h);
+
+ for (int j = 0; j < 512*512; ++j) {
+ float v = bufp[j];
+ if (v > 236.0f) v = 236.0f;
+ v = logf(236.0f / v);
+ bufp[j] = 256*v;
+ }
+
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(((float*)projData.ptr)+100*512*j+512*i, bufp+512*j, 512*sizeof(float), cudaMemcpyHostToDevice);
+ }
+
+ delete[] bufp;
+
+ }
+#endif
+
+#if 0
+ float* bufs = new float[100*512];
+
+ for (int i = 0; i < 512; ++i) {
+ cudaMemcpy(bufs, ((float*)projData.ptr)+100*512*i, 100*512*sizeof(float), cudaMemcpyDeviceToHost);
+
+ printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize);
+
+ char fname[20];
+ sprintf(fname, "sino%03d.png", i);
+ saveImage(fname, 100, 512, bufs);
+ }
+
+ float* bufp = new float[512*512];
+
+ for (int i = 0; i < 100; ++i) {
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(bufp+512*j, ((float*)projData.ptr)+100*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost);
+ }
+
+ char fname[20];
+ sprintf(fname, "proj%03d.png", i);
+ saveImage(fname, 512, 512, bufp);
+ }
+#endif
+
+ zeroVolumeData(volData, dims);
+
+ cudaPitchedPtr maskData;
+ maskData.ptr = 0;
+
+ astraCUDA3d::doCGLS(volData, projData, maskData, dims, angle, 50);
+#if 1
+ float* buf = new float[256*256];
+
+ for (int i = 0; i < 256; ++i) {
+ cudaMemcpy(buf, ((float*)volData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost);
+
+ char fname[20];
+ sprintf(fname, "vol%03d.png", i);
+ saveImage(fname, 256, 256, buf);
+ }
+#endif
+
+ return 0;
+}
+#endif
+
diff --git a/cuda/3d/cgls3d.h b/cuda/3d/cgls3d.h
new file mode 100644
index 0000000..d16b571
--- /dev/null
+++ b/cuda/3d/cgls3d.h
@@ -0,0 +1,114 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_CGLS3D_H
+#define _CUDA_CGLS3D_H
+
+#include "util3d.h"
+#include "algo3d.h"
+
+namespace astraCUDA3d {
+
+class _AstraExport CGLS : public ReconAlgo3D {
+public:
+ CGLS();
+ ~CGLS();
+
+// bool setConeGeometry(const SDimensions3D& dims, const SConeProjection* projs);
+
+
+ bool enableVolumeMask();
+ bool enableSinogramMask();
+
+ // init should be called after setting all geometry
+ bool init();
+
+ // setVolumeMask should be called after init and before iterate,
+ // but only if enableVolumeMask was called before init.
+ // It may be called again after iterate.
+ bool setVolumeMask(cudaPitchedPtr& D_maskData);
+
+ // setSinogramMask should be called after init and before iterate,
+ // but only if enableSinogramMask was called before init.
+ // It may be called again after iterate.
+ bool setSinogramMask(cudaPitchedPtr& D_smaskData);
+
+
+ // setBuffers should be called after init and before iterate.
+ // It may be called again after iterate.
+ bool setBuffers(cudaPitchedPtr& D_volumeData,
+ cudaPitchedPtr& D_projData);
+
+
+ // set Min/Max constraints. They may be called at any time, and will affect
+ // any iterate() calls afterwards.
+ bool setMinConstraint(float fMin) { return false; }
+ bool setMaxConstraint(float fMax) { return false; }
+
+ // iterate should be called after init and setBuffers.
+ // It may be called multiple times.
+ bool iterate(unsigned int iterations);
+
+ // Compute the norm of the difference of the FP of the current reconstruction
+ // and the sinogram. (This performs one FP.)
+ // It can be called after iterate.
+ float computeDiffNorm();
+
+protected:
+ void reset();
+
+ bool useVolumeMask;
+ bool useSinogramMask;
+
+ cudaPitchedPtr D_maskData;
+ cudaPitchedPtr D_smaskData;
+
+ // Input/output
+ cudaPitchedPtr D_sinoData;
+ cudaPitchedPtr D_volumeData;
+
+ // Temporary buffers
+ cudaPitchedPtr D_r;
+ cudaPitchedPtr D_w;
+ cudaPitchedPtr D_z;
+ cudaPitchedPtr D_p;
+
+ float gamma;
+
+ bool sliceInitialized;
+};
+
+_AstraExport bool doCGLS(cudaPitchedPtr D_volumeData, unsigned int volumePitch,
+ cudaPitchedPtr D_projData, unsigned int projPitch,
+ cudaPitchedPtr D_maskData, unsigned int maskPitch,
+ const SDimensions3D& dims, const SConeProjection* projs,
+ unsigned int iterations);
+
+}
+
+#endif
diff --git a/cuda/3d/cone_bp.cu b/cuda/3d/cone_bp.cu
new file mode 100644
index 0000000..7f8e320
--- /dev/null
+++ b/cuda/3d/cone_bp.cu
@@ -0,0 +1,481 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+#include <list>
+
+#include <cuda.h>
+#include "util3d.h"
+
+#ifdef STANDALONE
+#include "cone_fp.h"
+#include "testutil.h"
+#endif
+
+#include "dims3d.h"
+
+typedef texture<float, 3, cudaReadModeElementType> texture3D;
+
+static texture3D gT_coneProjTexture;
+
+namespace astraCUDA3d {
+
+static const unsigned int g_volBlockZ = 16;
+
+static const unsigned int g_anglesPerBlock = 64;
+static const unsigned int g_volBlockX = 32;
+static const unsigned int g_volBlockY = 16;
+
+static const unsigned g_MaxAngles = 1024;
+
+__constant__ float gC_Cux[g_MaxAngles];
+__constant__ float gC_Cuy[g_MaxAngles];
+__constant__ float gC_Cuz[g_MaxAngles];
+__constant__ float gC_Cuc[g_MaxAngles];
+__constant__ float gC_Cvx[g_MaxAngles];
+__constant__ float gC_Cvy[g_MaxAngles];
+__constant__ float gC_Cvz[g_MaxAngles];
+__constant__ float gC_Cvc[g_MaxAngles];
+__constant__ float gC_Cdx[g_MaxAngles];
+__constant__ float gC_Cdy[g_MaxAngles];
+__constant__ float gC_Cdz[g_MaxAngles];
+__constant__ float gC_Cdc[g_MaxAngles];
+
+
+bool bindProjDataTexture(const cudaArray* array)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+
+ gT_coneProjTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_coneProjTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_coneProjTexture.addressMode[2] = cudaAddressModeClamp;
+ gT_coneProjTexture.filterMode = cudaFilterModeLinear;
+ gT_coneProjTexture.normalized = false;
+
+ cudaBindTextureToArray(gT_coneProjTexture, array, channelDesc);
+
+ // TODO: error value?
+
+ return true;
+}
+
+
+__global__ void dev_cone_BP(void* D_volData, unsigned int volPitch, int startAngle, const SDimensions3D dims)
+{
+ float* volData = (float*)D_volData;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+
+ // threadIdx: x = rel x
+ // y = rel y
+
+ // blockIdx: x = x + y
+ // y = z
+
+
+ // TO TRY: precompute part of detector intersection formulas in shared mem?
+ // TO TRY: inner loop over z, gather ray values in shared mem
+
+ const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x;
+ const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y;
+
+ if (X >= dims.iVolX)
+ return;
+ if (Y >= dims.iVolY)
+ return;
+
+ const int startZ = blockIdx.y * g_volBlockZ;
+ int endZ = startZ + g_volBlockZ;
+ if (endZ > dims.iVolZ)
+ endZ = dims.iVolZ;
+
+ float fX = X - 0.5f*dims.iVolX + 0.5f;
+ float fY = Y - 0.5f*dims.iVolY + 0.5f;
+ float fZ = startZ - 0.5f*dims.iVolZ + 0.5f;
+
+ for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f)
+ {
+
+ float fVal = 0.0f;
+ float fAngle = startAngle + 0.5f;
+
+ for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f)
+ {
+
+ const float fCux = gC_Cux[angle];
+ const float fCuy = gC_Cuy[angle];
+ const float fCuz = gC_Cuz[angle];
+ const float fCuc = gC_Cuc[angle];
+ const float fCvx = gC_Cvx[angle];
+ const float fCvy = gC_Cvy[angle];
+ const float fCvz = gC_Cvz[angle];
+ const float fCvc = gC_Cvc[angle];
+ const float fCdx = gC_Cdx[angle];
+ const float fCdy = gC_Cdy[angle];
+ const float fCdz = gC_Cdz[angle];
+ const float fCdc = gC_Cdc[angle];
+
+ const float fUNum = fCuc + fX * fCux + fY * fCuy + fZ * fCuz;
+ const float fVNum = fCvc + fX * fCvx + fY * fCvy + fZ * fCvz;
+ const float fDen = fCdc + fX * fCdx + fY * fCdy + fZ * fCdz;
+
+ const float fU = fUNum / fDen + 1.0f;
+ const float fV = fVNum / fDen + 1.0f;
+
+ fVal += tex3D(gT_coneProjTexture, fU, fAngle, fV);
+
+ }
+
+ volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal;
+ }
+
+}
+
+// supersampling version
+__global__ void dev_cone_BP_SS(void* D_volData, unsigned int volPitch, int startAngle, const SDimensions3D dims)
+{
+ float* volData = (float*)D_volData;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+
+ // threadIdx: x = rel x
+ // y = rel y
+
+ // blockIdx: x = x + y
+ // y = z
+
+
+ // TO TRY: precompute part of detector intersection formulas in shared mem?
+ // TO TRY: inner loop over z, gather ray values in shared mem
+
+ const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x;
+ const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y;
+
+ if (X >= dims.iVolX)
+ return;
+ if (Y >= dims.iVolY)
+ return;
+
+ const int startZ = blockIdx.y * g_volBlockZ;
+ int endZ = startZ + g_volBlockZ;
+ if (endZ > dims.iVolZ)
+ endZ = dims.iVolZ;
+
+ float fX = X - 0.5f*dims.iVolX + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
+ float fY = Y - 0.5f*dims.iVolY + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
+ float fZ = startZ - 0.5f*dims.iVolZ + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
+ const float fSubStep = 1.0f/dims.iRaysPerVoxelDim;
+
+ for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f)
+ {
+
+ float fVal = 0.0f;
+ float fAngle = startAngle + 0.5f;
+
+ for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f)
+ {
+
+ const float fCux = gC_Cux[angle];
+ const float fCuy = gC_Cuy[angle];
+ const float fCuz = gC_Cuz[angle];
+ const float fCuc = gC_Cuc[angle];
+ const float fCvx = gC_Cvx[angle];
+ const float fCvy = gC_Cvy[angle];
+ const float fCvz = gC_Cvz[angle];
+ const float fCvc = gC_Cvc[angle];
+ const float fCdx = gC_Cdx[angle];
+ const float fCdy = gC_Cdy[angle];
+ const float fCdz = gC_Cdz[angle];
+ const float fCdc = gC_Cdc[angle];
+
+ float fXs = fX;
+ for (int iSubX = 0; iSubX < dims.iRaysPerVoxelDim; ++iSubX) {
+ float fYs = fY;
+ for (int iSubY = 0; iSubY < dims.iRaysPerVoxelDim; ++iSubY) {
+ float fZs = fZ;
+ for (int iSubZ = 0; iSubZ < dims.iRaysPerVoxelDim; ++iSubZ) {
+
+ const float fUNum = fCuc + fXs * fCux + fYs * fCuy + fZs * fCuz;
+ const float fVNum = fCvc + fXs * fCvx + fYs * fCvy + fZs * fCvz;
+ const float fDen = fCdc + fXs * fCdx + fYs * fCdy + fZs * fCdz;
+
+ const float fU = fUNum / fDen + 1.0f;
+ const float fV = fVNum / fDen + 1.0f;
+
+ fVal += tex3D(gT_coneProjTexture, fU, fAngle, fV);
+
+ fZs += fSubStep;
+ }
+ fYs += fSubStep;
+ }
+ fXs += fSubStep;
+ }
+
+ }
+
+ volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal / (dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim);
+ }
+
+}
+
+
+bool ConeBP_Array(cudaPitchedPtr D_volumeData,
+ cudaArray *D_projArray,
+ const SDimensions3D& dims, const SConeProjection* angles)
+{
+ bindProjDataTexture(D_projArray);
+
+
+ // transfer angles to constant memory
+ float* tmp = new float[dims.iProjAngles];
+
+#define TRANSFER_TO_CONSTANT(expr,name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = (expr) ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
+
+ TRANSFER_TO_CONSTANT( (angles[i].fDetSZ - angles[i].fSrcZ)*angles[i].fDetVY - (angles[i].fDetSY - angles[i].fSrcY)*angles[i].fDetVZ , Cux );
+ TRANSFER_TO_CONSTANT( (angles[i].fDetSX - angles[i].fSrcX)*angles[i].fDetVZ -(angles[i].fDetSZ - angles[i].fSrcZ)*angles[i].fDetVX , Cuy );
+ TRANSFER_TO_CONSTANT( (angles[i].fDetSY - angles[i].fSrcY)*angles[i].fDetVX - (angles[i].fDetSX - angles[i].fSrcX)*angles[i].fDetVY , Cuz );
+ TRANSFER_TO_CONSTANT( (angles[i].fDetSY*angles[i].fDetVZ - angles[i].fDetSZ*angles[i].fDetVY)*angles[i].fSrcX - (angles[i].fDetSX*angles[i].fDetVZ - angles[i].fDetSZ*angles[i].fDetVX)*angles[i].fSrcY + (angles[i].fDetSX*angles[i].fDetVY - angles[i].fDetSY*angles[i].fDetVX)*angles[i].fSrcZ , Cuc );
+
+ TRANSFER_TO_CONSTANT( (angles[i].fDetSY - angles[i].fSrcY)*angles[i].fDetUZ-(angles[i].fDetSZ - angles[i].fSrcZ)*angles[i].fDetUY, Cvx );
+ TRANSFER_TO_CONSTANT( (angles[i].fDetSZ - angles[i].fSrcZ)*angles[i].fDetUX - (angles[i].fDetSX - angles[i].fSrcX)*angles[i].fDetUZ , Cvy );
+ TRANSFER_TO_CONSTANT((angles[i].fDetSX - angles[i].fSrcX)*angles[i].fDetUY-(angles[i].fDetSY - angles[i].fSrcY)*angles[i].fDetUX , Cvz );
+ TRANSFER_TO_CONSTANT( -(angles[i].fDetSY*angles[i].fDetUZ - angles[i].fDetSZ*angles[i].fDetUY)*angles[i].fSrcX + (angles[i].fDetSX*angles[i].fDetUZ - angles[i].fDetSZ*angles[i].fDetUX)*angles[i].fSrcY - (angles[i].fDetSX*angles[i].fDetUY - angles[i].fDetSY*angles[i].fDetUX)*angles[i].fSrcZ , Cvc );
+
+ TRANSFER_TO_CONSTANT( angles[i].fDetUY*angles[i].fDetVZ - angles[i].fDetUZ*angles[i].fDetVY , Cdx );
+ TRANSFER_TO_CONSTANT( angles[i].fDetUZ*angles[i].fDetVX - angles[i].fDetUX*angles[i].fDetVZ , Cdy );
+ TRANSFER_TO_CONSTANT( angles[i].fDetUX*angles[i].fDetVY - angles[i].fDetUY*angles[i].fDetVX , Cdz );
+ TRANSFER_TO_CONSTANT( -angles[i].fSrcX * (angles[i].fDetUY*angles[i].fDetVZ - angles[i].fDetUZ*angles[i].fDetVY) - angles[i].fSrcY * (angles[i].fDetUZ*angles[i].fDetVX - angles[i].fDetUX*angles[i].fDetVZ) - angles[i].fSrcZ * (angles[i].fDetUX*angles[i].fDetVY - angles[i].fDetUY*angles[i].fDetVX) , Cdc );
+
+#undef TRANSFER_TO_CONSTANT
+
+ delete[] tmp;
+
+ dim3 dimBlock(g_volBlockX, g_volBlockY);
+
+ dim3 dimGrid(((dims.iVolX+g_volBlockX-1)/g_volBlockX)*((dims.iVolY+g_volBlockY-1)/g_volBlockY), (dims.iVolZ+g_volBlockZ-1)/g_volBlockZ);
+
+ // timeval t;
+ // tic(t);
+
+ for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) {
+ // printf("Calling BP: %d, %dx%d, %dx%d to %p\n", i, dimBlock.x, dimBlock.y, dimGrid.x, dimGrid.y, (void*)D_volumeData.ptr);
+ if (dims.iRaysPerVoxelDim == 1)
+ dev_cone_BP<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, dims);
+ else
+ dev_cone_BP_SS<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, dims);
+ }
+
+ cudaTextForceKernelsCompletion();
+
+ // printf("%f\n", toc(t));
+
+ return true;
+}
+
+bool ConeBP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SConeProjection* angles)
+{
+ // transfer projections to array
+
+ cudaArray* cuArray = allocateProjectionArray(dims);
+ transferProjectionsToArray(D_projData, cuArray, dims);
+
+ bool ret = ConeBP_Array(D_volumeData, cuArray, dims, angles);
+
+ cudaFreeArray(cuArray);
+
+ return ret;
+}
+
+
+}
+
+#ifdef STANDALONE
+int main()
+{
+ SDimensions3D dims;
+ dims.iVolX = 256;
+ dims.iVolY = 256;
+ dims.iVolZ = 256;
+ dims.iProjAngles = 180;
+ dims.iProjU = 512;
+ dims.iProjV = 512;
+ dims.iRaysPerDet = 1;
+
+ cudaExtent extentV;
+ extentV.width = dims.iVolX*sizeof(float);
+ extentV.height = dims.iVolY;
+ extentV.depth = dims.iVolZ;
+
+ cudaPitchedPtr volData; // pitch, ptr, xsize, ysize
+
+ cudaMalloc3D(&volData, extentV);
+
+ cudaExtent extentP;
+ extentP.width = dims.iProjU*sizeof(float);
+ extentP.height = dims.iProjAngles;
+ extentP.depth = dims.iProjV;
+
+ cudaPitchedPtr projData; // pitch, ptr, xsize, ysize
+
+ cudaMalloc3D(&projData, extentP);
+ cudaMemset3D(projData, 0, extentP);
+
+ float* slice = new float[256*256];
+ cudaPitchedPtr ptr;
+ ptr.ptr = slice;
+ ptr.pitch = 256*sizeof(float);
+ ptr.xsize = 256*sizeof(float);
+ ptr.ysize = 256;
+
+ for (unsigned int i = 0; i < 256*256; ++i)
+ slice[i] = 1.0f;
+ for (unsigned int i = 0; i < 256; ++i) {
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, i };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaMemcpy3D(&p);
+#if 0
+ if (i == 128) {
+ for (unsigned int j = 0; j < 256*256; ++j)
+ slice[j] = 0.0f;
+ }
+#endif
+ }
+
+
+ SConeProjection angle[180];
+ angle[0].fSrcX = -1536;
+ angle[0].fSrcY = 0;
+ angle[0].fSrcZ = 0;
+
+ angle[0].fDetSX = 512;
+ angle[0].fDetSY = -256;
+ angle[0].fDetSZ = -256;
+
+ angle[0].fDetUX = 0;
+ angle[0].fDetUY = 1;
+ angle[0].fDetUZ = 0;
+
+ angle[0].fDetVX = 0;
+ angle[0].fDetVY = 0;
+ angle[0].fDetVZ = 1;
+
+#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0)
+ for (int i = 1; i < 180; ++i) {
+ angle[i] = angle[0];
+ ROTATE0(Src, i, i*2*M_PI/180);
+ ROTATE0(DetS, i, i*2*M_PI/180);
+ ROTATE0(DetU, i, i*2*M_PI/180);
+ ROTATE0(DetV, i, i*2*M_PI/180);
+ }
+#undef ROTATE0
+
+ astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f);
+#if 0
+ float* bufs = new float[180*512];
+
+ for (int i = 0; i < 512; ++i) {
+ cudaMemcpy(bufs, ((float*)projData.ptr)+180*512*i, 180*512*sizeof(float), cudaMemcpyDeviceToHost);
+
+ printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize);
+
+ char fname[20];
+ sprintf(fname, "sino%03d.png", i);
+ saveImage(fname, 180, 512, bufs);
+ }
+
+ float* bufp = new float[512*512];
+
+ for (int i = 0; i < 180; ++i) {
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(bufp+512*j, ((float*)projData.ptr)+180*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost);
+ }
+
+ char fname[20];
+ sprintf(fname, "proj%03d.png", i);
+ saveImage(fname, 512, 512, bufp);
+ }
+#endif
+ for (unsigned int i = 0; i < 256*256; ++i)
+ slice[i] = 0.0f;
+ for (unsigned int i = 0; i < 256; ++i) {
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, i };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaMemcpy3D(&p);
+ }
+
+ astraCUDA3d::ConeBP(volData, projData, dims, angle);
+#if 0
+ float* buf = new float[256*256];
+
+ for (int i = 0; i < 256; ++i) {
+ cudaMemcpy(buf, ((float*)volData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost);
+
+ printf("%d %d %d\n", volData.pitch, volData.xsize, volData.ysize);
+
+ char fname[20];
+ sprintf(fname, "vol%03d.png", i);
+ saveImage(fname, 256, 256, buf);
+ }
+#endif
+
+}
+#endif
diff --git a/cuda/3d/cone_bp.h b/cuda/3d/cone_bp.h
new file mode 100644
index 0000000..c77714e
--- /dev/null
+++ b/cuda/3d/cone_bp.h
@@ -0,0 +1,45 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_CONE_BP_H
+#define _CUDA_CONE_BP_H
+
+namespace astraCUDA3d {
+
+_AstraExport bool ConeBP_Array(cudaPitchedPtr D_volumeData,
+ cudaArray *D_projArray,
+ const SDimensions3D& dims, const SConeProjection* angles);
+
+_AstraExport bool ConeBP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SConeProjection* angles);
+
+
+}
+
+#endif
diff --git a/cuda/3d/cone_fp.cu b/cuda/3d/cone_fp.cu
new file mode 100644
index 0000000..40dca4f
--- /dev/null
+++ b/cuda/3d/cone_fp.cu
@@ -0,0 +1,513 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+#include <list>
+
+#include <cuda.h>
+#include "util3d.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+#include "dims3d.h"
+
+typedef texture<float, 3, cudaReadModeElementType> texture3D;
+
+static texture3D gT_coneVolumeTexture;
+
+namespace astraCUDA3d {
+
+static const unsigned int g_anglesPerBlock = 4;
+
+// thickness of the slices we're splitting the volume up into
+static const unsigned int g_blockSlices = 64;
+static const unsigned int g_detBlockU = 32;
+static const unsigned int g_detBlockV = 32;
+
+static const unsigned g_MaxAngles = 1024;
+__constant__ float gC_SrcX[g_MaxAngles];
+__constant__ float gC_SrcY[g_MaxAngles];
+__constant__ float gC_SrcZ[g_MaxAngles];
+__constant__ float gC_DetSX[g_MaxAngles];
+__constant__ float gC_DetSY[g_MaxAngles];
+__constant__ float gC_DetSZ[g_MaxAngles];
+__constant__ float gC_DetUX[g_MaxAngles];
+__constant__ float gC_DetUY[g_MaxAngles];
+__constant__ float gC_DetUZ[g_MaxAngles];
+__constant__ float gC_DetVX[g_MaxAngles];
+__constant__ float gC_DetVY[g_MaxAngles];
+__constant__ float gC_DetVZ[g_MaxAngles];
+
+
+bool bindVolumeDataTexture(const cudaArray* array)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+
+ gT_coneVolumeTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_coneVolumeTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_coneVolumeTexture.addressMode[2] = cudaAddressModeClamp;
+ gT_coneVolumeTexture.filterMode = cudaFilterModeLinear;
+ gT_coneVolumeTexture.normalized = false;
+
+ cudaBindTextureToArray(gT_coneVolumeTexture, array, channelDesc);
+
+ // TODO: error value?
+
+ return true;
+}
+
+ // threadIdx: x = ??? detector (u?)
+ // y = relative angle
+
+ // blockIdx: x = ??? detector (u+v?)
+ // y = angle block
+
+
+#define CONE_FP_BODY(c0,c1,c2) \
+ int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \
+ if (angle >= endAngle) \
+ return; \
+ \
+ const float fSrcX = gC_SrcX[angle]; \
+ const float fSrcY = gC_SrcY[angle]; \
+ const float fSrcZ = gC_SrcZ[angle]; \
+ const float fDetUX = gC_DetUX[angle]; \
+ const float fDetUY = gC_DetUY[angle]; \
+ const float fDetUZ = gC_DetUZ[angle]; \
+ const float fDetVX = gC_DetVX[angle]; \
+ const float fDetVY = gC_DetVY[angle]; \
+ const float fDetVZ = gC_DetVZ[angle]; \
+ const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \
+ const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \
+ const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \
+ \
+ const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \
+ const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \
+ int endDetectorV = startDetectorV + g_detBlockV; \
+ if (endDetectorV > dims.iProjV) \
+ endDetectorV = dims.iProjV; \
+ \
+ int endSlice = startSlice + g_blockSlices; \
+ if (endSlice > dims.iVol##c0) \
+ endSlice = dims.iVol##c0; \
+ \
+ for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \
+ { \
+ /* Trace ray from Src to (detectorU,detectorV) from */ \
+ /* X = startSlice to X = endSlice */ \
+ \
+ const float fDetX = fDetSX + detectorU*fDetUX + detectorV*fDetVX; \
+ const float fDetY = fDetSY + detectorU*fDetUY + detectorV*fDetVY; \
+ const float fDetZ = fDetSZ + detectorU*fDetUZ + detectorV*fDetVZ; \
+ \
+ /* (x) ( 1) ( 0) */ \
+ /* ray: (y) = (ay) * x + (by) */ \
+ /* (z) (az) (bz) */ \
+ \
+ const float a##c1 = (fSrc##c1 - fDet##c1) / (fSrc##c0 - fDet##c0); \
+ const float a##c2 = (fSrc##c2 - fDet##c2) / (fSrc##c0 - fDet##c0); \
+ const float b##c1 = fSrc##c1 - a##c1 * fSrc##c0; \
+ const float b##c2 = fSrc##c2 - a##c2 * fSrc##c0; \
+ \
+ const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \
+ \
+ float fVal = 0.0f; \
+ \
+ float f##c0 = startSlice + 1.5f; \
+ float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f; \
+ float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f; \
+ \
+ for (int s = startSlice; s < endSlice; ++s) \
+ { \
+ fVal += tex3D(gT_coneVolumeTexture, fX, fY, fZ); \
+ f##c0 += 1.0f; \
+ f##c1 += a##c1; \
+ f##c2 += a##c2; \
+ } \
+ \
+ fVal *= fDistCorr; \
+ \
+ D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fVal; \
+ }
+
+#define CONE_FP_SS_BODY(c0,c1,c2) \
+ int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \
+ if (angle >= endAngle) \
+ return; \
+ \
+ const float fSrcX = gC_SrcX[angle]; \
+ const float fSrcY = gC_SrcY[angle]; \
+ const float fSrcZ = gC_SrcZ[angle]; \
+ const float fDetUX = gC_DetUX[angle]; \
+ const float fDetUY = gC_DetUY[angle]; \
+ const float fDetUZ = gC_DetUZ[angle]; \
+ const float fDetVX = gC_DetVX[angle]; \
+ const float fDetVY = gC_DetVY[angle]; \
+ const float fDetVZ = gC_DetVZ[angle]; \
+ const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \
+ const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \
+ const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \
+ \
+ const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \
+ const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \
+ int endDetectorV = startDetectorV + g_detBlockV; \
+ if (endDetectorV > dims.iProjV) \
+ endDetectorV = dims.iProjV; \
+ \
+ int endSlice = startSlice + g_blockSlices; \
+ if (endSlice > dims.iVolX) \
+ endSlice = dims.iVolX; \
+ \
+ const float fSubStep = 1.0f/dims.iRaysPerDetDim; \
+ \
+ for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \
+ { \
+ /* Trace ray from Src to (detectorU,detectorV) from */ \
+ /* X = startSlice to X = endSlice */ \
+ \
+ float fV = 0.0f; \
+ \
+ float fdU = detectorU - 0.5f + 0.5f*fSubStep; \
+ for (int iSubU = 0; iSubU < dims.iRaysPerDetDim; ++iSubU, fdU+=fSubStep) { \
+ float fdV = detectorV - 0.5f + 0.5f*fSubStep; \
+ for (int iSubV = 0; iSubV < dims.iRaysPerDetDim; ++iSubV, fdV+=fSubStep) { \
+ \
+ const float fDetX = fDetSX + fdU*fDetUX + fdV*fDetVX; \
+ const float fDetY = fDetSY + fdU*fDetUY + fdV*fDetVY; \
+ const float fDetZ = fDetSZ + fdU*fDetUZ + fdV*fDetVZ; \
+ \
+ /* (x) ( 1) ( 0) */ \
+ /* ray: (y) = (ay) * x + (by) */ \
+ /* (z) (az) (bz) */ \
+ \
+ const float a##c1 = (fSrc##c1 - fDet##c1) / (fSrc##c0 - fDet##c0); \
+ const float a##c2 = (fSrc##c2 - fDet##c2) / (fSrc##c0 - fDet##c0); \
+ const float b##c1 = fSrc##c1 - a##c1 * fSrc##c0; \
+ const float b##c2 = fSrc##c2 - a##c2 * fSrc##c0; \
+ \
+ const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \
+ \
+ float fVal = 0.0f; \
+ \
+ float f##c0 = startSlice + 1.5f; \
+ float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f; \
+ float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f; \
+ \
+ for (int s = startSlice; s < endSlice; ++s) \
+ { \
+ fVal += tex3D(gT_coneVolumeTexture, fX, fY, fZ); \
+ f##c0 += 1.0f; \
+ f##c1 += a##c1; \
+ f##c2 += a##c2; \
+ } \
+ \
+ fVal *= fDistCorr; \
+ fV += fVal; \
+ \
+ } \
+ } \
+ \
+ D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fV / (dims.iRaysPerDetDim * dims.iRaysPerDetDim);\
+ }
+
+
+
+
+
+__global__ void FP_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+CONE_FP_BODY(X,Y,Z)
+}
+
+__global__ void FP_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+CONE_FP_BODY(Y,X,Z)
+}
+
+__global__ void FP_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+CONE_FP_BODY(Z,X,Y)
+}
+
+
+__global__ void FP_SS_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+CONE_FP_SS_BODY(X,Y,Z)
+}
+
+__global__ void FP_SS_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+CONE_FP_SS_BODY(Y,X,Z)
+}
+
+__global__ void FP_SS_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+CONE_FP_SS_BODY(Z,X,Y)
+}
+
+
+
+bool ConeFP_Array(cudaArray *D_volArray,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SConeProjection* angles,
+ float fOutputScale)
+{
+ bindVolumeDataTexture(D_volArray);
+
+ // transfer angles to constant memory
+ float* tmp = new float[dims.iProjAngles];
+
+#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
+
+ TRANSFER_TO_CONSTANT(SrcX);
+ TRANSFER_TO_CONSTANT(SrcY);
+ TRANSFER_TO_CONSTANT(SrcZ);
+ TRANSFER_TO_CONSTANT(DetSX);
+ TRANSFER_TO_CONSTANT(DetSY);
+ TRANSFER_TO_CONSTANT(DetSZ);
+ TRANSFER_TO_CONSTANT(DetUX);
+ TRANSFER_TO_CONSTANT(DetUY);
+ TRANSFER_TO_CONSTANT(DetUZ);
+ TRANSFER_TO_CONSTANT(DetVX);
+ TRANSFER_TO_CONSTANT(DetVY);
+ TRANSFER_TO_CONSTANT(DetVZ);
+
+#undef TRANSFER_TO_CONSTANT
+
+ delete[] tmp;
+
+ std::list<cudaStream_t> streams;
+ dim3 dimBlock(g_detBlockU, g_anglesPerBlock); // region size, angles
+
+ // Run over all angles, grouping them into groups of the same
+ // orientation (roughly horizontal vs. roughly vertical).
+ // Start a stream of grids for each such group.
+
+ unsigned int blockStart = 0;
+ unsigned int blockEnd = 0;
+ int blockDirection = 0;
+
+ // timeval t;
+ // tic(t);
+
+ for (unsigned int a = 0; a <= dims.iProjAngles; ++a) {
+ int dir;
+ if (a != dims.iProjAngles) {
+ float dX = fabsf(angles[a].fSrcX - (angles[a].fDetSX + dims.iProjU*angles[a].fDetUX*0.5f + dims.iProjV*angles[a].fDetVX*0.5f));
+ float dY = fabsf(angles[a].fSrcY - (angles[a].fDetSY + dims.iProjU*angles[a].fDetUY*0.5f + dims.iProjV*angles[a].fDetVY*0.5f));
+ float dZ = fabsf(angles[a].fSrcZ - (angles[a].fDetSZ + dims.iProjU*angles[a].fDetUZ*0.5f + dims.iProjV*angles[a].fDetVZ*0.5f));
+
+ if (dX >= dY && dX >= dZ)
+ dir = 0;
+ else if (dY >= dX && dY >= dZ)
+ dir = 1;
+ else
+ dir = 2;
+ }
+
+ if (a == dims.iProjAngles || dir != blockDirection) {
+ // block done
+
+ blockEnd = a;
+ if (blockStart != blockEnd) {
+
+ dim3 dimGrid(
+ ((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV),
+(blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock);
+ // TODO: check if we can't immediately
+ // destroy the stream after use
+ cudaStream_t stream;
+ cudaStreamCreate(&stream);
+ streams.push_back(stream);
+
+ // printf("angle block: %d to %d, %d (%dx%d, %dx%d)\n", blockStart, blockEnd, blockDirection, dimGrid.x, dimGrid.y, dimBlock.x, dimBlock.y);
+
+ if (blockDirection == 0) {
+ for (unsigned int i = 0; i < dims.iVolX; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ FP_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+ FP_SS_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ } else if (blockDirection == 1) {
+ for (unsigned int i = 0; i < dims.iVolY; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ FP_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+ FP_SS_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ } else if (blockDirection == 2) {
+ for (unsigned int i = 0; i < dims.iVolZ; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ FP_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+ FP_SS_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ }
+
+ }
+
+ blockDirection = dir;
+ blockStart = a;
+ }
+ }
+
+ for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter)
+ cudaStreamDestroy(*iter);
+
+ streams.clear();
+
+ cudaTextForceKernelsCompletion();
+
+ // printf("%f\n", toc(t));
+
+ return true;
+}
+
+bool ConeFP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SConeProjection* angles,
+ float fOutputScale)
+{
+ // transfer volume to array
+
+ cudaArray* cuArray = allocateVolumeArray(dims);
+ transferVolumeToArray(D_volumeData, cuArray, dims);
+
+ bool ret = ConeFP_Array(cuArray, D_projData, dims, angles, fOutputScale);
+
+ cudaFreeArray(cuArray);
+
+ return ret;
+}
+
+
+}
+
+#ifdef STANDALONE
+int main()
+{
+ SDimensions3D dims;
+ dims.iVolX = 256;
+ dims.iVolY = 256;
+ dims.iVolZ = 256;
+ dims.iProjAngles = 32;
+ dims.iProjU = 512;
+ dims.iProjV = 512;
+ dims.iRaysPerDet = 1;
+
+ cudaExtent extentV;
+ extentV.width = dims.iVolX*sizeof(float);
+ extentV.height = dims.iVolY;
+ extentV.depth = dims.iVolZ;
+
+ cudaPitchedPtr volData; // pitch, ptr, xsize, ysize
+
+ cudaMalloc3D(&volData, extentV);
+
+ cudaExtent extentP;
+ extentP.width = dims.iProjU*sizeof(float);
+ extentP.height = dims.iProjV;
+ extentP.depth = dims.iProjAngles;
+
+ cudaPitchedPtr projData; // pitch, ptr, xsize, ysize
+
+ cudaMalloc3D(&projData, extentP);
+ cudaMemset3D(projData, 0, extentP);
+
+ float* slice = new float[256*256];
+ cudaPitchedPtr ptr;
+ ptr.ptr = slice;
+ ptr.pitch = 256*sizeof(float);
+ ptr.xsize = 256*sizeof(float);
+ ptr.ysize = 256;
+
+ for (unsigned int i = 0; i < 256*256; ++i)
+ slice[i] = 1.0f;
+ for (unsigned int i = 0; i < 256; ++i) {
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, i };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaError err = cudaMemcpy3D(&p);
+ assert(!err);
+ }
+
+
+ SConeProjection angle[32];
+ angle[0].fSrcX = -1536;
+ angle[0].fSrcY = 0;
+ angle[0].fSrcZ = 200;
+
+ angle[0].fDetSX = 512;
+ angle[0].fDetSY = -256;
+ angle[0].fDetSZ = -256;
+
+ angle[0].fDetUX = 0;
+ angle[0].fDetUY = 1;
+ angle[0].fDetUZ = 0;
+
+ angle[0].fDetVX = 0;
+ angle[0].fDetVY = 0;
+ angle[0].fDetVZ = 1;
+
+#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0)
+ for (int i = 1; i < 32; ++i) {
+ angle[i] = angle[0];
+ ROTATE0(Src, i, i*1*M_PI/180);
+ ROTATE0(DetS, i, i*1*M_PI/180);
+ ROTATE0(DetU, i, i*1*M_PI/180);
+ ROTATE0(DetV, i, i*1*M_PI/180);
+ }
+#undef ROTATE0
+
+ astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f);
+
+ float* buf = new float[512*512];
+
+ cudaMemcpy(buf, ((float*)projData.ptr)+512*512*8, 512*512*sizeof(float), cudaMemcpyDeviceToHost);
+
+ printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize);
+
+ saveImage("proj.png", 512, 512, buf);
+
+
+}
+#endif
diff --git a/cuda/3d/cone_fp.h b/cuda/3d/cone_fp.h
new file mode 100644
index 0000000..2a0463b
--- /dev/null
+++ b/cuda/3d/cone_fp.h
@@ -0,0 +1,46 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_CONE_FP_H
+#define _CUDA_CONE_FP_H
+
+namespace astraCUDA3d {
+
+_AstraExport bool ConeFP_Array(cudaArray *D_volArray,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SConeProjection* angles,
+ float fOutputScale);
+
+_AstraExport bool ConeFP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SConeProjection* angles,
+ float fOutputScale);
+
+}
+
+#endif
diff --git a/cuda/3d/darthelper3d.cu b/cuda/3d/darthelper3d.cu
new file mode 100644
index 0000000..68330a1
--- /dev/null
+++ b/cuda/3d/darthelper3d.cu
@@ -0,0 +1,229 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "util3d.h"
+#include "dims3d.h"
+#include "darthelper3d.h"
+#include <cassert>
+
+namespace astraCUDA3d {
+
+
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ __global__ void devDartSmoothing(cudaPitchedPtr out, cudaPitchedPtr in, float b, SDimensions3D dims)
+ {
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ unsigned int y = threadIdx.y + 16*blockIdx.y;
+
+ // Sacrifice the border pixels to simplify the implementation.
+ if (x > 0 && x < dims.iVolX - 1 && y > 0 && y < dims.iVolY - 1) {
+
+ float* d = (float*)in.ptr;
+ float* m = (float*)out.ptr;
+
+ unsigned int index;
+ unsigned int p = (out.pitch >> 2);
+
+ for (unsigned int z = 0; z <= dims.iVolZ-1; z++) {
+
+ float res = 0.0f;
+
+ // bottom slice
+ if (z > 0) {
+ index = ((z-1)*dims.iVolY + y) * p + x;
+ res += d[index-p-1] + d[index-p] + d[index-p+1] +
+ d[index -1] + d[index ] + d[index +1] +
+ d[index+p-1] + d[index+p] + d[index+p+1];
+ }
+
+ // top slice
+ if (z < dims.iVolZ-1) {
+ index = ((z+1)*dims.iVolY + y) * p + x;
+ res += d[index-p-1] + d[index-p] + d[index-p+1] +
+ d[index -1] + d[index ] + d[index +1] +
+ d[index+p-1] + d[index+p] + d[index+p+1];
+ }
+
+ // same slice
+ index = (z*dims.iVolY + y) * p + x;
+ res += d[index-p-1] + d[index-p] + d[index-p+1] +
+ d[index -1] + d[index +1] +
+ d[index+p-1] + d[index+p] + d[index+p+1];
+
+ // result
+ m[index] = (1.0f-b) * d[index] + b * 0.038461538f * res;
+
+ }
+
+ }
+ }
+
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ void dartSmoothing(float* out, const float* in, float b, unsigned int radius, SDimensions3D dims)
+ {
+ cudaPitchedPtr D_inData;
+ D_inData = allocateVolumeData(dims);
+ copyVolumeToDevice(in, D_inData, dims);
+
+ cudaPitchedPtr D_outData;
+ D_outData = allocateVolumeData(dims);
+ copyVolumeToDevice(out, D_outData, dims);
+
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+15)/16);
+
+ devDartSmoothing<<<gridSize, blockSize>>>(D_outData, D_inData, b, dims);
+
+ copyVolumeFromDevice(out, D_outData, dims);
+
+ cudaFree(D_outData.ptr);
+ cudaFree(D_inData.ptr);
+
+ }
+
+
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ // CUDA function for the masking of DART with a radius == 1
+ __global__ void devDartMasking(cudaPitchedPtr mask, cudaPitchedPtr in, unsigned int conn, SDimensions3D dims)
+ {
+ unsigned int x = threadIdx.x + 16*blockIdx.x;
+ unsigned int y = threadIdx.y + 16*blockIdx.y;
+
+ // Sacrifice the border pixels to simplify the implementation.
+ if (x > 0 && x < dims.iVolX - 1 && y > 0 && y < dims.iVolY - 1) {
+
+ float* d = (float*)in.ptr;
+ float* m = (float*)mask.ptr;
+
+ unsigned int index;
+ unsigned int p = (in.pitch >> 2);
+
+ for (unsigned int z = 0; z <= dims.iVolZ-1; z++) {
+
+ unsigned int o2 = (z*dims.iVolY + y) * p + x;
+
+ m[o2] = 0.0f;
+
+ // bottom slice
+ if (z > 0) {
+ index = ((z-1)*dims.iVolY + y) * p + x;
+ if ((conn == 26 &&
+ (d[index-p-1] != d[o2] || d[index-p] != d[o2] || d[index-p+1] != d[o2] ||
+ d[index -1] != d[o2] || d[index ] != d[o2] || d[index +1] != d[o2] ||
+ d[index+p-1] != d[o2] || d[index+p] != d[o2] || d[index+p+1] != d[o2] ))
+ ||
+ (conn == 6 && d[index] != d[o2]))
+ {
+ m[o2] = 1.0f;
+ continue;
+ }
+ }
+
+ // top slice
+ if (z < dims.iVolZ-1) {
+ index = ((z+1)*dims.iVolY + y) * p + x;
+ if ((conn == 26 &&
+ (d[index-p-1] != d[o2] || d[index-p] != d[o2] || d[index-p+1] != d[o2] ||
+ d[index -1] != d[o2] || d[index ] != d[o2] || d[index +1] != d[o2] ||
+ d[index+p-1] != d[o2] || d[index+p] != d[o2] || d[index+p+1] != d[o2] ))
+ ||
+ (conn == 6 && d[index] != d[o2]))
+ {
+ m[o2] = 1.0f;
+ continue;
+ }
+ }
+
+ // other slices
+ index = (z*dims.iVolY + y) * p + x;
+ if ((conn == 26 &&
+ (d[index-p-1] != d[o2] || d[index-p] != d[o2] || d[index-p+1] != d[o2] ||
+ d[index -1] != d[o2] || d[index +1] != d[o2] ||
+ d[index+p-1] != d[o2] || d[index+p] != d[o2] || d[index+p+1] != d[o2] ))
+ ||
+ (conn == 6 &&
+ ( d[index-p] != d[o2] ||
+ d[index -1] != d[o2] || d[index +1] != d[o2] ||
+ d[index+p] != d[o2] )))
+ {
+ m[o2] = 1.0f;
+ continue;
+ }
+
+ }
+
+ }
+ }
+
+
+
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ void dartMasking(float* mask, const float* segmentation, unsigned int conn, unsigned int radius, unsigned int threshold, SDimensions3D dims)
+ {
+ cudaPitchedPtr D_maskData;
+ D_maskData = allocateVolumeData(dims);
+ copyVolumeToDevice(mask, D_maskData, dims);
+
+ cudaPitchedPtr D_segmentationData;
+ D_segmentationData = allocateVolumeData(dims);
+ copyVolumeToDevice(segmentation, D_segmentationData, dims);
+
+ dim3 blockSize(16,16);
+ dim3 gridSize((dims.iVolX+15)/16, (dims.iVolY+15)/16);
+
+ if (threshold == 1 && radius == 1)
+ devDartMasking<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, dims);
+ //else if (threshold > 1 && radius == 1)
+ // devADartMask<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, threshold, pitch, width, height, 1, 1);
+ //else if (threshold == 1 && radius > 1)
+ // devDartMaskRadius<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, radius, pitch, width, height, 1, 1);
+ //else
+ // devADartMaskRadius<<<gridSize, blockSize>>>(D_maskData, D_segmentationData, conn, radius, threshold, pitch, width, height, 1, 1);
+
+ copyVolumeFromDevice(mask, D_maskData, dims);
+
+ cudaFree(D_maskData.ptr);
+ cudaFree(D_segmentationData.ptr);
+
+ }
+ // -------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+ bool setGPUIndex(int iGPUIndex)
+ {
+ cudaSetDevice(iGPUIndex);
+ cudaError_t err = cudaGetLastError();
+
+ // Ignore errors caused by calling cudaSetDevice multiple times
+ if (err != cudaSuccess && err != cudaErrorSetOnActiveProcess)
+ return false;
+
+ return true;
+ }
+
+
+}
diff --git a/cuda/3d/darthelper3d.h b/cuda/3d/darthelper3d.h
new file mode 100644
index 0000000..7899629
--- /dev/null
+++ b/cuda/3d/darthelper3d.h
@@ -0,0 +1,46 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_DARTHELPER3_H
+#define _CUDA_DARTHELPER3_H
+
+#include <cuda.h>
+#include <driver_types.h>
+#include "util3d.h"
+#include "algo3d.h"
+
+namespace astraCUDA3d {
+
+ void dartSmoothing(float* out, const float* in, float b, unsigned int radius, SDimensions3D dims);
+ void dartMasking(float* out, const float* in, unsigned int conn, unsigned int radius, unsigned int threshold, SDimensions3D dims);
+
+ bool setGPUIndex(int index);
+
+}
+
+#endif
diff --git a/cuda/3d/dims3d.h b/cuda/3d/dims3d.h
new file mode 100644
index 0000000..ec3c4a3
--- /dev/null
+++ b/cuda/3d/dims3d.h
@@ -0,0 +1,84 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_CONE_DIMS_H
+#define _CUDA_CONE_DIMS_H
+
+namespace astra {
+
+struct SConeProjection {
+ // the source
+ double fSrcX, fSrcY, fSrcZ;
+
+ // the origin ("bottom left") of the (flat-panel) detector
+ double fDetSX, fDetSY, fDetSZ;
+
+ // the U-edge of a detector pixel
+ double fDetUX, fDetUY, fDetUZ;
+
+ // the V-edge of a detector pixel
+ double fDetVX, fDetVY, fDetVZ;
+};
+
+struct SPar3DProjection {
+ // the ray direction
+ double fRayX, fRayY, fRayZ;
+
+ // the origin ("bottom left") of the (flat-panel) detector
+ double fDetSX, fDetSY, fDetSZ;
+
+ // the U-edge of a detector pixel
+ double fDetUX, fDetUY, fDetUZ;
+
+ // the V-edge of a detector pixel
+ double fDetVX, fDetVY, fDetVZ;
+};
+
+}
+
+
+namespace astraCUDA3d {
+
+using astra::SConeProjection;
+using astra::SPar3DProjection;
+
+struct SDimensions3D {
+ unsigned int iVolX;
+ unsigned int iVolY;
+ unsigned int iVolZ;
+ unsigned int iProjAngles;
+ unsigned int iProjU; // number of detectors in the U direction
+ unsigned int iProjV; // number of detectors in the V direction
+ unsigned int iRaysPerDetDim;
+ unsigned int iRaysPerVoxelDim;
+};
+
+}
+
+#endif
+
diff --git a/cuda/3d/fdk.cu b/cuda/3d/fdk.cu
new file mode 100644
index 0000000..ad0604c
--- /dev/null
+++ b/cuda/3d/fdk.cu
@@ -0,0 +1,646 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+#include <list>
+
+#include <cuda.h>
+#include "util3d.h"
+
+#ifdef STANDALONE
+#include "cone_fp.h"
+#include "testutil.h"
+#endif
+
+#include "dims3d.h"
+#include "../2d/fft.h"
+
+typedef texture<float, 3, cudaReadModeElementType> texture3D;
+
+static texture3D gT_coneProjTexture;
+
+namespace astraCUDA3d {
+
+static const unsigned int g_volBlockZ = 16;
+
+static const unsigned int g_anglesPerBlock = 64;
+static const unsigned int g_volBlockX = 32;
+static const unsigned int g_volBlockY = 16;
+
+static const unsigned int g_anglesPerWeightBlock = 16;
+static const unsigned int g_detBlockU = 32;
+static const unsigned int g_detBlockV = 32;
+
+static const unsigned g_MaxAngles = 2048;
+
+__constant__ float gC_angle_sin[g_MaxAngles];
+__constant__ float gC_angle_cos[g_MaxAngles];
+__constant__ float gC_angle[g_MaxAngles];
+
+
+// per-detector u/v shifts?
+
+static bool bindProjDataTexture(const cudaArray* array)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+
+ gT_coneProjTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_coneProjTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_coneProjTexture.addressMode[2] = cudaAddressModeClamp;
+ gT_coneProjTexture.filterMode = cudaFilterModeLinear;
+ gT_coneProjTexture.normalized = false;
+
+ cudaBindTextureToArray(gT_coneProjTexture, array, channelDesc);
+
+ // TODO: error value?
+
+ return true;
+}
+
+
+__global__ void devBP_FDK(void* D_volData, unsigned int volPitch, int startAngle, float fSrcOrigin, float fDetOrigin, float fSrcZ, float fDetZ, float fInvDetUSize, float fInvDetVSize, const SDimensions3D dims)
+{
+ float* volData = (float*)D_volData;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+
+ // threadIdx: x = rel x
+ // y = rel y
+
+ // blockIdx: x = x + y
+ // y = z
+
+
+ // TO TRY: precompute part of detector intersection formulas in shared mem?
+ // TO TRY: inner loop over z, gather ray values in shared mem
+
+ const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x;
+ const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y;
+
+ if (X > dims.iVolX)
+ return;
+ if (Y > dims.iVolY)
+ return;
+
+ const int startZ = blockIdx.y * g_volBlockZ;
+ int endZ = startZ + g_volBlockZ;
+ if (endZ > dims.iVolZ)
+ endZ = dims.iVolZ;
+
+ float fX = X - 0.5f*dims.iVolX + 0.5f;
+ float fY = Y - 0.5f*dims.iVolY + 0.5f;
+ float fZ = startZ - 0.5f*dims.iVolZ + 0.5f - fSrcZ;
+
+ const float fU_base = 0.5f*dims.iProjU - 0.5f + 1.5f;
+ const float fV_base = 0.5f*dims.iProjV - 0.5f + 1.5f + (fDetZ-fSrcZ);
+
+ // Note re. fZ/rV_base: the computations below are all relative to the
+ // optical axis, so we do the Z-adjustments beforehand.
+
+ for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f)
+ {
+
+ float fVal = 0.0f;
+ float fAngle = startAngle + 0.5f;
+
+ for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f)
+ {
+
+ const float cos_theta = gC_angle_cos[angle];
+ const float sin_theta = gC_angle_sin[angle];
+
+ const float fR = fSrcOrigin;
+ const float fD = fR - fX * sin_theta + fY * cos_theta;
+ float fWeight = fR / fD;
+ fWeight *= fWeight;
+
+ const float fScaleFactor = (fR + fDetOrigin) / fD;
+ const float fU = fU_base + (fX*cos_theta+fY*sin_theta) * fScaleFactor * fInvDetUSize;
+ const float fV = fV_base + fZ * fScaleFactor * fInvDetVSize;
+
+ fVal += tex3D(gT_coneProjTexture, fU, fAngle, fV);
+
+ }
+
+ volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal;
+// projData[(angle*dims.iProjV+detectorV)*projPitch+detectorU] = 10.0f;
+// if (threadIdx.x == 0 && threadIdx.y == 0) { printf("%d,%d,%d [%d / %d] -> %f\n", angle, detectorU, detectorV, (angle*dims.iProjV+detectorV)*projPitch+detectorU, projPitch, projData[(angle*dims.iProjV+detectorV)*projPitch+detectorU]); }
+ }
+
+}
+
+
+bool FDK_BP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ float fSrcOrigin, float fDetOrigin,
+ float fSrcZ, float fDetZ, float fDetUSize, float fDetVSize,
+ const SDimensions3D& dims, const float* angles)
+{
+ // transfer projections to array
+
+ cudaArray* cuArray = allocateProjectionArray(dims);
+ transferProjectionsToArray(D_projData, cuArray, dims);
+
+ bindProjDataTexture(cuArray);
+
+ float* angle_sin = new float[dims.iProjAngles];
+ float* angle_cos = new float[dims.iProjAngles];
+
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i) {
+ angle_sin[i] = sinf(angles[i]);
+ angle_cos[i] = cosf(angles[i]);
+ }
+ cudaError_t e1 = cudaMemcpyToSymbol(gC_angle_sin, angle_sin, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ cudaError_t e2 = cudaMemcpyToSymbol(gC_angle_cos, angle_cos, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice);
+ assert(e1 == cudaSuccess);
+ assert(e2 == cudaSuccess);
+
+ delete[] angle_sin;
+ delete[] angle_cos;
+
+ dim3 dimBlock(g_volBlockX, g_volBlockY);
+
+ dim3 dimGrid(((dims.iVolX+g_volBlockX-1)/g_volBlockX)*((dims.iVolY+g_volBlockY-1)/g_volBlockY), (dims.iVolZ+g_volBlockZ-1)/g_volBlockZ);
+
+ // timeval t;
+ // tic(t);
+
+ for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) {
+ devBP_FDK<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, fSrcOrigin, fDetOrigin, fSrcZ, fDetZ, 1.0f / fDetUSize, 1.0f / fDetVSize, dims);
+ }
+
+ cudaTextForceKernelsCompletion();
+
+ cudaFreeArray(cuArray);
+
+ // printf("%f\n", toc(t));
+
+ return true;
+}
+
+__global__ void devFDK_preweight(void* D_projData, unsigned int projPitch, unsigned int startAngle, unsigned int endAngle, float fSrcOrigin, float fDetOrigin, float fSrcZ, float fDetZ, float fDetUSize, float fDetVSize, const SDimensions3D dims)
+{
+ float* projData = (float*)D_projData;
+ int angle = startAngle + blockIdx.y * g_anglesPerWeightBlock + threadIdx.y;
+ if (angle >= endAngle)
+ return;
+
+ const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x;
+ const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV;
+ int endDetectorV = startDetectorV + g_detBlockV;
+ if (endDetectorV > dims.iProjV)
+ endDetectorV = dims.iProjV;
+
+ // We need the length of the central ray and the length of the ray(s) to
+ // our detector pixel(s).
+
+ const float fCentralRayLength = fSrcOrigin + fDetOrigin;
+
+ const float fU = (detectorU - 0.5f*dims.iProjU + 0.5f) * fDetUSize;
+
+ const float fT = fCentralRayLength * fCentralRayLength + fU * fU;
+
+ float fV = (startDetectorV - 0.5f*dims.iProjV + 0.5f) * fDetVSize + fDetZ - fSrcZ;
+
+ for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV)
+ {
+ const float fRayLength = sqrtf(fT + fV * fV);
+
+ const float fWeight = fCentralRayLength / fRayLength;
+
+ projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] *= fWeight;
+
+ fV += 1.0f;
+ }
+}
+
+__global__ void devFDK_ParkerWeight(void* D_projData, unsigned int projPitch, unsigned int startAngle, unsigned int endAngle, float fSrcOrigin, float fDetOrigin, float fSrcZ, float fDetZ, float fDetUSize, float fCentralFanAngle, const SDimensions3D dims)
+{
+ float* projData = (float*)D_projData;
+ int angle = startAngle + blockIdx.y * g_anglesPerWeightBlock + threadIdx.y;
+ if (angle >= endAngle)
+ return;
+
+ const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x;
+ const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV;
+ int endDetectorV = startDetectorV + g_detBlockV;
+ if (endDetectorV > dims.iProjV)
+ endDetectorV = dims.iProjV;
+
+ // We need the length of the central ray and the length of the projection
+ // of our ray onto the central slice
+
+ const float fCentralRayLength = fSrcOrigin + fDetOrigin;
+
+ // TODO: Detector pixel size
+ const float fU = (detectorU - 0.5f*dims.iProjU + 0.5f) * fDetUSize;
+
+ //const float fGamma = atanf(fU / fCentralRayLength);
+ //const float fBeta = gC_angle[angle];
+ const float fGamma = atanf(fU / fCentralRayLength);
+ const float fBeta = -gC_angle[angle];
+
+ // compute the weight depending on the location in the central fan's radon
+ // space
+ float fWeight;
+
+ if (fBeta <= 0.0f) {
+ fWeight = 0.0f;
+ } else if (fBeta <= 2.0f*(fCentralFanAngle + fGamma)) {
+ fWeight = sinf((M_PI / 4.0f) * fBeta / (fCentralFanAngle + fGamma));
+ fWeight *= fWeight;
+ } else if (fBeta <= M_PI + 2*fGamma) {
+ fWeight = 1.0f;
+ } else if (fBeta <= M_PI + 2*fCentralFanAngle) {
+ fWeight = sinf((M_PI / 4.0f) * (M_PI + 2.0f*fCentralFanAngle - fBeta) / (fCentralFanAngle - fGamma));
+ fWeight *= fWeight;
+ } else {
+ fWeight = 0.0f;
+ }
+
+ for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV)
+ {
+
+ projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] *= fWeight;
+
+ }
+}
+
+
+
+// Perform the FDK pre-weighting and filtering
+bool FDK_Filter(cudaPitchedPtr D_projData,
+ cufftComplex * D_filter,
+ float fSrcOrigin, float fDetOrigin,
+ float fSrcZ, float fDetZ,
+ float fDetUSize, float fDetVSize, bool bShortScan,
+ const SDimensions3D& dims, const float* angles)
+{
+ // The pre-weighting factor for a ray is the cosine of the angle between
+ // the central line and the ray.
+
+ dim3 dimBlock(g_detBlockU, g_anglesPerWeightBlock);
+ dim3 dimGrid( ((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV),
+ (dims.iProjAngles+g_anglesPerWeightBlock-1)/g_anglesPerWeightBlock);
+
+ int projPitch = D_projData.pitch/sizeof(float);
+
+ devFDK_preweight<<<dimGrid, dimBlock>>>(D_projData.ptr, projPitch, 0, dims.iProjAngles, fSrcOrigin, fDetOrigin, fSrcZ, fDetZ, fDetUSize, fDetVSize, dims);
+
+ cudaTextForceKernelsCompletion();
+
+ if (bShortScan) {
+ // We do short-scan Parker weighting
+
+ cudaError_t e1 = cudaMemcpyToSymbol(gC_angle, angles,
+ dims.iProjAngles*sizeof(float), 0,
+ cudaMemcpyHostToDevice);
+ assert(!e1);
+
+ // TODO: detector pixel size!
+ float fCentralFanAngle = atanf((dims.iProjU*0.5f) /
+ (fSrcOrigin + fDetOrigin));
+
+ devFDK_ParkerWeight<<<dimGrid, dimBlock>>>(D_projData.ptr, projPitch, 0, dims.iProjAngles, fSrcOrigin, fDetOrigin, fSrcZ, fDetZ, fDetUSize, fCentralFanAngle, dims);
+
+ }
+
+ cudaTextForceKernelsCompletion();
+
+
+ // The filtering is a regular ramp filter per detector line.
+
+ int iPaddedDetCount = calcNextPowerOfTwo(2 * dims.iProjU);
+ int iHalfFFTSize = calcFFTFourSize(iPaddedDetCount);
+
+
+
+ // We process one sinogram at a time.
+ float* D_sinoData = (float*)D_projData.ptr;
+
+ cufftComplex * D_sinoFFT = NULL;
+ allocateComplexOnDevice(dims.iProjAngles, iHalfFFTSize, &D_sinoFFT);
+
+ bool ok = true;
+
+ for (int v = 0; v < dims.iProjV; ++v) {
+
+ ok = runCudaFFT(dims.iProjAngles, D_sinoData, projPitch, 0,
+ dims.iProjU, iPaddedDetCount, iHalfFFTSize,
+ D_sinoFFT);
+
+ if (!ok) break;
+
+ applyFilter(dims.iProjAngles, iHalfFFTSize, D_sinoFFT, D_filter);
+
+
+ ok = runCudaIFFT(dims.iProjAngles, D_sinoFFT, D_sinoData, projPitch,
+ 0, dims.iProjU, iPaddedDetCount, iHalfFFTSize);
+
+ if (!ok) break;
+
+ D_sinoData += (dims.iProjAngles * projPitch);
+ }
+
+ freeComplexOnDevice(D_sinoFFT);
+
+ return ok;
+}
+
+
+bool FDK(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ float fSrcOrigin, float fDetOrigin,
+ float fSrcZ, float fDetZ, float fDetUSize, float fDetVSize,
+ const SDimensions3D& dims, const float* angles, bool bShortScan)
+{
+ bool ok;
+ // Generate filter
+ // TODO: Check errors
+ cufftComplex * D_filter;
+ int iPaddedDetCount = calcNextPowerOfTwo(2 * dims.iProjU);
+ int iHalfFFTSize = calcFFTFourSize(iPaddedDetCount);
+
+ cufftComplex *pHostFilter = new cufftComplex[dims.iProjAngles * iHalfFFTSize];
+ memset(pHostFilter, 0, sizeof(cufftComplex) * dims.iProjAngles * iHalfFFTSize);
+
+ genFilter(FILTER_RAMLAK, 1.0f, dims.iProjAngles, pHostFilter, iPaddedDetCount, iHalfFFTSize);
+
+ allocateComplexOnDevice(dims.iProjAngles, iHalfFFTSize, &D_filter);
+ uploadComplexArrayToDevice(dims.iProjAngles, iHalfFFTSize, pHostFilter, D_filter);
+
+ delete [] pHostFilter;
+
+
+ // Perform filtering
+
+ ok = FDK_Filter(D_projData, D_filter, fSrcOrigin, fDetOrigin,
+ fSrcZ, fDetZ, fDetUSize, fDetVSize,
+ bShortScan, dims, angles);
+
+ // Clean up filter
+ freeComplexOnDevice(D_filter);
+
+
+ if (!ok)
+ return false;
+
+ // Perform BP
+
+ ok = FDK_BP(D_volumeData, D_projData, fSrcOrigin, fDetOrigin, fSrcZ, fDetZ,
+ fDetUSize, fDetVSize, dims, angles);
+
+ if (!ok)
+ return false;
+
+ return true;
+}
+
+
+}
+
+#ifdef STANDALONE
+void dumpVolume(const char* filespec, const cudaPitchedPtr& data, const SDimensions3D& dims, float fMin, float fMax)
+{
+ float* buf = new float[dims.iVolX*dims.iVolY];
+ unsigned int pitch = data.pitch / sizeof(float);
+
+ for (int i = 0; i < dims.iVolZ; ++i) {
+ cudaMemcpy2D(buf, dims.iVolX*sizeof(float), ((float*)data.ptr)+pitch*dims.iVolY*i, data.pitch, dims.iVolX*sizeof(float), dims.iVolY, cudaMemcpyDeviceToHost);
+
+ char fname[512];
+ sprintf(fname, filespec, dims.iVolZ-i-1);
+ saveImage(fname, dims.iVolY, dims.iVolX, buf, fMin, fMax);
+ }
+}
+
+void dumpSinograms(const char* filespec, const cudaPitchedPtr& data, const SDimensions3D& dims, float fMin, float fMax)
+{
+ float* bufs = new float[dims.iProjAngles*dims.iProjU];
+ unsigned int pitch = data.pitch / sizeof(float);
+
+ for (int i = 0; i < dims.iProjV; ++i) {
+ cudaMemcpy2D(bufs, dims.iProjU*sizeof(float), ((float*)data.ptr)+pitch*dims.iProjAngles*i, data.pitch, dims.iProjU*sizeof(float), dims.iProjAngles, cudaMemcpyDeviceToHost);
+
+ char fname[512];
+ sprintf(fname, filespec, i);
+ saveImage(fname, dims.iProjAngles, dims.iProjU, bufs, fMin, fMax);
+ }
+}
+
+void dumpProjections(const char* filespec, const cudaPitchedPtr& data, const SDimensions3D& dims, float fMin, float fMax)
+{
+ float* bufp = new float[dims.iProjV*dims.iProjU];
+ unsigned int pitch = data.pitch / sizeof(float);
+
+ for (int i = 0; i < dims.iProjAngles; ++i) {
+ for (int j = 0; j < dims.iProjV; ++j) {
+ cudaMemcpy(bufp+dims.iProjU*j, ((float*)data.ptr)+pitch*dims.iProjAngles*j+pitch*i, dims.iProjU*sizeof(float), cudaMemcpyDeviceToHost);
+ }
+
+ char fname[512];
+ sprintf(fname, filespec, i);
+ saveImage(fname, dims.iProjV, dims.iProjU, bufp, fMin, fMax);
+ }
+}
+
+
+
+
+int main()
+{
+#if 0
+ SDimensions3D dims;
+ dims.iVolX = 512;
+ dims.iVolY = 512;
+ dims.iVolZ = 512;
+ dims.iProjAngles = 180;
+ dims.iProjU = 1024;
+ dims.iProjV = 1024;
+ dims.iRaysPerDet = 1;
+
+ cudaExtent extentV;
+ extentV.width = dims.iVolX*sizeof(float);
+ extentV.height = dims.iVolY;
+ extentV.depth = dims.iVolZ;
+
+ cudaPitchedPtr volData; // pitch, ptr, xsize, ysize
+
+ cudaMalloc3D(&volData, extentV);
+
+ cudaExtent extentP;
+ extentP.width = dims.iProjU*sizeof(float);
+ extentP.height = dims.iProjAngles;
+ extentP.depth = dims.iProjV;
+
+ cudaPitchedPtr projData; // pitch, ptr, xsize, ysize
+
+ cudaMalloc3D(&projData, extentP);
+ cudaMemset3D(projData, 0, extentP);
+
+#if 0
+ float* slice = new float[256*256];
+ cudaPitchedPtr ptr;
+ ptr.ptr = slice;
+ ptr.pitch = 256*sizeof(float);
+ ptr.xsize = 256*sizeof(float);
+ ptr.ysize = 256;
+
+ for (unsigned int i = 0; i < 256*256; ++i)
+ slice[i] = 1.0f;
+ for (unsigned int i = 0; i < 256; ++i) {
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, i };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaMemcpy3D(&p);
+#if 0
+ if (i == 128) {
+ for (unsigned int j = 0; j < 256*256; ++j)
+ slice[j] = 0.0f;
+ }
+#endif
+ }
+#endif
+
+ SConeProjection angle[180];
+ angle[0].fSrcX = -1536;
+ angle[0].fSrcY = 0;
+ angle[0].fSrcZ = 0;
+
+ angle[0].fDetSX = 1024;
+ angle[0].fDetSY = -512;
+ angle[0].fDetSZ = 512;
+
+ angle[0].fDetUX = 0;
+ angle[0].fDetUY = 1;
+ angle[0].fDetUZ = 0;
+
+ angle[0].fDetVX = 0;
+ angle[0].fDetVY = 0;
+ angle[0].fDetVZ = -1;
+
+#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0)
+ for (int i = 1; i < 180; ++i) {
+ angle[i] = angle[0];
+ ROTATE0(Src, i, i*2*M_PI/180);
+ ROTATE0(DetS, i, i*2*M_PI/180);
+ ROTATE0(DetU, i, i*2*M_PI/180);
+ ROTATE0(DetV, i, i*2*M_PI/180);
+ }
+#undef ROTATE0
+
+ astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f);
+
+ //dumpSinograms("sino%03d.png", projData, dims, 0, 512);
+ //dumpProjections("proj%03d.png", projData, dims, 0, 512);
+
+ astraCUDA3d::zeroVolumeData(volData, dims);
+
+ float* angles = new float[dims.iProjAngles];
+ for (int i = 0; i < 180; ++i)
+ angles[i] = i*2*M_PI/180;
+
+ astraCUDA3d::FDK(volData, projData, 1536, 512, 0, 0, dims, angles);
+
+ dumpVolume("vol%03d.png", volData, dims, -20, 100);
+
+
+#else
+
+ SDimensions3D dims;
+ dims.iVolX = 1000;
+ dims.iVolY = 999;
+ dims.iVolZ = 500;
+ dims.iProjAngles = 376;
+ dims.iProjU = 1024;
+ dims.iProjV = 524;
+ dims.iRaysPerDet = 1;
+
+ float* angles = new float[dims.iProjAngles];
+ for (int i = 0; i < dims.iProjAngles; ++i)
+ angles[i] = -i*(M_PI)/360;
+
+ cudaPitchedPtr volData = astraCUDA3d::allocateVolumeData(dims);
+ cudaPitchedPtr projData = astraCUDA3d::allocateProjectionData(dims);
+ astraCUDA3d::zeroProjectionData(projData, dims);
+ astraCUDA3d::zeroVolumeData(volData, dims);
+
+ timeval t;
+ tic(t);
+
+ for (int i = 0; i < dims.iProjAngles; ++i) {
+ char fname[256];
+ sprintf(fname, "/home/wpalenst/tmp/Elke/proj%04d.png", i);
+ unsigned int w,h;
+ float* bufp = loadImage(fname, w,h);
+
+ int pitch = projData.pitch / sizeof(float);
+ for (int j = 0; j < dims.iProjV; ++j) {
+ cudaMemcpy(((float*)projData.ptr)+dims.iProjAngles*pitch*j+pitch*i, bufp+dims.iProjU*j, dims.iProjU*sizeof(float), cudaMemcpyHostToDevice);
+ }
+
+ delete[] bufp;
+ }
+ printf("Load time: %f\n", toc(t));
+
+ //dumpSinograms("sino%03d.png", projData, dims, -8.0f, 256.0f);
+ //astraCUDA3d::FDK(volData, projData, 7350, 62355, 0, 10, dims, angles);
+ //astraCUDA3d::FDK(volData, projData, 7350, -380, 0, 10, dims, angles);
+
+ tic(t);
+
+ astraCUDA3d::FDK(volData, projData, 7383.29867, 0, 0, 10, dims, angles);
+
+ printf("FDK time: %f\n", toc(t));
+ tic(t);
+
+ dumpVolume("vol%03d.png", volData, dims, -65.9f, 200.0f);
+ //dumpVolume("vol%03d.png", volData, dims, 0.0f, 256.0f);
+ printf("Save time: %f\n", toc(t));
+
+#endif
+
+
+}
+#endif
diff --git a/cuda/3d/fdk.h b/cuda/3d/fdk.h
new file mode 100644
index 0000000..5443b19
--- /dev/null
+++ b/cuda/3d/fdk.h
@@ -0,0 +1,43 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_FDK_H
+#define _CUDA_FDK_H
+
+namespace astraCUDA3d {
+
+bool FDK(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ float fSrcOrigin, float fDetOrigin,
+ float fSrcZ, float fDetZ, float fDetUSize, float fDetVSize,
+ const SDimensions3D& dims, const float* angles, bool bShortScan);
+
+
+}
+
+#endif
diff --git a/cuda/3d/par3d_bp.cu b/cuda/3d/par3d_bp.cu
new file mode 100644
index 0000000..872b1eb
--- /dev/null
+++ b/cuda/3d/par3d_bp.cu
@@ -0,0 +1,464 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+#include <list>
+
+#include <cuda.h>
+#include "util3d.h"
+
+#ifdef STANDALONE
+#include "par3d_fp.h"
+#include "testutil.h"
+#endif
+
+#include "dims3d.h"
+
+typedef texture<float, 3, cudaReadModeElementType> texture3D;
+
+static texture3D gT_par3DProjTexture;
+
+namespace astraCUDA3d {
+
+static const unsigned int g_volBlockZ = 16;
+
+static const unsigned int g_anglesPerBlock = 64;
+static const unsigned int g_volBlockX = 32;
+static const unsigned int g_volBlockY = 16;
+
+static const unsigned g_MaxAngles = 1024;
+
+__constant__ float gC_Cux[g_MaxAngles];
+__constant__ float gC_Cuy[g_MaxAngles];
+__constant__ float gC_Cuz[g_MaxAngles];
+__constant__ float gC_Cuc[g_MaxAngles];
+__constant__ float gC_Cvx[g_MaxAngles];
+__constant__ float gC_Cvy[g_MaxAngles];
+__constant__ float gC_Cvz[g_MaxAngles];
+__constant__ float gC_Cvc[g_MaxAngles];
+
+
+static bool bindProjDataTexture(const cudaArray* array)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+
+ gT_par3DProjTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_par3DProjTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_par3DProjTexture.addressMode[2] = cudaAddressModeClamp;
+ gT_par3DProjTexture.filterMode = cudaFilterModeLinear;
+ gT_par3DProjTexture.normalized = false;
+
+ cudaBindTextureToArray(gT_par3DProjTexture, array, channelDesc);
+
+ // TODO: error value?
+
+ return true;
+}
+
+
+__global__ void dev_par3D_BP(void* D_volData, unsigned int volPitch, int startAngle, const SDimensions3D dims)
+{
+ float* volData = (float*)D_volData;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+
+ // threadIdx: x = rel x
+ // y = rel y
+
+ // blockIdx: x = x + y
+ // y = z
+
+
+ // TO TRY: precompute part of detector intersection formulas in shared mem?
+ // TO TRY: inner loop over z, gather ray values in shared mem
+
+ const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x;
+ const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y;
+
+ if (X >= dims.iVolX)
+ return;
+ if (Y >= dims.iVolY)
+ return;
+
+ const int startZ = blockIdx.y * g_volBlockZ;
+ int endZ = startZ + g_volBlockZ;
+ if (endZ > dims.iVolZ)
+ endZ = dims.iVolZ;
+
+ float fX = X - 0.5f*dims.iVolX + 0.5f;
+ float fY = Y - 0.5f*dims.iVolY + 0.5f;
+ float fZ = startZ - 0.5f*dims.iVolZ + 0.5f;
+
+ for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f)
+ {
+
+ float fVal = 0.0f;
+ float fAngle = startAngle + 0.5f;
+
+ for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f)
+ {
+
+ const float fCux = gC_Cux[angle];
+ const float fCuy = gC_Cuy[angle];
+ const float fCuz = gC_Cuz[angle];
+ const float fCuc = gC_Cuc[angle];
+ const float fCvx = gC_Cvx[angle];
+ const float fCvy = gC_Cvy[angle];
+ const float fCvz = gC_Cvz[angle];
+ const float fCvc = gC_Cvc[angle];
+
+ const float fUNum = fCuc + fX * fCux + fY * fCuy + fZ * fCuz;
+ const float fVNum = fCvc + fX * fCvx + fY * fCvy + fZ * fCvz;
+
+ const float fU = fUNum + 1.0f;
+ const float fV = fVNum + 1.0f;
+
+ fVal += tex3D(gT_par3DProjTexture, fU, fAngle, fV); // TODO: check order
+
+ }
+
+ volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal;
+ }
+
+}
+
+// supersampling version
+__global__ void dev_par3D_BP_SS(void* D_volData, unsigned int volPitch, int startAngle, const SDimensions3D dims)
+{
+ float* volData = (float*)D_volData;
+
+ int endAngle = startAngle + g_anglesPerBlock;
+ if (endAngle > dims.iProjAngles)
+ endAngle = dims.iProjAngles;
+
+ // threadIdx: x = rel x
+ // y = rel y
+
+ // blockIdx: x = x + y
+ // y = z
+
+
+ // TO TRY: precompute part of detector intersection formulas in shared mem?
+ // TO TRY: inner loop over z, gather ray values in shared mem
+
+ const int X = blockIdx.x % ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockX + threadIdx.x;
+ const int Y = blockIdx.x / ((dims.iVolX+g_volBlockX-1)/g_volBlockX) * g_volBlockY + threadIdx.y;
+
+ if (X >= dims.iVolX)
+ return;
+ if (Y >= dims.iVolY)
+ return;
+
+ const int startZ = blockIdx.y * g_volBlockZ;
+ int endZ = startZ + g_volBlockZ;
+ if (endZ > dims.iVolZ)
+ endZ = dims.iVolZ;
+
+ float fX = X - 0.5f*dims.iVolX + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
+ float fY = Y - 0.5f*dims.iVolY + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
+ float fZ = startZ - 0.5f*dims.iVolZ + 0.5f - 0.5f + 0.5f/dims.iRaysPerVoxelDim;
+
+ const float fSubStep = 1.0f/dims.iRaysPerVoxelDim;
+
+ for (int Z = startZ; Z < endZ; ++Z, fZ += 1.0f)
+ {
+
+ float fVal = 0.0f;
+ float fAngle = startAngle + 0.5f;
+
+ for (int angle = startAngle; angle < endAngle; ++angle, fAngle += 1.0f)
+ {
+ const float fCux = gC_Cux[angle];
+ const float fCuy = gC_Cuy[angle];
+ const float fCuz = gC_Cuz[angle];
+ const float fCuc = gC_Cuc[angle];
+ const float fCvx = gC_Cvx[angle];
+ const float fCvy = gC_Cvy[angle];
+ const float fCvz = gC_Cvz[angle];
+ const float fCvc = gC_Cvc[angle];
+
+ float fXs = fX;
+ for (int iSubX = 0; iSubX < dims.iRaysPerVoxelDim; ++iSubX) {
+ float fYs = fY;
+ for (int iSubY = 0; iSubY < dims.iRaysPerVoxelDim; ++iSubY) {
+ float fZs = fZ;
+ for (int iSubZ = 0; iSubZ < dims.iRaysPerVoxelDim; ++iSubZ) {
+
+ const float fUNum = fCuc + fXs * fCux + fYs * fCuy + fZs * fCuz;
+ const float fVNum = fCvc + fXs * fCvx + fYs * fCvy + fZs * fCvz;
+
+ const float fU = fUNum + 1.0f;
+ const float fV = fVNum + 1.0f;
+
+ fVal += tex3D(gT_par3DProjTexture, fU, fAngle, fV); // TODO: check order
+ fZs += fSubStep;
+ }
+ fYs += fSubStep;
+ }
+ fXs += fSubStep;
+ }
+
+ }
+
+ volData[(Z*dims.iVolY+Y)*volPitch+X] += fVal / (dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim*dims.iRaysPerVoxelDim);
+ }
+
+}
+
+bool Par3DBP_Array(cudaPitchedPtr D_volumeData,
+ cudaArray *D_projArray,
+ const SDimensions3D& dims, const SPar3DProjection* angles)
+{
+ bindProjDataTexture(D_projArray);
+
+
+ // transfer angles to constant memory
+ float* tmp = new float[dims.iProjAngles];
+
+#define TRANSFER_TO_CONSTANT(expr,name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = (expr) ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
+
+#define DENOM (angles[i].fRayX*angles[i].fDetUY*angles[i].fDetVZ - angles[i].fRayX*angles[i].fDetUZ*angles[i].fDetVY - angles[i].fRayY*angles[i].fDetUX*angles[i].fDetVZ + angles[i].fRayY*angles[i].fDetUZ*angles[i].fDetVX + angles[i].fRayZ*angles[i].fDetUX*angles[i].fDetVY - angles[i].fRayZ*angles[i].fDetUY*angles[i].fDetVX)
+
+
+ TRANSFER_TO_CONSTANT( ( - (angles[i].fRayY*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVY)) / DENOM , Cux );
+ TRANSFER_TO_CONSTANT( ( (angles[i].fRayX*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVX)) / DENOM , Cuy );
+ TRANSFER_TO_CONSTANT( (- (angles[i].fRayX*angles[i].fDetVY - angles[i].fRayY*angles[i].fDetVX) ) / DENOM , Cuz );
+ TRANSFER_TO_CONSTANT( (-(angles[i].fDetSY*angles[i].fDetVZ - angles[i].fDetSZ*angles[i].fDetVY)*angles[i].fRayX + (angles[i].fRayY*angles[i].fDetVZ - angles[i].fRayZ*angles[i].fDetVY)*angles[i].fDetSX - (angles[i].fRayY*angles[i].fDetSZ - angles[i].fRayZ*angles[i].fDetSY)*angles[i].fDetVX) / DENOM , Cuc );
+
+ TRANSFER_TO_CONSTANT( ((angles[i].fRayY*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUY) ) / DENOM , Cvx );
+ TRANSFER_TO_CONSTANT( (- (angles[i].fRayX*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUX) ) / DENOM , Cvy );
+ TRANSFER_TO_CONSTANT( ((angles[i].fRayX*angles[i].fDetUY - angles[i].fRayY*angles[i].fDetUX) ) / DENOM , Cvz );
+ TRANSFER_TO_CONSTANT( ((angles[i].fDetSY*angles[i].fDetUZ - angles[i].fDetSZ*angles[i].fDetUY)*angles[i].fRayX - (angles[i].fRayY*angles[i].fDetUZ - angles[i].fRayZ*angles[i].fDetUY)*angles[i].fDetSX + (angles[i].fRayY*angles[i].fDetSZ - angles[i].fRayZ*angles[i].fDetSY)*angles[i].fDetUX ) / DENOM , Cvc );
+
+#undef TRANSFER_TO_CONSTANT
+#undef DENOM
+
+ delete[] tmp;
+
+ dim3 dimBlock(g_volBlockX, g_volBlockY);
+
+ dim3 dimGrid(((dims.iVolX+g_volBlockX-1)/g_volBlockX)*((dims.iVolY+g_volBlockY-1)/g_volBlockY), (dims.iVolZ+g_volBlockZ-1)/g_volBlockZ);
+
+ // timeval t;
+ // tic(t);
+
+ for (unsigned int i = 0; i < dims.iProjAngles; i += g_anglesPerBlock) {
+ // printf("Calling BP: %d, %dx%d, %dx%d to %p\n", i, dimBlock.x, dimBlock.y, dimGrid.x, dimGrid.y, (void*)D_volumeData.ptr);
+ if (dims.iRaysPerVoxelDim == 1)
+ dev_par3D_BP<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, dims);
+ else
+ dev_par3D_BP_SS<<<dimGrid, dimBlock>>>(D_volumeData.ptr, D_volumeData.pitch/sizeof(float), i, dims);
+ }
+
+ cudaTextForceKernelsCompletion();
+
+ // printf("%f\n", toc(t));
+
+ return true;
+}
+
+bool Par3DBP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SPar3DProjection* angles)
+{
+ // transfer projections to array
+
+ cudaArray* cuArray = allocateProjectionArray(dims);
+ transferProjectionsToArray(D_projData, cuArray, dims);
+
+ bool ret = Par3DBP_Array(D_volumeData, cuArray, dims, angles);
+
+ cudaFreeArray(cuArray);
+
+ return ret;
+}
+
+
+}
+
+#ifdef STANDALONE
+int main()
+{
+ SDimensions3D dims;
+ dims.iVolX = 256;
+ dims.iVolY = 256;
+ dims.iVolZ = 256;
+ dims.iProjAngles = 180;
+ dims.iProjU = 512;
+ dims.iProjV = 512;
+ dims.iRaysPerDet = 1;
+
+ cudaExtent extentV;
+ extentV.width = dims.iVolX*sizeof(float);
+ extentV.height = dims.iVolY;
+ extentV.depth = dims.iVolZ;
+
+ cudaPitchedPtr volData; // pitch, ptr, xsize, ysize
+
+ cudaMalloc3D(&volData, extentV);
+
+ cudaExtent extentP;
+ extentP.width = dims.iProjU*sizeof(float);
+ extentP.height = dims.iProjAngles;
+ extentP.depth = dims.iProjV;
+
+ cudaPitchedPtr projData; // pitch, ptr, xsize, ysize
+
+ cudaMalloc3D(&projData, extentP);
+ cudaMemset3D(projData, 0, extentP);
+
+ float* slice = new float[256*256];
+ cudaPitchedPtr ptr;
+ ptr.ptr = slice;
+ ptr.pitch = 256*sizeof(float);
+ ptr.xsize = 256*sizeof(float);
+ ptr.ysize = 256;
+
+ for (unsigned int i = 0; i < 256*256; ++i)
+ slice[i] = 1.0f;
+ for (unsigned int i = 0; i < 256; ++i) {
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, i };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaMemcpy3D(&p);
+#if 0
+ if (i == 128) {
+ for (unsigned int j = 0; j < 256*256; ++j)
+ slice[j] = 0.0f;
+ }
+#endif
+ }
+
+
+ SPar3DProjection angle[180];
+ angle[0].fRayX = 1;
+ angle[0].fRayY = 0;
+ angle[0].fRayZ = 0;
+
+ angle[0].fDetSX = 512;
+ angle[0].fDetSY = -256;
+ angle[0].fDetSZ = -256;
+
+ angle[0].fDetUX = 0;
+ angle[0].fDetUY = 1;
+ angle[0].fDetUZ = 0;
+
+ angle[0].fDetVX = 0;
+ angle[0].fDetVY = 0;
+ angle[0].fDetVZ = 1;
+
+#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0)
+ for (int i = 1; i < 180; ++i) {
+ angle[i] = angle[0];
+ ROTATE0(Ray, i, i*2*M_PI/180);
+ ROTATE0(DetS, i, i*2*M_PI/180);
+ ROTATE0(DetU, i, i*2*M_PI/180);
+ ROTATE0(DetV, i, i*2*M_PI/180);
+ }
+#undef ROTATE0
+
+ astraCUDA3d::Par3DFP(volData, projData, dims, angle, 1.0f);
+#if 1
+ float* bufs = new float[180*512];
+
+ for (int i = 0; i < 512; ++i) {
+ cudaMemcpy(bufs, ((float*)projData.ptr)+180*512*i, 180*512*sizeof(float), cudaMemcpyDeviceToHost);
+
+ printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize);
+
+ char fname[20];
+ sprintf(fname, "sino%03d.png", i);
+ saveImage(fname, 180, 512, bufs, 0, 512);
+ }
+
+ float* bufp = new float[512*512];
+
+ for (int i = 0; i < 180; ++i) {
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(bufp+512*j, ((float*)projData.ptr)+180*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost);
+ }
+
+ char fname[20];
+ sprintf(fname, "proj%03d.png", i);
+ saveImage(fname, 512, 512, bufp, 0, 512);
+ }
+#endif
+ for (unsigned int i = 0; i < 256*256; ++i)
+ slice[i] = 0.0f;
+ for (unsigned int i = 0; i < 256; ++i) {
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, i };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaMemcpy3D(&p);
+ }
+
+ astraCUDA3d::Par3DBP(volData, projData, dims, angle);
+#if 1
+ float* buf = new float[256*256];
+
+ for (int i = 0; i < 256; ++i) {
+ cudaMemcpy(buf, ((float*)volData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost);
+
+ printf("%d %d %d\n", volData.pitch, volData.xsize, volData.ysize);
+
+ char fname[20];
+ sprintf(fname, "vol%03d.png", i);
+ saveImage(fname, 256, 256, buf, 0, 60000);
+ }
+#endif
+
+}
+#endif
diff --git a/cuda/3d/par3d_bp.h b/cuda/3d/par3d_bp.h
new file mode 100644
index 0000000..399a3cb
--- /dev/null
+++ b/cuda/3d/par3d_bp.h
@@ -0,0 +1,45 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_PAR3D_BP_H
+#define _CUDA_PAR3D_BP_H
+
+namespace astraCUDA3d {
+
+_AstraExport bool Par3DBP_Array(cudaPitchedPtr D_volumeData,
+ cudaArray *D_projArray,
+ const SDimensions3D& dims, const SPar3DProjection* angles);
+
+_AstraExport bool Par3DBP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SPar3DProjection* angles);
+
+
+}
+
+#endif
diff --git a/cuda/3d/par3d_fp.cu b/cuda/3d/par3d_fp.cu
new file mode 100644
index 0000000..6bf9037
--- /dev/null
+++ b/cuda/3d/par3d_fp.cu
@@ -0,0 +1,814 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include <iostream>
+#include <list>
+
+#include <cuda.h>
+#include "util3d.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+#include "dims3d.h"
+
+typedef texture<float, 3, cudaReadModeElementType> texture3D;
+
+static texture3D gT_par3DVolumeTexture;
+
+namespace astraCUDA3d {
+
+static const unsigned int g_anglesPerBlock = 4;
+
+// thickness of the slices we're splitting the volume up into
+static const unsigned int g_blockSlices = 64;
+static const unsigned int g_detBlockU = 32;
+static const unsigned int g_detBlockV = 32;
+
+static const unsigned g_MaxAngles = 1024;
+__constant__ float gC_RayX[g_MaxAngles];
+__constant__ float gC_RayY[g_MaxAngles];
+__constant__ float gC_RayZ[g_MaxAngles];
+__constant__ float gC_DetSX[g_MaxAngles];
+__constant__ float gC_DetSY[g_MaxAngles];
+__constant__ float gC_DetSZ[g_MaxAngles];
+__constant__ float gC_DetUX[g_MaxAngles];
+__constant__ float gC_DetUY[g_MaxAngles];
+__constant__ float gC_DetUZ[g_MaxAngles];
+__constant__ float gC_DetVX[g_MaxAngles];
+__constant__ float gC_DetVY[g_MaxAngles];
+__constant__ float gC_DetVZ[g_MaxAngles];
+
+
+static bool bindVolumeDataTexture(const cudaArray* array)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+
+ gT_par3DVolumeTexture.addressMode[0] = cudaAddressModeClamp;
+ gT_par3DVolumeTexture.addressMode[1] = cudaAddressModeClamp;
+ gT_par3DVolumeTexture.addressMode[2] = cudaAddressModeClamp;
+ gT_par3DVolumeTexture.filterMode = cudaFilterModeLinear;
+ gT_par3DVolumeTexture.normalized = false;
+
+ cudaBindTextureToArray(gT_par3DVolumeTexture, array, channelDesc);
+
+ // TODO: error value?
+
+ return true;
+}
+
+
+
+// threadIdx: x = u detector
+// y = relative angle
+// blockIdx: x = u/v detector
+// y = angle block
+
+#define PAR3D_FP_BODY(c0,c1,c2) \
+ int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \
+ if (angle >= endAngle) \
+ return; \
+ \
+ const float fRayX = gC_RayX[angle]; \
+ const float fRayY = gC_RayY[angle]; \
+ const float fRayZ = gC_RayZ[angle]; \
+ const float fDetUX = gC_DetUX[angle]; \
+ const float fDetUY = gC_DetUY[angle]; \
+ const float fDetUZ = gC_DetUZ[angle]; \
+ const float fDetVX = gC_DetVX[angle]; \
+ const float fDetVY = gC_DetVY[angle]; \
+ const float fDetVZ = gC_DetVZ[angle]; \
+ const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \
+ const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \
+ const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \
+ \
+ \
+ \
+ const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \
+ const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \
+ int endDetectorV = startDetectorV + g_detBlockV; \
+ if (endDetectorV > dims.iProjV) \
+ endDetectorV = dims.iProjV; \
+ \
+ int endSlice = startSlice + g_blockSlices; \
+ if (endSlice > dims.iVol##c0) \
+ endSlice = dims.iVol##c0; \
+ \
+ for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \
+ { \
+ /* Trace ray in direction Ray to (detectorU,detectorV) from */ \
+ /* X = startSlice to X = endSlice */ \
+ \
+ const float fDetX = fDetSX + detectorU*fDetUX + detectorV*fDetVX; \
+ const float fDetY = fDetSY + detectorU*fDetUY + detectorV*fDetVY; \
+ const float fDetZ = fDetSZ + detectorU*fDetUZ + detectorV*fDetVZ; \
+ \
+ /* (x) ( 1) ( 0) */ \
+ /* ray: (y) = (ay) * x + (by) */ \
+ /* (z) (az) (bz) */ \
+ \
+ const float a##c1 = fRay##c1 / fRay##c0; \
+ const float a##c2 = fRay##c2 / fRay##c0; \
+ const float b##c1 = fDet##c1 - a##c1 * fDet##c0; \
+ const float b##c2 = fDet##c2 - a##c2 * fDet##c0; \
+ \
+ const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \
+ \
+ float fVal = 0.0f; \
+ \
+ float f##c0 = startSlice + 1.5f; \
+ float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f;\
+ float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f;\
+ \
+ for (int s = startSlice; s < endSlice; ++s) \
+ { \
+ fVal += tex3D(gT_par3DVolumeTexture, fX, fY, fZ); \
+ f##c0 += 1.0f; \
+ f##c1 += a##c1; \
+ f##c2 += a##c2; \
+ } \
+ \
+ fVal *= fDistCorr; \
+ \
+ D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fVal; \
+ }
+
+
+
+// Supersampling version
+#define PAR3D_FP_SS_BODY(c0,c1,c2) \
+ int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \
+ if (angle >= endAngle) \
+ return; \
+ \
+ const float fRayX = gC_RayX[angle]; \
+ const float fRayY = gC_RayY[angle]; \
+ const float fRayZ = gC_RayZ[angle]; \
+ const float fDetUX = gC_DetUX[angle]; \
+ const float fDetUY = gC_DetUY[angle]; \
+ const float fDetUZ = gC_DetUZ[angle]; \
+ const float fDetVX = gC_DetVX[angle]; \
+ const float fDetVY = gC_DetVY[angle]; \
+ const float fDetVZ = gC_DetVZ[angle]; \
+ const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \
+ const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \
+ const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \
+ \
+ \
+ \
+ const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \
+ const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \
+ int endDetectorV = startDetectorV + g_detBlockV; \
+ if (endDetectorV > dims.iProjV) \
+ endDetectorV = dims.iProjV; \
+ \
+ int endSlice = startSlice + g_blockSlices; \
+ if (endSlice > dims.iVol##c0) \
+ endSlice = dims.iVol##c0; \
+ \
+ const float fSubStep = 1.0f/dims.iRaysPerDetDim; \
+ \
+ for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \
+ { \
+ \
+ float fV = 0.0f; \
+ \
+ float fdU = detectorU - 0.5f + 0.5f*fSubStep; \
+ for (int iSubU = 0; iSubU < dims.iRaysPerDetDim; ++iSubU, fdU+=fSubStep) { \
+ float fdV = detectorV - 0.5f + 0.5f*fSubStep; \
+ for (int iSubV = 0; iSubV < dims.iRaysPerDetDim; ++iSubV, fdV+=fSubStep) { \
+ \
+ /* Trace ray in direction Ray to (detectorU,detectorV) from */ \
+ /* X = startSlice to X = endSlice */ \
+ \
+ const float fDetX = fDetSX + fdU*fDetUX + fdV*fDetVX; \
+ const float fDetY = fDetSY + fdU*fDetUY + fdV*fDetVY; \
+ const float fDetZ = fDetSZ + fdU*fDetUZ + fdV*fDetVZ; \
+ \
+ /* (x) ( 1) ( 0) */ \
+ /* ray: (y) = (ay) * x + (by) */ \
+ /* (z) (az) (bz) */ \
+ \
+ const float a##c1 = fRay##c1 / fRay##c0; \
+ const float a##c2 = fRay##c2 / fRay##c0; \
+ const float b##c1 = fDet##c1 - a##c1 * fDet##c0; \
+ const float b##c2 = fDet##c2 - a##c2 * fDet##c0; \
+ \
+ const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \
+ \
+ float fVal = 0.0f; \
+ \
+ float f##c0 = startSlice + 1.5f; \
+ float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f;\
+ float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f;\
+ \
+ for (int s = startSlice; s < endSlice; ++s) \
+ { \
+ fVal += tex3D(gT_par3DVolumeTexture, fX, fY, fZ); \
+ f##c0 += 1.0f; \
+ f##c1 += a##c1; \
+ f##c2 += a##c2; \
+ } \
+ \
+ fVal *= fDistCorr; \
+ fV += fVal; \
+ \
+ } \
+ } \
+ \
+ D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fV / (dims.iRaysPerDetDim * dims.iRaysPerDetDim);\
+ }
+
+
+
+__global__ void par3D_FP_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_BODY(X,Y,Z)
+}
+
+__global__ void par3D_FP_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_BODY(Y,X,Z)
+}
+
+__global__ void par3D_FP_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_BODY(Z,X,Y)
+}
+
+__global__ void par3D_FP_SS_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_SS_BODY(X,Y,Z)
+}
+
+__global__ void par3D_FP_SS_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_SS_BODY(Y,X,Z)
+}
+
+__global__ void par3D_FP_SS_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_SS_BODY(Z,X,Y)
+}
+
+
+__device__ float dirWeights(float fX, float fN) {
+ if (fX <= 0.5f) // outside image on left
+ return 0.0f;
+ if (fX <= 1.5f) // half outside image on left
+ return (fX - 0.5f) * (fX - 0.5f);
+ if (fX <= fN + 0.5f) { // inside image
+ float t = fX - 0.5f - floorf(fX - 0.5f);
+ return t*t + (1-t)*(1-t);
+ }
+ if (fX <= fN + 1.5f) // half outside image on right
+ return (fN + 1.5f - fX) * (fN + 1.5f - fX);
+ return 0.0f; // outside image on right
+}
+
+#define PAR3D_FP_SUMSQW_BODY(c0,c1,c2) \
+ int angle = startAngle + blockIdx.y * g_anglesPerBlock + threadIdx.y; \
+ if (angle >= endAngle) \
+ return; \
+ \
+ const float fRayX = gC_RayX[angle]; \
+ const float fRayY = gC_RayY[angle]; \
+ const float fRayZ = gC_RayZ[angle]; \
+ const float fDetUX = gC_DetUX[angle]; \
+ const float fDetUY = gC_DetUY[angle]; \
+ const float fDetUZ = gC_DetUZ[angle]; \
+ const float fDetVX = gC_DetVX[angle]; \
+ const float fDetVY = gC_DetVY[angle]; \
+ const float fDetVZ = gC_DetVZ[angle]; \
+ const float fDetSX = gC_DetSX[angle] + 0.5f * fDetUX + 0.5f * fDetVX; \
+ const float fDetSY = gC_DetSY[angle] + 0.5f * fDetUY + 0.5f * fDetVY; \
+ const float fDetSZ = gC_DetSZ[angle] + 0.5f * fDetUZ + 0.5f * fDetVZ; \
+ \
+ \
+ \
+ const int detectorU = (blockIdx.x%((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockU + threadIdx.x; \
+ const int startDetectorV = (blockIdx.x/((dims.iProjU+g_detBlockU-1)/g_detBlockU)) * g_detBlockV; \
+ int endDetectorV = startDetectorV + g_detBlockV; \
+ if (endDetectorV > dims.iProjV) \
+ endDetectorV = dims.iProjV; \
+ \
+ int endSlice = startSlice + g_blockSlices; \
+ if (endSlice > dims.iVol##c0) \
+ endSlice = dims.iVol##c0; \
+ \
+ for (int detectorV = startDetectorV; detectorV < endDetectorV; ++detectorV) \
+ { \
+ /* Trace ray in direction Ray to (detectorU,detectorV) from */ \
+ /* X = startSlice to X = endSlice */ \
+ \
+ const float fDetX = fDetSX + detectorU*fDetUX + detectorV*fDetVX; \
+ const float fDetY = fDetSY + detectorU*fDetUY + detectorV*fDetVY; \
+ const float fDetZ = fDetSZ + detectorU*fDetUZ + detectorV*fDetVZ; \
+ \
+ /* (x) ( 1) ( 0) */ \
+ /* ray: (y) = (ay) * x + (by) */ \
+ /* (z) (az) (bz) */ \
+ \
+ const float a##c1 = fRay##c1 / fRay##c0; \
+ const float a##c2 = fRay##c2 / fRay##c0; \
+ const float b##c1 = fDet##c1 - a##c1 * fDet##c0; \
+ const float b##c2 = fDet##c2 - a##c2 * fDet##c0; \
+ \
+ const float fDistCorr = sqrt(a##c1*a##c1+a##c2*a##c2+1.0f) * fOutputScale; \
+ \
+ float fVal = 0.0f; \
+ \
+ float f##c0 = startSlice + 1.5f; \
+ float f##c1 = a##c1 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c1 + 0.5f*dims.iVol##c1 - 0.5f + 1.5f;\
+ float f##c2 = a##c2 * (startSlice - 0.5f*dims.iVol##c0 + 0.5f) + b##c2 + 0.5f*dims.iVol##c2 - 0.5f + 1.5f;\
+ \
+ for (int s = startSlice; s < endSlice; ++s) \
+ { \
+ fVal += dirWeights(f##c1, dims.iVol##c1) * dirWeights(f##c2, dims.iVol##c2) * fDistCorr * fDistCorr; \
+ f##c0 += 1.0f; \
+ f##c1 += a##c1; \
+ f##c2 += a##c2; \
+ } \
+ \
+ D_projData[(detectorV*dims.iProjAngles+angle)*projPitch+detectorU] += fVal; \
+ }
+
+// Supersampling version
+// TODO
+
+
+__global__ void par3D_FP_SumSqW_dirX(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_SUMSQW_BODY(X,Y,Z)
+}
+
+__global__ void par3D_FP_SumSqW_dirY(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_SUMSQW_BODY(Y,X,Z)
+}
+
+__global__ void par3D_FP_SumSqW_dirZ(float* D_projData, unsigned int projPitch, unsigned int startSlice, unsigned int startAngle, unsigned int endAngle, const SDimensions3D dims, float fOutputScale)
+{
+PAR3D_FP_SUMSQW_BODY(Z,X,Y)
+}
+
+
+
+bool Par3DFP_Array(cudaArray *D_volArray,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SPar3DProjection* angles,
+ float fOutputScale)
+{
+
+ bindVolumeDataTexture(D_volArray);
+
+
+ // transfer angles to constant memory
+ float* tmp = new float[dims.iProjAngles];
+
+#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
+
+ TRANSFER_TO_CONSTANT(RayX);
+ TRANSFER_TO_CONSTANT(RayY);
+ TRANSFER_TO_CONSTANT(RayZ);
+ TRANSFER_TO_CONSTANT(DetSX);
+ TRANSFER_TO_CONSTANT(DetSY);
+ TRANSFER_TO_CONSTANT(DetSZ);
+ TRANSFER_TO_CONSTANT(DetUX);
+ TRANSFER_TO_CONSTANT(DetUY);
+ TRANSFER_TO_CONSTANT(DetUZ);
+ TRANSFER_TO_CONSTANT(DetVX);
+ TRANSFER_TO_CONSTANT(DetVY);
+ TRANSFER_TO_CONSTANT(DetVZ);
+
+#undef TRANSFER_TO_CONSTANT
+
+ delete[] tmp;
+
+ std::list<cudaStream_t> streams;
+ dim3 dimBlock(g_detBlockU, g_anglesPerBlock); // region size, angles
+
+ // Run over all angles, grouping them into groups of the same
+ // orientation (roughly horizontal vs. roughly vertical).
+ // Start a stream of grids for each such group.
+
+ unsigned int blockStart = 0;
+ unsigned int blockEnd = 0;
+ int blockDirection = 0;
+
+ // timeval t;
+ // tic(t);
+
+ for (unsigned int a = 0; a <= dims.iProjAngles; ++a) {
+ int dir;
+ if (a != dims.iProjAngles) {
+ float dX = fabsf(angles[a].fRayX);
+ float dY = fabsf(angles[a].fRayY);
+ float dZ = fabsf(angles[a].fRayZ);
+
+ if (dX >= dY && dX >= dZ)
+ dir = 0;
+ else if (dY >= dX && dY >= dZ)
+ dir = 1;
+ else
+ dir = 2;
+ }
+
+ if (a == dims.iProjAngles || dir != blockDirection) {
+ // block done
+
+ blockEnd = a;
+ if (blockStart != blockEnd) {
+
+ dim3 dimGrid(
+ ((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV),
+(blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock);
+ // TODO: check if we can't immediately
+ // destroy the stream after use
+ cudaStream_t stream;
+ cudaStreamCreate(&stream);
+ streams.push_back(stream);
+
+ // printf("angle block: %d to %d, %d (%dx%d, %dx%d)\n", blockStart, blockEnd, blockDirection, dimGrid.x, dimGrid.y, dimBlock.x, dimBlock.y);
+
+ if (blockDirection == 0) {
+ for (unsigned int i = 0; i < dims.iVolX; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ par3D_FP_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+ par3D_FP_SS_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ } else if (blockDirection == 1) {
+ for (unsigned int i = 0; i < dims.iVolY; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ par3D_FP_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+ par3D_FP_SS_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ } else if (blockDirection == 2) {
+ for (unsigned int i = 0; i < dims.iVolZ; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ par3D_FP_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+ par3D_FP_SS_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ }
+
+ }
+
+ blockDirection = dir;
+ blockStart = a;
+ }
+ }
+
+ for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter)
+ cudaStreamDestroy(*iter);
+
+ streams.clear();
+
+ cudaTextForceKernelsCompletion();
+
+
+ // printf("%f\n", toc(t));
+
+ return true;
+}
+
+bool Par3DFP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SPar3DProjection* angles,
+ float fOutputScale)
+{
+ // transfer volume to array
+ cudaArray* cuArray = allocateVolumeArray(dims);
+ transferVolumeToArray(D_volumeData, cuArray, dims);
+
+ bool ret = Par3DFP_Array(cuArray, D_projData, dims, angles, fOutputScale);
+
+ cudaFreeArray(cuArray);
+
+ return ret;
+}
+
+
+
+bool Par3DFP_SumSqW(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SPar3DProjection* angles,
+ float fOutputScale)
+{
+ // transfer angles to constant memory
+ float* tmp = new float[dims.iProjAngles];
+
+#define TRANSFER_TO_CONSTANT(name) do { for (unsigned int i = 0; i < dims.iProjAngles; ++i) tmp[i] = angles[i].f##name ; cudaMemcpyToSymbol(gC_##name, tmp, dims.iProjAngles*sizeof(float), 0, cudaMemcpyHostToDevice); } while (0)
+
+ TRANSFER_TO_CONSTANT(RayX);
+ TRANSFER_TO_CONSTANT(RayY);
+ TRANSFER_TO_CONSTANT(RayZ);
+ TRANSFER_TO_CONSTANT(DetSX);
+ TRANSFER_TO_CONSTANT(DetSY);
+ TRANSFER_TO_CONSTANT(DetSZ);
+ TRANSFER_TO_CONSTANT(DetUX);
+ TRANSFER_TO_CONSTANT(DetUY);
+ TRANSFER_TO_CONSTANT(DetUZ);
+ TRANSFER_TO_CONSTANT(DetVX);
+ TRANSFER_TO_CONSTANT(DetVY);
+ TRANSFER_TO_CONSTANT(DetVZ);
+
+#undef TRANSFER_TO_CONSTANT
+
+ delete[] tmp;
+
+ std::list<cudaStream_t> streams;
+ dim3 dimBlock(g_detBlockU, g_anglesPerBlock); // region size, angles
+
+ // Run over all angles, grouping them into groups of the same
+ // orientation (roughly horizontal vs. roughly vertical).
+ // Start a stream of grids for each such group.
+
+ unsigned int blockStart = 0;
+ unsigned int blockEnd = 0;
+ int blockDirection = 0;
+
+ // timeval t;
+ // tic(t);
+
+ for (unsigned int a = 0; a <= dims.iProjAngles; ++a) {
+ int dir;
+ if (a != dims.iProjAngles) {
+ float dX = fabsf(angles[a].fRayX);
+ float dY = fabsf(angles[a].fRayY);
+ float dZ = fabsf(angles[a].fRayZ);
+
+ if (dX >= dY && dX >= dZ)
+ dir = 0;
+ else if (dY >= dX && dY >= dZ)
+ dir = 1;
+ else
+ dir = 2;
+ }
+
+ if (a == dims.iProjAngles || dir != blockDirection) {
+ // block done
+
+ blockEnd = a;
+ if (blockStart != blockEnd) {
+
+ dim3 dimGrid(
+ ((dims.iProjU+g_detBlockU-1)/g_detBlockU)*((dims.iProjV+g_detBlockV-1)/g_detBlockV),
+(blockEnd-blockStart+g_anglesPerBlock-1)/g_anglesPerBlock);
+ // TODO: check if we can't immediately
+ // destroy the stream after use
+ cudaStream_t stream;
+ cudaStreamCreate(&stream);
+ streams.push_back(stream);
+
+ // printf("angle block: %d to %d, %d (%dx%d, %dx%d)\n", blockStart, blockEnd, blockDirection, dimGrid.x, dimGrid.y, dimBlock.x, dimBlock.y);
+
+ if (blockDirection == 0) {
+ for (unsigned int i = 0; i < dims.iVolX; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ par3D_FP_SumSqW_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+#if 0
+ par3D_FP_SS_SumSqW_dirX<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+#else
+ assert(false);
+#endif
+ } else if (blockDirection == 1) {
+ for (unsigned int i = 0; i < dims.iVolY; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ par3D_FP_SumSqW_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+#if 0
+ par3D_FP_SS_SumSqW_dirY<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+#else
+ assert(false);
+#endif
+ } else if (blockDirection == 2) {
+ for (unsigned int i = 0; i < dims.iVolZ; i += g_blockSlices)
+ if (dims.iRaysPerDetDim == 1)
+ par3D_FP_SumSqW_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+ else
+#if 0
+ par3D_FP_SS_SumSqW_dirZ<<<dimGrid, dimBlock, 0, stream>>>((float*)D_projData.ptr, D_projData.pitch/sizeof(float), i, blockStart, blockEnd, dims, fOutputScale);
+#else
+ assert(false);
+#endif
+ }
+
+ }
+
+ blockDirection = dir;
+ blockStart = a;
+ }
+ }
+
+ for (std::list<cudaStream_t>::iterator iter = streams.begin(); iter != streams.end(); ++iter)
+ cudaStreamDestroy(*iter);
+
+ streams.clear();
+
+ cudaTextForceKernelsCompletion();
+
+
+ // printf("%f\n", toc(t));
+
+ return true;
+}
+
+
+
+
+
+
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA3d;
+
+int main()
+{
+ cudaSetDevice(1);
+
+
+ SDimensions3D dims;
+ dims.iVolX = 500;
+ dims.iVolY = 500;
+ dims.iVolZ = 81;
+ dims.iProjAngles = 241;
+ dims.iProjU = 600;
+ dims.iProjV = 100;
+ dims.iRaysPerDet = 1;
+
+ SPar3DProjection base;
+ base.fRayX = 1.0f;
+ base.fRayY = 0.0f;
+ base.fRayZ = 0.1f;
+
+ base.fDetSX = 0.0f;
+ base.fDetSY = -300.0f;
+ base.fDetSZ = -50.0f;
+
+ base.fDetUX = 0.0f;
+ base.fDetUY = 1.0f;
+ base.fDetUZ = 0.0f;
+
+ base.fDetVX = 0.0f;
+ base.fDetVY = 0.0f;
+ base.fDetVZ = 1.0f;
+
+ SPar3DProjection angle[dims.iProjAngles];
+
+ cudaPitchedPtr volData; // pitch, ptr, xsize, ysize
+
+ volData = allocateVolumeData(dims);
+
+ cudaPitchedPtr projData; // pitch, ptr, xsize, ysize
+
+ projData = allocateProjectionData(dims);
+
+ unsigned int ix = 500,iy = 500;
+
+ float* buf = new float[dims.iProjU*dims.iProjV];
+
+ float* slice = new float[dims.iVolX*dims.iVolY];
+ for (int i = 0; i < dims.iVolX*dims.iVolY; ++i)
+ slice[i] = 1.0f;
+
+ for (unsigned int a = 0; a < 241; a += dims.iProjAngles) {
+
+ zeroProjectionData(projData, dims);
+
+ for (int y = 0; y < iy; y += dims.iVolY) {
+ for (int x = 0; x < ix; x += dims.iVolX) {
+
+ timeval st;
+ tic(st);
+
+ for (int z = 0; z < dims.iVolZ; ++z) {
+// char sfn[256];
+// sprintf(sfn, "/home/wpalenst/projects/cone_simulation/phantom_4096/mouse_fem_phantom_%04d.png", 30+z);
+// float* slice = loadSubImage(sfn, x, y, dims.iVolX, dims.iVolY);
+
+ cudaPitchedPtr ptr;
+ ptr.ptr = slice;
+ ptr.pitch = dims.iVolX*sizeof(float);
+ ptr.xsize = dims.iVolX*sizeof(float);
+ ptr.ysize = dims.iVolY;
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, z };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaError err = cudaMemcpy3D(&p);
+ assert(!err);
+// delete[] slice;
+ }
+
+ printf("Load: %f\n", toc(st));
+
+#if 0
+
+ cudaPos zp = { 0, 0, 0 };
+
+ cudaPitchedPtr t;
+ t.ptr = new float[1024*1024];
+ t.pitch = 1024*4;
+ t.xsize = 1024*4;
+ t.ysize = 1024;
+
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = volData;
+ p.extent = extentS;
+ p.dstArray = 0;
+ p.dstPtr = t;
+ p.dstPos = zp;
+ p.kind = cudaMemcpyDeviceToHost;
+ cudaError err = cudaMemcpy3D(&p);
+ assert(!err);
+
+ char fn[32];
+ sprintf(fn, "t%d%d.png", x / dims.iVolX, y / dims.iVolY);
+ saveImage(fn, 1024, 1024, (float*)t.ptr);
+ saveImage("s.png", 4096, 4096, slice);
+ delete[] (float*)t.ptr;
+#endif
+
+
+#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = base.f##name##X * cos(alpha) - base.f##name##Y * sin(alpha); angle[i].f##name##Y = base.f##name##X * sin(alpha) + base.f##name##Y * cos(alpha); angle[i].f##name##Z = base.f##name##Z; } while(0)
+#define SHIFT(name,i,x,y) do { angle[i].f##name##X += x; angle[i].f##name##Y += y; } while(0)
+ for (int i = 0; i < dims.iProjAngles; ++i) {
+ ROTATE0(Ray, i, (a+i)*.8*M_PI/180);
+ ROTATE0(DetS, i, (a+i)*.8*M_PI/180);
+ ROTATE0(DetU, i, (a+i)*.8*M_PI/180);
+ ROTATE0(DetV, i, (a+i)*.8*M_PI/180);
+
+
+// SHIFT(Src, i, (-x+1536), (-y+1536));
+// SHIFT(DetS, i, (-x+1536), (-y+1536));
+ }
+#undef ROTATE0
+#undef SHIFT
+ tic(st);
+
+ astraCUDA3d::Par3DFP(volData, projData, dims, angle, 1.0f);
+
+ printf("FP: %f\n", toc(st));
+
+ }
+ }
+ for (unsigned int aa = 0; aa < dims.iProjAngles; ++aa) {
+ for (unsigned int v = 0; v < dims.iProjV; ++v)
+ cudaMemcpy(buf+v*dims.iProjU, ((float*)projData.ptr)+(v*dims.iProjAngles+aa)*(projData.pitch/sizeof(float)), dims.iProjU*sizeof(float), cudaMemcpyDeviceToHost);
+
+ char fname[32];
+ sprintf(fname, "proj%03d.png", a+aa);
+ saveImage(fname, dims.iProjV, dims.iProjU, buf, 0.0f, 1000.0f);
+ }
+ }
+
+ delete[] buf;
+
+}
+#endif
diff --git a/cuda/3d/par3d_fp.h b/cuda/3d/par3d_fp.h
new file mode 100644
index 0000000..7208361
--- /dev/null
+++ b/cuda/3d/par3d_fp.h
@@ -0,0 +1,51 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_PAR3D_FP_H
+#define _CUDA_PAR3D_FP_H
+
+namespace astraCUDA3d {
+
+_AstraExport bool Par3DFP_Array(cudaArray *D_volArray,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SPar3DProjection* angles,
+ float fOutputScale);
+
+_AstraExport bool Par3DFP(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SPar3DProjection* angles,
+ float fOutputScale);
+
+_AstraExport bool Par3DFP_SumSqW(cudaPitchedPtr D_volumeData,
+ cudaPitchedPtr D_projData,
+ const SDimensions3D& dims, const SPar3DProjection* angles,
+ float fOutputScale);
+
+}
+
+#endif
diff --git a/cuda/3d/sirt3d.cu b/cuda/3d/sirt3d.cu
new file mode 100644
index 0000000..f615204
--- /dev/null
+++ b/cuda/3d/sirt3d.cu
@@ -0,0 +1,533 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+
+#include "sirt3d.h"
+#include "util3d.h"
+#include "arith3d.h"
+#include "cone_fp.h"
+
+#ifdef STANDALONE
+#include "testutil.h"
+#endif
+
+namespace astraCUDA3d {
+
+SIRT::SIRT() : ReconAlgo3D()
+{
+ D_maskData.ptr = 0;
+ D_smaskData.ptr = 0;
+
+ D_sinoData.ptr = 0;
+ D_volumeData.ptr = 0;
+
+ D_projData.ptr = 0;
+ D_tmpData.ptr = 0;
+
+ D_lineWeight.ptr = 0;
+ D_pixelWeight.ptr = 0;
+
+ useVolumeMask = false;
+ useSinogramMask = false;
+
+ useMinConstraint = false;
+ useMaxConstraint = false;
+}
+
+
+SIRT::~SIRT()
+{
+ reset();
+}
+
+void SIRT::reset()
+{
+ cudaFree(D_projData.ptr);
+ cudaFree(D_tmpData.ptr);
+ cudaFree(D_lineWeight.ptr);
+ cudaFree(D_pixelWeight.ptr);
+
+ D_maskData.ptr = 0;
+ D_smaskData.ptr = 0;
+
+ D_sinoData.ptr = 0;
+ D_volumeData.ptr = 0;
+
+ D_projData.ptr = 0;
+ D_tmpData.ptr = 0;
+
+ D_lineWeight.ptr = 0;
+ D_pixelWeight.ptr = 0;
+
+ useVolumeMask = false;
+ useSinogramMask = false;
+
+ ReconAlgo3D::reset();
+}
+
+bool SIRT::enableVolumeMask()
+{
+ useVolumeMask = true;
+ return true;
+}
+
+bool SIRT::enableSinogramMask()
+{
+ useSinogramMask = true;
+ return true;
+}
+
+
+bool SIRT::init()
+{
+ D_pixelWeight = allocateVolumeData(dims);
+ zeroVolumeData(D_pixelWeight, dims);
+
+ D_tmpData = allocateVolumeData(dims);
+ zeroVolumeData(D_tmpData, dims);
+
+ D_projData = allocateProjectionData(dims);
+ zeroProjectionData(D_projData, dims);
+
+ D_lineWeight = allocateProjectionData(dims);
+ zeroProjectionData(D_lineWeight, dims);
+
+ // We can't precompute lineWeights and pixelWeights when using a mask
+ if (!useVolumeMask && !useSinogramMask)
+ precomputeWeights();
+
+ // TODO: check if allocations succeeded
+ return true;
+}
+
+bool SIRT::setMinConstraint(float fMin)
+{
+ fMinConstraint = fMin;
+ useMinConstraint = true;
+ return true;
+}
+
+bool SIRT::setMaxConstraint(float fMax)
+{
+ fMaxConstraint = fMax;
+ useMaxConstraint = true;
+ return true;
+}
+
+bool SIRT::precomputeWeights()
+{
+ zeroProjectionData(D_lineWeight, dims);
+ if (useVolumeMask) {
+ callFP(D_maskData, D_lineWeight, 1.0f);
+ } else {
+ processVol3D<opSet>(D_tmpData, 1.0f, dims);
+ callFP(D_tmpData, D_lineWeight, 1.0f);
+ }
+ processSino3D<opInvert>(D_lineWeight, dims);
+
+ if (useSinogramMask) {
+ // scale line weights with sinogram mask to zero out masked sinogram pixels
+ processSino3D<opMul>(D_lineWeight, D_smaskData, dims);
+ }
+
+ zeroVolumeData(D_pixelWeight, dims);
+
+ if (useSinogramMask) {
+ callBP(D_pixelWeight, D_smaskData);
+ } else {
+ processSino3D<opSet>(D_projData, 1.0f, dims);
+ callBP(D_pixelWeight, D_projData);
+ }
+#if 0
+ float* bufp = new float[512*512];
+
+ for (int i = 0; i < 180; ++i) {
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(bufp+512*j, ((float*)D_projData.ptr)+180*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost);
+ }
+
+ char fname[20];
+ sprintf(fname, "ray%03d.png", i);
+ saveImage(fname, 512, 512, bufp);
+ }
+#endif
+
+#if 0
+ float* buf = new float[256*256];
+
+ for (int i = 0; i < 256; ++i) {
+ cudaMemcpy(buf, ((float*)D_pixelWeight.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost);
+
+ char fname[20];
+ sprintf(fname, "pix%03d.png", i);
+ saveImage(fname, 256, 256, buf);
+ }
+#endif
+ processVol3D<opInvert>(D_pixelWeight, dims);
+
+ if (useVolumeMask) {
+ // scale pixel weights with mask to zero out masked pixels
+ processVol3D<opMul>(D_pixelWeight, D_maskData, dims);
+ }
+
+ return true;
+}
+
+
+bool SIRT::setVolumeMask(cudaPitchedPtr& _D_maskData)
+{
+ assert(useVolumeMask);
+
+ D_maskData = _D_maskData;
+
+ return true;
+}
+
+bool SIRT::setSinogramMask(cudaPitchedPtr& _D_smaskData)
+{
+ assert(useSinogramMask);
+
+ D_smaskData = _D_smaskData;
+
+ return true;
+}
+
+bool SIRT::setBuffers(cudaPitchedPtr& _D_volumeData,
+ cudaPitchedPtr& _D_projData)
+{
+ D_volumeData = _D_volumeData;
+ D_sinoData = _D_projData;
+
+ fprintf(stderr, "Reconstruction buffer: %p\n", (void*)D_volumeData.ptr);
+
+ return true;
+}
+
+bool SIRT::iterate(unsigned int iterations)
+{
+ shouldAbort = false;
+
+ if (useVolumeMask || useSinogramMask)
+ precomputeWeights();
+
+#if 0
+ float* buf = new float[256*256];
+
+ for (int i = 0; i < 256; ++i) {
+ cudaMemcpy(buf, ((float*)D_pixelWeight.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost);
+
+ char fname[20];
+ sprintf(fname, "pix%03d.png", i);
+ saveImage(fname, 256, 256, buf);
+ }
+#endif
+#if 0
+ float* bufp = new float[512*512];
+
+ for (int i = 0; i < 100; ++i) {
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(bufp+512*j, ((float*)D_lineWeight.ptr)+100*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost);
+ }
+
+ char fname[20];
+ sprintf(fname, "ray%03d.png", i);
+ saveImage(fname, 512, 512, bufp);
+ }
+#endif
+
+
+ // iteration
+ for (unsigned int iter = 0; iter < iterations && !shouldAbort; ++iter) {
+ // copy sinogram to projection data
+ duplicateProjectionData(D_projData, D_sinoData, dims);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ duplicateVolumeData(D_tmpData, D_volumeData, dims);
+ processVol3D<opMul>(D_tmpData, D_maskData, dims);
+ callFP(D_tmpData, D_projData, -1.0f);
+ } else {
+ callFP(D_volumeData, D_projData, -1.0f);
+ }
+
+ processSino3D<opMul>(D_projData, D_lineWeight, dims);
+
+ zeroVolumeData(D_tmpData, dims);
+#if 0
+ float* bufp = new float[512*512];
+ printf("Dumping projData: %p\n", (void*)D_projData.ptr);
+ for (int i = 0; i < 180; ++i) {
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(bufp+512*j, ((float*)D_projData.ptr)+180*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost);
+ }
+
+ char fname[20];
+ sprintf(fname, "diff%03d.png", i);
+ saveImage(fname, 512, 512, bufp);
+ }
+#endif
+
+
+ callBP(D_tmpData, D_projData);
+#if 0
+ printf("Dumping tmpData: %p\n", (void*)D_tmpData.ptr);
+ float* buf = new float[256*256];
+
+ for (int i = 0; i < 256; ++i) {
+ cudaMemcpy(buf, ((float*)D_tmpData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost);
+
+ char fname[20];
+ sprintf(fname, "add%03d.png", i);
+ saveImage(fname, 256, 256, buf);
+ }
+#endif
+
+
+ processVol3D<opAddMul>(D_volumeData, D_tmpData, D_pixelWeight, dims);
+
+ if (useMinConstraint)
+ processVol3D<opClampMin>(D_volumeData, fMinConstraint, dims);
+ if (useMaxConstraint)
+ processVol3D<opClampMax>(D_volumeData, fMaxConstraint, dims);
+ }
+
+ return true;
+}
+
+float SIRT::computeDiffNorm()
+{
+ // copy sinogram to projection data
+ duplicateProjectionData(D_projData, D_sinoData, dims);
+
+ // do FP, subtracting projection from sinogram
+ if (useVolumeMask) {
+ duplicateVolumeData(D_tmpData, D_volumeData, dims);
+ processVol3D<opMul>(D_tmpData, D_maskData, dims);
+ callFP(D_tmpData, D_projData, -1.0f);
+ } else {
+ callFP(D_volumeData, D_projData, -1.0f);
+ }
+
+ float s = dotProduct3D(D_projData, dims.iProjU, dims.iProjAngles, dims.iProjV);
+ return sqrt(s);
+}
+
+
+bool doSIRT(cudaPitchedPtr& D_volumeData,
+ cudaPitchedPtr& D_sinoData,
+ cudaPitchedPtr& D_maskData,
+ const SDimensions3D& dims, const SConeProjection* angles,
+ unsigned int iterations)
+{
+ SIRT sirt;
+ bool ok = true;
+
+ ok &= sirt.setConeGeometry(dims, angles);
+ if (D_maskData.ptr)
+ ok &= sirt.enableVolumeMask();
+
+ if (!ok)
+ return false;
+
+ ok = sirt.init();
+ if (!ok)
+ return false;
+
+ if (D_maskData.ptr)
+ ok &= sirt.setVolumeMask(D_maskData);
+
+ ok &= sirt.setBuffers(D_volumeData, D_sinoData);
+ if (!ok)
+ return false;
+
+ ok = sirt.iterate(iterations);
+
+ return ok;
+}
+
+}
+
+#ifdef STANDALONE
+
+using namespace astraCUDA3d;
+
+int main()
+{
+ SDimensions3D dims;
+ dims.iVolX = 256;
+ dims.iVolY = 256;
+ dims.iVolZ = 256;
+ dims.iProjAngles = 100;
+ dims.iProjU = 512;
+ dims.iProjV = 512;
+ dims.iRaysPerDet = 1;
+
+ SConeProjection angle[100];
+ angle[0].fSrcX = -2905.6;
+ angle[0].fSrcY = 0;
+ angle[0].fSrcZ = 0;
+
+ angle[0].fDetSX = 694.4;
+ angle[0].fDetSY = -122.4704;
+ angle[0].fDetSZ = -122.4704;
+
+ angle[0].fDetUX = 0;
+ angle[0].fDetUY = .4784;
+ //angle[0].fDetUY = .5;
+ angle[0].fDetUZ = 0;
+
+ angle[0].fDetVX = 0;
+ angle[0].fDetVY = 0;
+ angle[0].fDetVZ = .4784;
+
+#define ROTATE0(name,i,alpha) do { angle[i].f##name##X = angle[0].f##name##X * cos(alpha) - angle[0].f##name##Y * sin(alpha); angle[i].f##name##Y = angle[0].f##name##X * sin(alpha) + angle[0].f##name##Y * cos(alpha); } while(0)
+ for (int i = 1; i < 100; ++i) {
+ angle[i] = angle[0];
+ ROTATE0(Src, i, i*2*M_PI/100);
+ ROTATE0(DetS, i, i*2*M_PI/100);
+ ROTATE0(DetU, i, i*2*M_PI/100);
+ ROTATE0(DetV, i, i*2*M_PI/100);
+ }
+#undef ROTATE0
+
+
+ cudaPitchedPtr volData = allocateVolumeData(dims);
+ cudaPitchedPtr projData = allocateProjectionData(dims);
+ zeroProjectionData(projData, dims);
+
+ float* pbuf = new float[100*512*512];
+ copyProjectionsFromDevice(pbuf, projData, dims);
+ copyProjectionsToDevice(pbuf, projData, dims);
+ delete[] pbuf;
+
+#if 0
+ float* slice = new float[256*256];
+ cudaPitchedPtr ptr;
+ ptr.ptr = slice;
+ ptr.pitch = 256*sizeof(float);
+ ptr.xsize = 256*sizeof(float);
+ ptr.ysize = 256;
+
+ for (unsigned int i = 0; i < 256; ++i) {
+ for (unsigned int y = 0; y < 256; ++y)
+ for (unsigned int x = 0; x < 256; ++x)
+ slice[y*256+x] = (i-127.5)*(i-127.5)+(y-127.5)*(y-127.5)+(x-127.5)*(x-127.5) < 4900 ? 1.0f : 0.0f;
+
+ cudaExtent extentS;
+ extentS.width = dims.iVolX*sizeof(float);
+ extentS.height = dims.iVolY;
+ extentS.depth = 1;
+ cudaPos sp = { 0, 0, 0 };
+ cudaPos dp = { 0, 0, i };
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = sp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = dp;
+ p.dstPtr = volData;
+ p.extent = extentS;
+ p.kind = cudaMemcpyHostToDevice;
+ cudaMemcpy3D(&p);
+ }
+ astraCUDA3d::ConeFP(volData, projData, dims, angle, 1.0f);
+
+#else
+
+ for (int i = 0; i < 100; ++i) {
+ char fname[32];
+ sprintf(fname, "Tiffs/%04d.png", 4*i);
+ unsigned int w,h;
+ float* bufp = loadImage(fname, w,h);
+
+ for (int j = 0; j < 512*512; ++j) {
+ float v = bufp[j];
+ if (v > 236.0f) v = 236.0f;
+ v = logf(236.0f / v);
+ bufp[j] = 256*v;
+ }
+
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(((float*)projData.ptr)+100*512*j+512*i, bufp+512*j, 512*sizeof(float), cudaMemcpyHostToDevice);
+ }
+
+ delete[] bufp;
+
+ }
+#endif
+
+#if 0
+ float* bufs = new float[100*512];
+
+ for (int i = 0; i < 512; ++i) {
+ cudaMemcpy(bufs, ((float*)projData.ptr)+100*512*i, 100*512*sizeof(float), cudaMemcpyDeviceToHost);
+
+ printf("%d %d %d\n", projData.pitch, projData.xsize, projData.ysize);
+
+ char fname[20];
+ sprintf(fname, "sino%03d.png", i);
+ saveImage(fname, 100, 512, bufs);
+ }
+
+ float* bufp = new float[512*512];
+
+ for (int i = 0; i < 100; ++i) {
+ for (int j = 0; j < 512; ++j) {
+ cudaMemcpy(bufp+512*j, ((float*)projData.ptr)+100*512*j+512*i, 512*sizeof(float), cudaMemcpyDeviceToHost);
+ }
+
+ char fname[20];
+ sprintf(fname, "proj%03d.png", i);
+ saveImage(fname, 512, 512, bufp);
+ }
+#endif
+
+ zeroVolumeData(volData, dims);
+
+ cudaPitchedPtr maskData;
+ maskData.ptr = 0;
+
+ astraCUDA3d::doSIRT(volData, projData, maskData, dims, angle, 50);
+#if 1
+ float* buf = new float[256*256];
+
+ for (int i = 0; i < 256; ++i) {
+ cudaMemcpy(buf, ((float*)volData.ptr)+256*256*i, 256*256*sizeof(float), cudaMemcpyDeviceToHost);
+
+ char fname[20];
+ sprintf(fname, "vol%03d.png", i);
+ saveImage(fname, 256, 256, buf);
+ }
+#endif
+
+ return 0;
+}
+#endif
+
diff --git a/cuda/3d/sirt3d.h b/cuda/3d/sirt3d.h
new file mode 100644
index 0000000..c3752c2
--- /dev/null
+++ b/cuda/3d/sirt3d.h
@@ -0,0 +1,118 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_SIRT3D_H
+#define _CUDA_SIRT3D_H
+
+#include "util3d.h"
+#include "algo3d.h"
+
+namespace astraCUDA3d {
+
+class _AstraExport SIRT : public ReconAlgo3D {
+public:
+ SIRT();
+ ~SIRT();
+
+// bool setConeGeometry(const SDimensions3D& dims, const SConeProjection* projs);
+
+
+ bool enableVolumeMask();
+ bool enableSinogramMask();
+
+ // init should be called after setting all geometry
+ bool init();
+
+ // setVolumeMask should be called after init and before iterate,
+ // but only if enableVolumeMask was called before init.
+ // It may be called again after iterate.
+ bool setVolumeMask(cudaPitchedPtr& D_maskData);
+
+ // setSinogramMask should be called after init and before iterate,
+ // but only if enableSinogramMask was called before init.
+ // It may be called again after iterate.
+ bool setSinogramMask(cudaPitchedPtr& D_smaskData);
+
+
+ // setBuffers should be called after init and before iterate.
+ // It may be called again after iterate.
+ bool setBuffers(cudaPitchedPtr& D_volumeData,
+ cudaPitchedPtr& D_projData);
+
+
+ // set Min/Max constraints. They may be called at any time, and will affect
+ // any iterate() calls afterwards.
+ bool setMinConstraint(float fMin);
+ bool setMaxConstraint(float fMax);
+
+ // iterate should be called after init and setBuffers.
+ // It may be called multiple times.
+ bool iterate(unsigned int iterations);
+
+ // Compute the norm of the difference of the FP of the current reconstruction
+ // and the sinogram. (This performs one FP.)
+ // It can be called after iterate.
+ float computeDiffNorm();
+
+protected:
+ void reset();
+ bool precomputeWeights();
+
+ bool useVolumeMask;
+ bool useSinogramMask;
+
+ bool useMinConstraint;
+ bool useMaxConstraint;
+ float fMinConstraint;
+ float fMaxConstraint;
+
+ cudaPitchedPtr D_maskData;
+ cudaPitchedPtr D_smaskData;
+
+ // Input/output
+ cudaPitchedPtr D_sinoData;
+ cudaPitchedPtr D_volumeData;
+
+ // Temporary buffers
+ cudaPitchedPtr D_projData;
+ cudaPitchedPtr D_tmpData;
+
+ // Geometry-specific precomputed data
+ cudaPitchedPtr D_lineWeight;
+ cudaPitchedPtr D_pixelWeight;
+};
+
+bool doSIRT(cudaPitchedPtr D_volumeData, unsigned int volumePitch,
+ cudaPitchedPtr D_projData, unsigned int projPitch,
+ cudaPitchedPtr D_maskData, unsigned int maskPitch,
+ const SDimensions3D& dims, const SConeProjection* projs,
+ unsigned int iterations);
+
+}
+
+#endif
diff --git a/cuda/3d/util3d.cu b/cuda/3d/util3d.cu
new file mode 100644
index 0000000..81ea823
--- /dev/null
+++ b/cuda/3d/util3d.cu
@@ -0,0 +1,514 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <cstdio>
+#include <cassert>
+#include "util3d.h"
+#include "../2d/util.h"
+
+namespace astraCUDA3d {
+
+
+cudaPitchedPtr allocateVolumeData(const SDimensions3D& dims)
+{
+ cudaExtent extentV;
+ extentV.width = dims.iVolX*sizeof(float);
+ extentV.height = dims.iVolY;
+ extentV.depth = dims.iVolZ;
+
+ cudaPitchedPtr volData;
+
+ cudaError err = cudaMalloc3D(&volData, extentV);
+ if (err != cudaSuccess) {
+ astraCUDA::reportCudaError(err);
+ fprintf(stderr, "Failed to allocate %dx%dx%d GPU buffer\n", dims.iVolX, dims.iVolY, dims.iVolZ);
+ volData.ptr = 0;
+ // TODO: return 0 somehow?
+ }
+
+ return volData;
+}
+cudaPitchedPtr allocateProjectionData(const SDimensions3D& dims)
+{
+ cudaExtent extentP;
+ extentP.width = dims.iProjU*sizeof(float);
+ extentP.height = dims.iProjAngles;
+ extentP.depth = dims.iProjV;
+
+ cudaPitchedPtr projData;
+
+ cudaError err = cudaMalloc3D(&projData, extentP);
+ if (err != cudaSuccess) {
+ astraCUDA::reportCudaError(err);
+ fprintf(stderr, "Failed to allocate %dx%dx%d GPU buffer\n", dims.iProjU, dims.iProjAngles, dims.iProjV);
+ projData.ptr = 0;
+ // TODO: return 0 somehow?
+ }
+
+ return projData;
+}
+bool zeroVolumeData(cudaPitchedPtr& D_data, const SDimensions3D& dims)
+{
+ char* t = (char*)D_data.ptr;
+ cudaError err;
+
+ for (unsigned int z = 0; z < dims.iVolZ; ++z) {
+ err = cudaMemset2D(t, D_data.pitch, 0, dims.iVolX*sizeof(float), dims.iVolY);
+ ASTRA_CUDA_ASSERT(err);
+ t += D_data.pitch * dims.iVolY;
+ }
+ return true;
+}
+bool zeroProjectionData(cudaPitchedPtr& D_data, const SDimensions3D& dims)
+{
+ char* t = (char*)D_data.ptr;
+ cudaError err;
+
+ for (unsigned int z = 0; z < dims.iProjV; ++z) {
+ err = cudaMemset2D(t, D_data.pitch, 0, dims.iProjU*sizeof(float), dims.iProjAngles);
+ ASTRA_CUDA_ASSERT(err);
+ t += D_data.pitch * dims.iProjAngles;
+ }
+
+ return true;
+}
+bool copyVolumeToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch)
+{
+ if (!pitch)
+ pitch = dims.iVolX;
+
+ cudaPitchedPtr ptr;
+ ptr.ptr = (void*)data; // const cast away
+ ptr.pitch = pitch*sizeof(float);
+ ptr.xsize = dims.iVolX*sizeof(float);
+ ptr.ysize = dims.iVolY;
+
+ cudaExtent extentV;
+ extentV.width = dims.iVolX*sizeof(float);
+ extentV.height = dims.iVolY;
+ extentV.depth = dims.iVolZ;
+
+ cudaPos zp = { 0, 0, 0 };
+
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = zp;
+ p.dstPtr = D_data;
+ p.extent = extentV;
+ p.kind = cudaMemcpyHostToDevice;
+
+ cudaError err;
+ err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+
+ return err == cudaSuccess;
+}
+
+bool copyProjectionsToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch)
+{
+ if (!pitch)
+ pitch = dims.iProjU;
+
+ cudaPitchedPtr ptr;
+ ptr.ptr = (void*)data; // const cast away
+ ptr.pitch = pitch*sizeof(float);
+ ptr.xsize = dims.iProjU*sizeof(float);
+ ptr.ysize = dims.iProjAngles;
+
+ cudaExtent extentV;
+ extentV.width = dims.iProjU*sizeof(float);
+ extentV.height = dims.iProjAngles;
+ extentV.depth = dims.iProjV;
+
+ cudaPos zp = { 0, 0, 0 };
+
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = ptr;
+ p.dstArray = 0;
+ p.dstPos = zp;
+ p.dstPtr = D_data;
+ p.extent = extentV;
+ p.kind = cudaMemcpyHostToDevice;
+
+ cudaError err;
+ err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+
+ return err == cudaSuccess;
+}
+
+bool copyVolumeFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch)
+{
+ if (!pitch)
+ pitch = dims.iVolX;
+
+ cudaPitchedPtr ptr;
+ ptr.ptr = data;
+ ptr.pitch = pitch*sizeof(float);
+ ptr.xsize = dims.iVolX*sizeof(float);
+ ptr.ysize = dims.iVolY;
+
+ cudaExtent extentV;
+ extentV.width = dims.iVolX*sizeof(float);
+ extentV.height = dims.iVolY;
+ extentV.depth = dims.iVolZ;
+
+ cudaPos zp = { 0, 0, 0 };
+
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = D_data;
+ p.dstArray = 0;
+ p.dstPos = zp;
+ p.dstPtr = ptr;
+ p.extent = extentV;
+ p.kind = cudaMemcpyDeviceToHost;
+
+ cudaError err;
+ err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+
+ return err == cudaSuccess;
+}
+bool copyProjectionsFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch)
+{
+ if (!pitch)
+ pitch = dims.iProjU;
+
+ cudaPitchedPtr ptr;
+ ptr.ptr = data;
+ ptr.pitch = pitch*sizeof(float);
+ ptr.xsize = dims.iProjU*sizeof(float);
+ ptr.ysize = dims.iProjAngles;
+
+ cudaExtent extentV;
+ extentV.width = dims.iProjU*sizeof(float);
+ extentV.height = dims.iProjAngles;
+ extentV.depth = dims.iProjV;
+
+ cudaPos zp = { 0, 0, 0 };
+
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = D_data;
+ p.dstArray = 0;
+ p.dstPos = zp;
+ p.dstPtr = ptr;
+ p.extent = extentV;
+ p.kind = cudaMemcpyDeviceToHost;
+
+ cudaError err;
+ err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+
+ return err == cudaSuccess;
+}
+
+bool duplicateVolumeData(cudaPitchedPtr& D_dst, const cudaPitchedPtr& D_src, const SDimensions3D& dims)
+{
+ cudaExtent extentV;
+ extentV.width = dims.iVolX*sizeof(float);
+ extentV.height = dims.iVolY;
+ extentV.depth = dims.iVolZ;
+
+ cudaPos zp = { 0, 0, 0 };
+
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = D_src;
+ p.dstArray = 0;
+ p.dstPos = zp;
+ p.dstPtr = D_dst;
+ p.extent = extentV;
+ p.kind = cudaMemcpyDeviceToDevice;
+
+ cudaError err;
+ err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+
+ return err == cudaSuccess;
+}
+bool duplicateProjectionData(cudaPitchedPtr& D_dst, const cudaPitchedPtr& D_src, const SDimensions3D& dims)
+{
+ cudaExtent extentV;
+ extentV.width = dims.iProjU*sizeof(float);
+ extentV.height = dims.iProjAngles;
+ extentV.depth = dims.iProjV;
+
+ cudaPos zp = { 0, 0, 0 };
+
+ cudaMemcpy3DParms p;
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = D_src;
+ p.dstArray = 0;
+ p.dstPos = zp;
+ p.dstPtr = D_dst;
+ p.extent = extentV;
+ p.kind = cudaMemcpyDeviceToDevice;
+
+ cudaError err;
+ err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+
+ return err == cudaSuccess;
+}
+
+
+
+// TODO: Consider using a single array of size max(proj,volume) (per dim)
+// instead of allocating a new one each time
+
+// TODO: Figure out a faster way of zeroing the padding?
+
+cudaArray* allocateVolumeArray(const SDimensions3D& dims)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+ cudaArray* cuArray;
+ cudaExtent extentA;
+ extentA.width = dims.iVolX+2;
+ extentA.height = dims.iVolY+2;
+ extentA.depth = dims.iVolZ+2;
+ cudaError err = cudaMalloc3DArray(&cuArray, &channelDesc, extentA);
+ if (err != cudaSuccess) {
+ astraCUDA::reportCudaError(err);
+ fprintf(stderr, "Failed to allocate %dx%dx%d GPU array\n", dims.iVolX, dims.iVolY, dims.iVolZ);
+ return 0;
+ }
+
+ zeroVolumeArray(cuArray, dims);
+
+ return cuArray;
+}
+cudaArray* allocateProjectionArray(const SDimensions3D& dims)
+{
+ cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
+ cudaArray* cuArray;
+ cudaExtent extentA;
+ extentA.width = dims.iProjU+2;
+ extentA.height = dims.iProjAngles;
+ extentA.depth = dims.iProjV+2;
+ cudaError err = cudaMalloc3DArray(&cuArray, &channelDesc, extentA);
+
+ if (err != cudaSuccess) {
+ astraCUDA::reportCudaError(err);
+ fprintf(stderr, "Failed to allocate %dx%dx%d GPU array\n", dims.iProjU, dims.iProjAngles, dims.iProjV);
+ return 0;
+ }
+
+ zeroProjectionArray(cuArray, dims);
+
+ return cuArray;
+}
+bool zeroVolumeArray(cudaArray* array, const SDimensions3D& dims)
+{
+ cudaPitchedPtr zeroBuf;
+ cudaExtent extentS;
+ extentS.width = sizeof(float)*(dims.iVolX+2);
+ extentS.height = dims.iVolY+2;
+ extentS.depth = 1;
+
+ cudaExtent extentA;
+ extentA.width = dims.iVolX+2;
+ extentA.height = dims.iVolY+2;
+ extentA.depth = 1;
+
+
+
+ cudaError err;
+ err = cudaMalloc3D(&zeroBuf, extentS);
+ ASTRA_CUDA_ASSERT(err);
+ err = cudaMemset2D(zeroBuf.ptr, zeroBuf.pitch, 0, sizeof(float)*(dims.iVolX+2), dims.iVolY+2);
+ ASTRA_CUDA_ASSERT(err);
+
+ // zero array
+ for (unsigned int i = 0; i < dims.iVolZ+2; ++i) {
+ cudaMemcpy3DParms p;
+ cudaPos zp = {0, 0, 0};
+ cudaPos dp = {0, 0, i};
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = zeroBuf;
+ p.dstArray = array;
+ p.dstPtr.ptr = 0;
+ p.dstPtr.pitch = 0;
+ p.dstPtr.xsize = 0;
+ p.dstPtr.ysize = 0;
+ p.dstPos = dp;
+ p.extent = extentA;
+ p.kind = cudaMemcpyDeviceToDevice;
+
+ err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+ }
+ cudaFree(zeroBuf.ptr);
+
+ // TODO: check errors
+
+ return true;
+}
+bool zeroProjectionArray(cudaArray* array, const SDimensions3D& dims)
+{
+ cudaPitchedPtr zeroBuf;
+ cudaExtent extentS;
+ extentS.width = sizeof(float)*(dims.iProjU+2);
+ extentS.height = dims.iProjAngles;
+ extentS.depth = 1;
+ cudaExtent extentA;
+ extentA.width = dims.iProjU+2;
+ extentA.height = dims.iProjAngles;
+ extentA.depth = 1;
+
+
+ cudaError err;
+ err = cudaMalloc3D(&zeroBuf, extentS);
+ ASTRA_CUDA_ASSERT(err);
+ err = cudaMemset2D(zeroBuf.ptr, zeroBuf.pitch, 0, sizeof(float)*(dims.iProjU+2), dims.iProjAngles);
+ ASTRA_CUDA_ASSERT(err);
+
+ for (unsigned int i = 0; i < dims.iProjV+2; ++i) {
+ cudaMemcpy3DParms p;
+ cudaPos zp = {0, 0, 0};
+ cudaPos dp = {0, 0, i};
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = zeroBuf;
+ p.dstArray = array;
+ p.dstPtr.ptr = 0;
+ p.dstPtr.pitch = 0;
+ p.dstPtr.xsize = 0;
+ p.dstPtr.ysize = 0;
+ p.dstPos = dp;
+ p.extent = extentA;
+ p.kind = cudaMemcpyDeviceToDevice;
+
+ err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+ }
+ cudaFree(zeroBuf.ptr);
+
+ // TODO: check errors
+ return true;
+}
+
+
+bool transferVolumeToArray(cudaPitchedPtr D_volumeData, cudaArray* array, const SDimensions3D& dims)
+{
+ cudaExtent extentA;
+ extentA.width = dims.iVolX;
+ extentA.height = dims.iVolY;
+ extentA.depth = dims.iVolZ;
+
+ cudaMemcpy3DParms p;
+ cudaPos zp = {0, 0, 0};
+ cudaPos dp = {1, 1, 1};
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = D_volumeData;
+ p.dstArray = array;
+ p.dstPtr.ptr = 0;
+ p.dstPtr.pitch = 0;
+ p.dstPtr.xsize = 0;
+ p.dstPtr.ysize = 0;
+ p.dstPos = dp;
+ p.extent = extentA;
+ p.kind = cudaMemcpyDeviceToDevice;
+
+ cudaError err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+ // TODO: check errors
+
+ return true;
+}
+bool transferProjectionsToArray(cudaPitchedPtr D_projData, cudaArray* array, const SDimensions3D& dims)
+{
+ cudaExtent extentA;
+ extentA.width = dims.iProjU;
+ extentA.height = dims.iProjAngles;
+ extentA.depth = dims.iProjV;
+
+ cudaMemcpy3DParms p;
+ cudaPos zp = {0, 0, 0};
+ cudaPos dp = {1, 0, 1};
+ p.srcArray = 0;
+ p.srcPos = zp;
+ p.srcPtr = D_projData;
+ p.dstArray = array;
+ p.dstPtr.ptr = 0;
+ p.dstPtr.pitch = 0;
+ p.dstPtr.xsize = 0;
+ p.dstPtr.ysize = 0;
+ p.dstPos = dp;
+ p.extent = extentA;
+ p.kind = cudaMemcpyDeviceToDevice;
+
+ cudaError err = cudaMemcpy3D(&p);
+ ASTRA_CUDA_ASSERT(err);
+
+ // TODO: check errors
+
+ return true;
+}
+
+
+float dotProduct3D(cudaPitchedPtr data, unsigned int x, unsigned int y,
+ unsigned int z)
+{
+ return astraCUDA::dotProduct2D((float*)data.ptr, data.pitch/sizeof(float), x, y*z, 0, 0);
+}
+
+
+bool cudaTextForceKernelsCompletion()
+{
+ cudaError_t returnedCudaError = cudaThreadSynchronize();
+
+ if(returnedCudaError != cudaSuccess) {
+ fprintf(stderr, "Failed to force completion of cuda kernels: %d: %s.\n", returnedCudaError, cudaGetErrorString(returnedCudaError));
+ return false;
+ }
+
+ return true;
+}
+
+int calcNextPowerOfTwo(int _iValue)
+{
+ int iOutput = 1;
+ while(iOutput < _iValue)
+ iOutput *= 2;
+ return iOutput;
+}
+
+}
diff --git a/cuda/3d/util3d.h b/cuda/3d/util3d.h
new file mode 100644
index 0000000..cf04a18
--- /dev/null
+++ b/cuda/3d/util3d.h
@@ -0,0 +1,69 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _CUDA_UTIL3D_H
+#define _CUDA_UTIL3D_H
+
+#include <cuda.h>
+#include "dims3d.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#include "../2d/util.h"
+
+namespace astraCUDA3d {
+
+cudaPitchedPtr allocateVolumeData(const SDimensions3D& dims);
+cudaPitchedPtr allocateProjectionData(const SDimensions3D& dims);
+bool zeroVolumeData(cudaPitchedPtr& D_data, const SDimensions3D& dims);
+bool zeroProjectionData(cudaPitchedPtr& D_data, const SDimensions3D& dims);
+bool copyVolumeToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0);
+bool copyProjectionsToDevice(const float* data, cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0);
+bool copyVolumeFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0);
+bool copyProjectionsFromDevice(float* data, const cudaPitchedPtr& D_data, const SDimensions3D& dims, unsigned int pitch = 0);
+bool duplicateVolumeData(cudaPitchedPtr& D_dest, const cudaPitchedPtr& D_src, const SDimensions3D& dims);
+bool duplicateProjectionData(cudaPitchedPtr& D_dest, const cudaPitchedPtr& D_src, const SDimensions3D& dims);
+
+
+bool transferProjectionsToArray(cudaPitchedPtr D_projData, cudaArray* array, const SDimensions3D& dims);
+bool transferVolumeToArray(cudaPitchedPtr D_volumeData, cudaArray* array, const SDimensions3D& dims);
+bool zeroProjectionArray(cudaArray* array, const SDimensions3D& dims);
+bool zeroVolumeArray(cudaArray* array, const SDimensions3D& dims);
+cudaArray* allocateProjectionArray(const SDimensions3D& dims);
+cudaArray* allocateVolumeArray(const SDimensions3D& dims);
+
+bool cudaTextForceKernelsCompletion();
+
+float dotProduct3D(cudaPitchedPtr data, unsigned int x, unsigned int y, unsigned int z);
+
+int calcNextPowerOfTwo(int _iValue);
+
+}
+
+#endif
diff --git a/include/astra/Algorithm.h b/include/astra/Algorithm.h
new file mode 100644
index 0000000..d4c73f9
--- /dev/null
+++ b/include/astra/Algorithm.h
@@ -0,0 +1,135 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_ALGORITHM
+#define _INC_ASTRA_ALGORITHM
+
+#include <boost/any.hpp>
+
+#include "Globals.h"
+#include "Config.h"
+
+namespace astra {
+
+/**
+ * This class contains the interface for an algorithm implementation.
+ */
+class _AstraExport CAlgorithm {
+
+public:
+
+ /** Default constructor, containing no code.
+ */
+ CAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg) = 0;
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0) = 0;
+
+ /** Has this class been initialized?
+ *
+ * @return initialized
+ */
+ bool isInitialized();
+
+ /** get a description of the class
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Signal the algorithm it should abort soon.
+ * This is intended to be called from a different thread
+ * while the algorithm is running. There are no guarantees
+ * on how soon the algorithm will abort. The state of the
+ * algorithm object will be consistent (so it is safe to delete it
+ * normally afterwards), but the algorithm's output is undefined.
+ *
+ * Note that specific algorithms may give guarantees on their
+ * state after an abort. Check their documentation for details.
+ */
+ virtual void signalAbort() { m_bShouldAbort = true; }
+
+protected:
+
+ //< Has this class been initialized?
+ bool m_bIsInitialized;
+
+ //< If this is set, the algorithm should try to abort as soon as possible.
+ volatile bool m_bShouldAbort;
+
+private:
+ /**
+ * Private copy constructor to prevent CAlgorithms from being copied.
+ */
+ CAlgorithm(const CAlgorithm&);
+
+ /**
+ * Private assignment operator to prevent CAlgorithms from being copied.
+ */
+ CAlgorithm& operator=(const CAlgorithm&);
+
+ //< For Config unused argument checking
+ ConfigCheckData* configCheckData;
+ friend class ConfigStackCheck<CAlgorithm>;
+
+};
+
+// inline functions
+inline std::string CAlgorithm::description() const { return "Algorithm"; };
+inline bool CAlgorithm::isInitialized() { return m_bIsInitialized; }
+
+} // end namespace
+
+#endif
diff --git a/include/astra/AlgorithmTypelist.h b/include/astra/AlgorithmTypelist.h
new file mode 100644
index 0000000..615c143
--- /dev/null
+++ b/include/astra/AlgorithmTypelist.h
@@ -0,0 +1,108 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_ALGORITHMTYPELIST
+#define _INC_ASTRA_ALGORITHMTYPELIST
+
+#include "Algorithm.h"
+#include "TypeList.h"
+
+#include "ArtAlgorithm.h"
+#include "SirtAlgorithm.h"
+#include "SartAlgorithm.h"
+#include "ForwardProjectionAlgorithm.h"
+#include "BackProjectionAlgorithm.h"
+#include "FilteredBackProjectionAlgorithm.h"
+#include "CudaBackProjectionAlgorithm.h"
+#include "CudaSartAlgorithm.h"
+#include "CudaSirtAlgorithm.h"
+#include "CudaCglsAlgorithm.h"
+#include "CudaEMAlgorithm.h"
+#include "CudaForwardProjectionAlgorithm.h"
+#include "CglsAlgorithm.h"
+#include "CudaCglsAlgorithm3D.h"
+#include "CudaSirtAlgorithm3D.h"
+#include "CudaForwardProjectionAlgorithm3D.h"
+#include "CudaBackProjectionAlgorithm3D.h"
+#include "CudaFDKAlgorithm3D.h"
+#include "CudaDartMaskAlgorithm.h"
+#include "CudaDartMaskAlgorithm3D.h"
+#include "CudaDartSmoothingAlgorithm.h"
+#include "CudaDartSmoothingAlgorithm3D.h"
+#include "CudaDataOperationAlgorithm.h"
+#include "CudaRoiSelectAlgorithm.h"
+
+using namespace astra;
+
+#ifdef ASTRA_CUDA
+
+#include "CudaFilteredBackProjectionAlgorithm.h"
+
+typedef TYPELIST_25(
+ CArtAlgorithm,
+ CSartAlgorithm,
+ CSirtAlgorithm,
+ CCglsAlgorithm,
+ CBackProjectionAlgorithm,
+ CForwardProjectionAlgorithm,
+ CCudaSartAlgorithm,
+ CFilteredBackProjectionAlgorithm,
+ CCudaBackProjectionAlgorithm,
+ CCudaDartMaskAlgorithm,
+ CCudaDartMaskAlgorithm3D,
+ CCudaDartSmoothingAlgorithm,
+ CCudaDartSmoothingAlgorithm3D,
+ CCudaDataOperationAlgorithm,
+ CCudaRoiSelectAlgorithm,
+ CCudaSirtAlgorithm,
+ CCudaCglsAlgorithm,
+ CCudaEMAlgorithm,
+ CCudaForwardProjectionAlgorithm,
+ CCudaCglsAlgorithm3D,
+ CCudaFilteredBackProjectionAlgorithm,
+ CCudaFDKAlgorithm3D,
+ CCudaSirtAlgorithm3D,
+ CCudaForwardProjectionAlgorithm3D,
+ CCudaBackProjectionAlgorithm3D
+ )
+ AlgorithmTypeList;
+#else
+
+typedef TYPELIST_7(
+ CArtAlgorithm,
+ CSartAlgorithm,
+ CSirtAlgorithm,
+ CCglsAlgorithm,
+ CBackProjectionAlgorithm,
+ CForwardProjectionAlgorithm,
+ CFilteredBackProjectionAlgorithm
+ ) AlgorithmTypeList;
+
+#endif
+
+#endif
diff --git a/include/astra/ArtAlgorithm.h b/include/astra/ArtAlgorithm.h
new file mode 100644
index 0000000..bd02fc4
--- /dev/null
+++ b/include/astra/ArtAlgorithm.h
@@ -0,0 +1,196 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_ARTALGORITHM
+#define _INC_ASTRA_ARTALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+#include "ReconstructionAlgorithm2D.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+namespace astra {
+
+/**
+ * This class contains the implementation of the ART (Algebraic Reconstruction Technique) algorithm.
+ *
+ * The update step of pixel \f$v_j\f$ for ray \f$i\f$ and iteration \f$k\f$ is given by:
+ * \f[
+ * v_j^{(k+1)} = v_j^{(k)} + \lambda \frac{p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}}{\sum_{k=1}^{N} w_{ik}^2}
+ * \f]
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.}
+ * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.}
+ * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.}
+ * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.}
+ * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.}
+ * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.}
+ * \astra_xml_item_option{Lamda, float, 1, The relaxation factor.}
+ * \astra_xml_item_option{RayOrder, string, "sequential", the order in which the rays are updated. 'sequential' or 'custom'}
+ * \astra_xml_item_option{RayOrderList, n by 2 vector of float, not used, if RayOrder='custom': use this ray order. Each row consist of a projection id and detector id.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('ART');\n
+ * cfg.ProjectorId = proj_id;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * cfg.ReconstructionDataId = recon_id;\n
+ * cfg.option.MaskId = mask_id;\n
+ * cfg.option.UseMinConstraint = 'yes';\n
+ * cfg.option.UseMaxConstraint = 'yes';\n
+ * cfg.option.MaxConstraintValue = 1024;\n
+ * cfg.option.Lamda = 0.7;\n
+ * cfg.option.RayOrder = 'custom';\n
+ * cfg.option.RayOrderList = [0\,0; 0\,2; 1\,0];\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('iterate'\, alg_id\, 1000);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ */
+class _AstraExport CArtAlgorithm : public CReconstructionAlgorithm2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - the projector is compatible with both data objects
+ * - the ray order list only contains valid values
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CArtAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CArtAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, use sequential ray order.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Set the relaxation factor.
+ *
+ * @param _fLambda Relaxation factor
+ */
+ void setLambda(float32 _fLambda);
+
+ /** Set the order in which the rays will be selected
+ *
+ * @param _piProjectionOrder Order of the rays, the projections. (size should be _piRayCount)
+ * @param _piDetectorOrder Order of the rays, the detectors. (size should be _piRayCount)
+ * @param _piRayCount Number of rays in the two previous arrays.
+ */
+ void setRayOrder(int* _piProjectionOrder, int* _piDetectorOrder, int _piRayCount);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+protected:
+
+ //< Relaxation Factor
+ float32 m_fLambda;
+
+ //< Order of the rays, the projections.
+ int* m_piProjectionOrder;
+ //< Order of the rays, the detectors.
+ int* m_piDetectorOrder;
+ //< Number of rays specified in the ray order arrays.
+ int m_iRayCount;
+ //< Current index in the ray order arrays.
+ int m_iCurrentRay;
+
+};
+
+// inline functions
+inline std::string CArtAlgorithm::description() const { return CArtAlgorithm::type; };
+
+
+} // end namespace
+
+#endif
diff --git a/include/astra/AstraObjectFactory.h b/include/astra/AstraObjectFactory.h
new file mode 100644
index 0000000..784d698
--- /dev/null
+++ b/include/astra/AstraObjectFactory.h
@@ -0,0 +1,149 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_ASTRAOBJECTFACTORY
+#define _INC_ASTRA_ASTRAOBJECTFACTORY
+
+#include "Globals.h"
+#include "Config.h"
+#include "Singleton.h"
+#include "Utilities.h"
+#include "TypeList.h"
+
+#include "ProjectorTypelist.h"
+
+
+#include "AlgorithmTypelist.h"
+
+
+namespace astra {
+
+/**
+ * This class contains functionality to create data objects based on their type or on a configuration object.
+ */
+template <typename T, typename TypeList>
+class CAstraObjectFactory : public Singleton<CAstraObjectFactory<T, TypeList> > {
+
+public:
+
+ /** A default constructor that contains not a single line of code.
+ */
+ CAstraObjectFactory();
+
+ /** Destructor.
+ */
+ ~CAstraObjectFactory();
+
+ /** Create, but don't initialize, a new projector object.
+ *
+ * @param _sType Type of the new projector.
+ * @return Pointer to a new, unitialized projector.
+ */
+ T* create(std::string _sType);
+
+ /** Create and initialize a new projector object.
+ *
+ * @param _cfg Configuration object to create and initialize a new projector.
+ * @return Pointer to a new, initialized projector.
+ */
+ T* create(const Config& _cfg);
+
+
+};
+
+
+//----------------------------------------------------------------------------------------
+// Constructor
+template <typename T, typename TypeList>
+CAstraObjectFactory<T, TypeList>::CAstraObjectFactory()
+{
+
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+template <typename T, typename TypeList>
+CAstraObjectFactory<T, TypeList>::~CAstraObjectFactory()
+{
+
+}
+
+//----------------------------------------------------------------------------------------
+// Create
+template <typename T, typename TypeList>
+T* CAstraObjectFactory<T, TypeList>::create(std::string _sType)
+{
+ functor_find<T> finder = functor_find<T>();
+ finder.tofind = _sType;
+ CreateObject<TypeList>::find(finder);
+ return finder.res;
+}
+
+//----------------------------------------------------------------------------------------
+// Create with XML
+template <typename T, typename TypeList>
+T* CAstraObjectFactory<T, TypeList>::create(const Config& _cfg)
+{
+ functor_find<T> finder = functor_find<T>();
+ finder.tofind = _cfg.self->getAttribute("type");
+ CreateObject<TypeList>::find(finder);
+ if (finder.res == NULL) return NULL;
+ if (finder.res->initialize(_cfg))
+ return finder.res;
+
+ delete finder.res;
+ return NULL;
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+//----------------------------------------------------------------------------------------
+// Create the necessary Object Managers
+/**
+ * Class used to create algorithms from a string or a config object
+*/
+class _AstraExport CAlgorithmFactory : public CAstraObjectFactory<CAlgorithm, AlgorithmTypeList> {};
+
+/**
+ * Class used to create 2D projectors from a string or a config object
+*/
+class _AstraExport CProjector2DFactory : public CAstraObjectFactory<CProjector2D, Projector2DTypeList> {};
+
+/**
+ * Class used to create 3D projectors from a string or a config object
+*/
+class _AstraExport CProjector3DFactory : public CAstraObjectFactory<CProjector3D, Projector3DTypeList> {};
+
+
+
+
+} // end namespace
+
+#endif
diff --git a/include/astra/AstraObjectManager.h b/include/astra/AstraObjectManager.h
new file mode 100644
index 0000000..afb6312
--- /dev/null
+++ b/include/astra/AstraObjectManager.h
@@ -0,0 +1,290 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_ASTRAOBJECTMANAGER
+#define _INC_ASTRA_ASTRAOBJECTMANAGER
+
+#include <map>
+#include <sstream>
+
+#include "Globals.h"
+#include "Singleton.h"
+#include "Projector2D.h"
+#include "Projector3D.h"
+#include "Float32Data2D.h"
+#include "Float32Data3D.h"
+#include "SparseMatrix.h"
+#include "Algorithm.h"
+
+namespace astra {
+
+/**
+ * This class contains functionality to store objects. A unique index handle
+ * will be assigned to each data object by which it can be accessed in the
+ * future. Indices are always >= 1.
+ *
+ * We store them in a special common base class to make indices unique
+ * among all ObjectManagers.
+ */
+
+
+class CAstraIndexManager {
+protected:
+ /** The index of the previously stored data object.
+ */
+ static int m_iPreviousIndex;
+};
+
+
+template <typename T>
+class CAstraObjectManager : public Singleton<CAstraObjectManager<T> >, CAstraIndexManager {
+
+public:
+
+ /** Default constructor.
+ */
+ CAstraObjectManager();
+
+ /** Destructor.
+ */
+ ~CAstraObjectManager();
+
+ /** Store the object in the manager and assign a unique index handle to it.
+ *
+ * @param _pObject A pointer to the object that should be stored.
+ * @return The index of the stored data object. If the index in negative, an error occurred
+ * and the object was NOT stored.
+ */
+ int store(T* _pObject);
+
+ /** Does the manager contain an object with the index _iIndex?
+ *
+ * @param _iIndex Index handle to the data object in question.
+ * @return True if the manager contains an object with the index handle _iIndex.
+ */
+ bool hasIndex(int _iIndex) const;
+
+ /** Fetch the object to which _iIndex refers to.
+ *
+ * @param _iIndex Index handle to the data object in question.
+ * @return Pointer to the stored data object. A null pointer is returned if no object with index _iIndex is found.
+ */
+ T* get(int _iIndex) const;
+
+ /** Delete an object that was previously stored. This actually DELETES the objecy. Therefore, after this
+ * function call, the object in question will have passed on. It will be no more. It will have ceased
+ * to be. It will be expired and will go to meet its maker. Bereft of life, it will rest in peace.
+ * It will be an EX-OBJECT.
+ *
+ * @param _iIndex Index handle to the object in question.
+ * @return Error code. 0 for success.
+ */
+ void remove(int _iIndex);
+
+ /** Get the index of the object, zero if it doesn't exist.
+ *
+ * @param _pObject The data object.
+ * @return Index of the stored object, 0 if not found.
+ */
+ int getIndex(const T* _pObject) const;
+
+ /** Clear all data. This will also delete all the content of each object.
+ */
+ void clear();
+
+ /** Get info.
+ */
+ std::string info();
+
+protected:
+
+ /** Map each data object to a unique index.
+ */
+ std::map<int, T*> m_mIndexToObject;
+
+};
+
+//----------------------------------------------------------------------------------------
+// Constructor
+template <typename T>
+CAstraObjectManager<T>::CAstraObjectManager()
+{
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+template <typename T>
+CAstraObjectManager<T>::~CAstraObjectManager()
+{
+
+}
+
+//----------------------------------------------------------------------------------------
+// store data
+template <typename T>
+int CAstraObjectManager<T>::store(T* _pDataObject)
+{
+ m_iPreviousIndex++;
+ m_mIndexToObject[m_iPreviousIndex] = _pDataObject;
+ return m_iPreviousIndex;
+}
+
+//----------------------------------------------------------------------------------------
+// has data?
+template <typename T>
+bool CAstraObjectManager<T>::hasIndex(int _iIndex) const
+{
+ typename map<int,T*>::const_iterator it = m_mIndexToObject.find(_iIndex);
+ return it != m_mIndexToObject.end();
+}
+
+//----------------------------------------------------------------------------------------
+// get data
+template <typename T>
+T* CAstraObjectManager<T>::get(int _iIndex) const
+{
+ typename map<int,T*>::const_iterator it = m_mIndexToObject.find(_iIndex);
+ if (it != m_mIndexToObject.end())
+ return it->second;
+ else
+ return 0;
+}
+
+//----------------------------------------------------------------------------------------
+// delete data
+template <typename T>
+void CAstraObjectManager<T>::remove(int _iIndex)
+{
+ if (!hasIndex(_iIndex)) {
+ return;
+ }
+ // find data
+ typename map<int,T*>::iterator it = m_mIndexToObject.find(_iIndex);
+ // delete data
+ delete (*it).second;
+ // delete from map
+ m_mIndexToObject.erase(it);
+}
+
+//----------------------------------------------------------------------------------------
+// Get Index
+template <typename T>
+int CAstraObjectManager<T>::getIndex(const T* _pObject) const
+{
+ for (typename map<int,T*>::const_iterator it = m_mIndexToObject.begin(); it != m_mIndexToObject.end(); it++) {
+ if ((*it).second == _pObject) return (*it).first;
+ }
+ return 0;
+}
+
+
+//----------------------------------------------------------------------------------------
+// clear
+template <typename T>
+void CAstraObjectManager<T>::clear()
+{
+ for (typename map<int,T*>::iterator it = m_mIndexToObject.begin(); it != m_mIndexToObject.end(); it++) {
+ // delete data
+ delete (*it).second;
+ (*it).second = 0;
+ }
+
+ m_mIndexToObject.clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Print info to string
+template <typename T>
+std::string CAstraObjectManager<T>::info() {
+ std::stringstream res;
+ res << "id init description" << std::endl;
+ res << "-----------------------------------------" << std::endl;
+ for (typename map<int,T*>::iterator it = m_mIndexToObject.begin(); it != m_mIndexToObject.end(); it++) {
+ res << (*it).first << " \t";
+ T* pObject = m_mIndexToObject[(*it).first];
+ if (pObject->isInitialized()) {
+ res << "v ";
+ } else {
+ res << "x ";
+ }
+ res << pObject->description() << endl;
+ }
+ res << "-----------------------------------------" << std::endl;
+ return res.str();
+}
+
+
+
+//----------------------------------------------------------------------------------------
+// Create the necessary Object Managers
+/**
+ * This class contains functionality to store 2D projector objects. A unique index handle will be
+ * assigned to each data object by which it can be accessed in the future.
+ * Indices are always >= 1.
+ */
+class _AstraExport CProjector2DManager : public CAstraObjectManager<CProjector2D>{};
+
+/**
+ * This class contains functionality to store 3D projector objects. A unique index handle will be
+ * assigned to each data object by which it can be accessed in the future.
+ * Indices are always >= 1.
+ */
+class _AstraExport CProjector3DManager : public CAstraObjectManager<CProjector3D>{};
+
+/**
+ * This class contains functionality to store 2D data objects. A unique index handle will be
+ * assigned to each data object by which it can be accessed in the future.
+ * Indices are always >= 1.
+ */
+class _AstraExport CData2DManager : public CAstraObjectManager<CFloat32Data2D>{};
+
+/**
+ * This class contains functionality to store 3D data objects. A unique index handle will be
+ * assigned to each data object by which it can be accessed in the future.
+ * Indices are always >= 1.
+ */
+class _AstraExport CData3DManager : public CAstraObjectManager<CFloat32Data3D>{};
+
+/**
+ * This class contains functionality to store algorithm objects. A unique index handle will be
+ * assigned to each data object by which it can be accessed in the future.
+ * Indices are always >= 1.
+ */
+class _AstraExport CAlgorithmManager : public CAstraObjectManager<CAlgorithm>{};
+
+/**
+ * This class contains functionality to store matrix objects. A unique index handle will be
+ * assigned to each data object by which it can be accessed in the future.
+ * Indices are always >= 1.
+ */
+class _AstraExport CMatrixManager : public CAstraObjectManager<CSparseMatrix>{};
+
+
+} // end namespace
+
+#endif
diff --git a/include/astra/AsyncAlgorithm.h b/include/astra/AsyncAlgorithm.h
new file mode 100644
index 0000000..64f70c3
--- /dev/null
+++ b/include/astra/AsyncAlgorithm.h
@@ -0,0 +1,128 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_ASYNCALGORITHM
+#define _INC_ASTRA_ASYNCALGORITHM
+
+#include "Config.h"
+#include "Algorithm.h"
+
+#ifdef __linux__
+#define USE_PTHREADS
+#include <pthread.h>
+#else
+#include <boost/thread.hpp>
+#endif
+
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains an wrapper algorithm that allows termination of its wrapped algorithm.
+ *
+ * This is used to allow algorithm termination from matlab command line.
+ */
+
+class _AstraExport CAsyncAlgorithm : public CAlgorithm {
+public:
+ /** Default constructor, containing no code.
+ */
+ CAsyncAlgorithm();
+
+ /** Constructor.
+ */
+ explicit CAsyncAlgorithm(CAlgorithm* _pAlg);
+
+ /** Destructor.
+ */
+ virtual ~CAsyncAlgorithm();
+
+ /** Initialize using config object.
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize using algorithm pointer.
+ */
+ virtual bool initialize(CAlgorithm* _pAlg);
+
+ /** Run the algorithm.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Wait for thread to complete and delete thread.
+ */
+ virtual void timedJoin(int _milliseconds);
+
+ /** Return pointer to the wrapped algorithm.
+ */
+ CAlgorithm* getWrappedAlgorithm() { return m_pAlg; }
+
+ /** Is the wrapped algorithm done.
+ */
+ bool isDone() const { return m_bDone; }
+
+ /** Signal abort to the wrapped algorithm.
+ */
+ void signalAbort();
+
+protected:
+ //< Has this class been initialized?
+ bool m_bInitialized;
+
+ //< Should wrapped algorithm be deleted after completion?
+ bool m_bAutoFree;
+
+ //< Pointer to wrapped algorithm.
+ CAlgorithm* m_pAlg;
+
+ //< Is the wrapped algorithm done.
+ volatile bool m_bDone;
+
+#ifndef USE_PTHREADS
+ //< Handle to boost thread object running the wrapped algorithm.
+ boost::thread* m_pThread;
+#else
+ pthread_t m_thread;
+ struct AsyncThreadInfo {
+ int m_iIterations;
+ CAlgorithm* m_pAlg;
+ volatile bool* m_pDone;
+ } m_ThreadInfo;
+ friend void* runAsync_pthreads(void*);
+#endif
+ bool m_bThreadStarted;
+
+ //< Run the wrapped algorithm.
+ void runWrapped(int _iNrIterations);
+
+};
+
+}
+
+#endif
diff --git a/include/astra/BackProjectionAlgorithm.h b/include/astra/BackProjectionAlgorithm.h
new file mode 100644
index 0000000..d50b406
--- /dev/null
+++ b/include/astra/BackProjectionAlgorithm.h
@@ -0,0 +1,155 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_BACKPROJECTIONALGORITHM
+#define _INC_ASTRA_BACKPROJECTIONALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+#include "ReconstructionAlgorithm2D.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+#include "DataProjector.h"
+
+namespace astra {
+
+/**
+ * \brief
+ * This class performs an unfiltered backprojection.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.}
+ * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.}
+ *
+ */
+class _AstraExport CBackProjectionAlgorithm : public CReconstructionAlgorithm2D {
+
+protected:
+
+ /** Init stuff
+ */
+ virtual void _init();
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - valid projector
+ * - valid data objects
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CBackProjectionAlgorithm();
+
+ /** Default constructor
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ */
+ CBackProjectionAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Destructor.
+ */
+ virtual ~CBackProjectionAlgorithm();
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return Initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @return Initialization successful?
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Get all information parameters.
+ *
+ * @return Map with all available identifier strings and their values.
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier Identifier string to specify which piece of information you want.
+ * @return One piece of information.
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+};
+
+// inline functions
+inline std::string CBackProjectionAlgorithm::description() const { return CBackProjectionAlgorithm::type; };
+
+
+} // end namespace
+
+#endif
diff --git a/include/astra/CglsAlgorithm.h b/include/astra/CglsAlgorithm.h
new file mode 100644
index 0000000..1700d74
--- /dev/null
+++ b/include/astra/CglsAlgorithm.h
@@ -0,0 +1,182 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CGLSALGORITHM
+#define _INC_ASTRA_CGLSALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+#include "ReconstructionAlgorithm2D.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+#include "DataProjector.h"
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains the implementation of the CGLS (Conguent Gradient Algorithm) algorithm.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.}
+ * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 0 = reconstruct using this ray. 1 = don't use this ray while reconstructing.}
+ * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.}
+ * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.}
+ * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.}
+ * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('CGLS');\n
+ * cfg.ProjectorId = proj_id;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * cfg.ReconstructionDataId = recon_id;\n
+ * cfg.option.MaskId = mask_id;\n
+ * cfg.option.UseMinConstraint = 'yes';\n
+ * cfg.option.UseMaxConstraint = 'yes';\n
+ * cfg.option.MaxConstraintValue = 1024;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('iterate'\, alg_id\, 10);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ */
+class _AstraExport CCglsAlgorithm : public CReconstructionAlgorithm2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - valid projector
+ * - valid data objects
+ */
+ virtual bool _check();
+
+ CFloat32ProjectionData2D* r;
+ CFloat32ProjectionData2D* w;
+ CFloat32VolumeData2D* z;
+ CFloat32VolumeData2D* p;
+
+ float32 alpha;
+ float32 beta;
+ float32 gamma;
+
+
+ int m_iIteration;
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCglsAlgorithm();
+
+ /** Default constructor
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ */
+ CCglsAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Destructor.
+ */
+ virtual ~CCglsAlgorithm();
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return Initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @return Initialization successful?
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Get all information parameters.
+ *
+ * @return Map with all available identifier strings and their values.
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier Identifier string to specify which piece of information you want.
+ * @return One piece of information.
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+};
+
+// inline functions
+inline std::string CCglsAlgorithm::description() const { return CCglsAlgorithm::type; };
+
+
+} // end namespace
+
+#endif
diff --git a/include/astra/ConeProjectionGeometry3D.h b/include/astra/ConeProjectionGeometry3D.h
new file mode 100644
index 0000000..497ce7d
--- /dev/null
+++ b/include/astra/ConeProjectionGeometry3D.h
@@ -0,0 +1,213 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CONEPROJECTIONGEOMETRY3D
+#define _INC_ASTRA_CONEPROJECTIONGEOMETRY3D
+
+#include "ProjectionGeometry3D.h"
+
+namespace astra
+{
+
+/**
+ * This class defines a 3D cone beam projection geometry.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorWidth, float, Width of each detector.}
+ * \astra_xml_item{DetectorHeight, float, Width of each detector.}
+ * \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.}
+ * \astra_xml_item{DistanceOriginDetector, float, Distance between the center of rotation and the detectorarray.}
+ * \astra_xml_item{DistanceOriginSource, float, Distance between the center of rotation the the x-ray source.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * proj_geom = astra_struct('cone');\n
+ * proj_geom.DetectorRowCount = 512;\n
+ * proj_geom.DetectorColCount = 512;\n
+ * proj_geom.DetectorWidth = 1.0;\n
+ * proj_geom.DetectorHeight = 1.0;\n
+ * proj_geom.ProjectionAngles = linspace(0,pi,100);\n
+ * proj_geom.DistanceOriginDetector = 10000;\n
+ * proj_geom.DistanceOriginSource = 10000;\n
+ * }
+ */
+class _AstraExport CConeProjectionGeometry3D : public CProjectionGeometry3D
+{
+protected:
+
+ /**
+ * Distance from the origin of the coordinate system to the source.
+ */
+ float32 m_fOriginSourceDistance;
+
+ /**
+ * Distance from the origin of the coordinate system to the detector (i.e., the distance between the origin and its orthogonal projection
+ * onto the detector array).
+ */
+ float32 m_fOriginDetectorDistance;
+
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the initialize() methods before the object can be used. Any use before calling initialize()
+ * is not allowed, except calling the member function isInitialized().
+ */
+ CConeProjectionGeometry3D();
+
+ /** Constructor. Create an instance of the CParallelProjectionGeometry3D class.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _fDetectorHeight Height of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles
+ * are represented in radians and lie in the [0,2pi[ interval.
+ */
+ CConeProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorWidth,
+ float32 _fDetectorHeight,
+ const float32* _pfProjectionAngles,
+ float32 _fOriginSourceDistance,
+ float32 _fOriginDetectorDistance);
+
+ /** Copy constructor.
+ */
+ CConeProjectionGeometry3D(const CConeProjectionGeometry3D& _projGeom);
+
+ /** Destructor.
+ */
+ ~CConeProjectionGeometry3D();
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the geometry. If the object has been initialized before, the object is reinitialized
+ * and memory is freed and reallocated if necessary.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _fDetectorHeight Height of a detector cell, in unit lengths. All detector cells are assumed to have equal height.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles
+ * are represented in radians and lie in the [0,2pi[ interval.
+ */
+ bool initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorWidth,
+ float32 _fDetectorHeight,
+ const float32* _pfProjectionAngles,
+ float32 _fOriginSourceDistance,
+ float32 _fOriginDetectorDistance);
+
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry3D* clone() const;
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(const CProjectionGeometry3D*) const;
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if _sType == "cone".
+ */
+ virtual bool isOfType(const std::string& _sType) const;
+
+ /** Turn this object into an XML object.
+ *
+ * @param _sNode The XML object to fill.
+ */
+ virtual void toXML(XMLNode* _sNode) const;
+
+ /** Returns the distance from the origin of the coordinate system to the source.
+ *
+ * @return Distance from the origin of the coordinate system to the source
+ */
+ float32 getOriginSourceDistance() const;
+
+ /** Returns the distance from the origin of the coordinate system to the detector
+ * (i.e., the distance between the origin and its orthogonal projection onto the detector array).
+ *
+ * @return Distance from the origin of the coordinate system to the detector
+ */
+ float32 getOriginDetectorDistance() const;
+
+ /** Returns the distance from the source to the detector
+ * (i.e., the distance between the source and its orthogonal projection onto the detector array).
+ *
+ * @return Distance from the source to the detector
+ */
+ float32 getSourceDetectorDistance() const;
+
+ /**
+ * Returns a vector giving the projection direction for a projection and detector index
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const;
+};
+
+// Returns the distance from the origin of the coordinate system to the source.
+inline float32 CConeProjectionGeometry3D::getOriginSourceDistance() const
+{
+ return m_fOriginSourceDistance;
+}
+
+
+// Returns the distance from the origin of the coordinate system to the detector.
+inline float32 CConeProjectionGeometry3D::getOriginDetectorDistance() const
+{
+ return m_fOriginDetectorDistance;
+}
+
+
+// Returns the distance from the source to the detector.
+inline float32 CConeProjectionGeometry3D::getSourceDetectorDistance() const
+{
+ return (m_fOriginSourceDistance + m_fOriginDetectorDistance);
+}
+
+
+} // namespace astra
+
+#endif /* _INC_ASTRA_PARALLELPROJECTIONGEOMETRY3D */
diff --git a/include/astra/ConeVecProjectionGeometry3D.h b/include/astra/ConeVecProjectionGeometry3D.h
new file mode 100644
index 0000000..1765cdd
--- /dev/null
+++ b/include/astra/ConeVecProjectionGeometry3D.h
@@ -0,0 +1,154 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CONEVECPROJECTIONGEOMETRY3D
+#define _INC_ASTRA_CONEVECPROJECTIONGEOMETRY3D
+
+#include "ProjectionGeometry3D.h"
+#include "../cuda/3d/dims3d.h"
+
+namespace astra
+{
+
+/**
+ * This class defines a 3D cone beam projection geometry.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{Vectors, matrix defining the 3D position of source and detector.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * proj_geom = astra_struct('cone_vec');\n
+ * proj_geom.DetectorRowCount = 512;\n
+ * proj_geom.DetectorColCount = 512;\n
+ * proj_geom.Vectors = V;\n
+ * }
+ *
+ * \par Vectors
+ * Vectors is a matrix containing the actual geometry. Each row corresponds
+ * to a single projection, and consists of:
+ * ( srcX, srcY, srcZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ )
+ * src: the ray source
+ * d : the corner of the detector
+ * u : the vector from detector pixel (0,0) to (0,1)
+ * v : the vector from detector pixel (0,0) to (1,0)
+ */
+class _AstraExport CConeVecProjectionGeometry3D : public CProjectionGeometry3D
+{
+protected:
+
+ SConeProjection *m_pProjectionAngles;
+
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the initialize() methods before the object can be used. Any use before calling initialize()
+ * is not allowed, except calling the member function isInitialized().
+ */
+ CConeVecProjectionGeometry3D();
+
+ /** Constructor. Create an instance of the CConeVecProjectionGeometry3D class.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ CConeVecProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ const SConeProjection* _pProjectionAngles);
+
+ /** Copy constructor.
+ */
+ CConeVecProjectionGeometry3D(const CConeVecProjectionGeometry3D& _projGeom);
+
+ /** Destructor.
+ */
+ ~CConeVecProjectionGeometry3D();
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the geometry. If the object has been initialized before, the object is reinitialized
+ * and memory is freed and reallocated if necessary.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _pProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ bool initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ const SConeProjection* _pProjectionAngles);
+
+ virtual bool _check();
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry3D* clone() const;
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(const CProjectionGeometry3D*) const;
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if _sType == "cone_vec".
+ */
+ virtual bool isOfType(const std::string& _sType) const;
+
+ /** Turn this object into an XML object.
+ *
+ * @param _sNode The XML object to fill.
+ */
+ virtual void toXML(XMLNode* _sNode) const;
+
+ /**
+ * Returns a vector giving the projection direction for a projection and detector index
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const;
+
+ const SConeProjection* getProjectionVectors() const { return m_pProjectionAngles; }
+};
+
+} // namespace astra
+
+#endif /* _INC_ASTRA_CONEVECPROJECTIONGEOMETRY3D */
diff --git a/include/astra/Config.h b/include/astra/Config.h
new file mode 100644
index 0000000..5a629a2
--- /dev/null
+++ b/include/astra/Config.h
@@ -0,0 +1,80 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CONFIG
+#define _INC_ASTRA_CONFIG
+
+#include "Globals.h"
+#include "XMLNode.h"
+
+#include <set>
+
+namespace astra {
+
+
+/**
+ * Configuration options for an ASTRA class.
+ */
+struct _AstraExport Config {
+
+ Config();
+ Config(XMLNode* _self);
+ ~Config();
+
+ XMLNode* self;
+ XMLNode* global;
+};
+
+struct ConfigCheckData {
+ // For checking for unparsed nodes/options
+ std::set<std::string> parsedNodes;
+ std::set<std::string> parsedOptions;
+ unsigned int parseDepth;
+};
+
+
+template<class T>
+class ConfigStackCheck {
+public:
+ ConfigStackCheck(const char *_name, T* _obj, const Config& _cfg);
+ ~ConfigStackCheck();
+
+ bool stopParsing(); // returns true if no unused nodes/options
+ void markNodeParsed(const std::string& name);
+ void markOptionParsed(const std::string& name);
+
+
+private:
+ T* object;
+ const Config* cfg;
+ const char* name;
+};
+
+} // end namespace
+
+#endif
diff --git a/include/astra/CudaBackProjectionAlgorithm.h b/include/astra/CudaBackProjectionAlgorithm.h
new file mode 100644
index 0000000..965c734
--- /dev/null
+++ b/include/astra/CudaBackProjectionAlgorithm.h
@@ -0,0 +1,110 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDABACKPROJECTIONALGORITHM
+#define _INC_ASTRA_CUDABACKPROJECTIONALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "CudaReconstructionAlgorithm2D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains a GPU implementation of backprojection.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('BP_CUDA');\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * cfg.ReconstructionDataId = recon_id;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('iterate'\, alg_id\, 1);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ */
+class _AstraExport CCudaBackProjectionAlgorithm : public CCudaReconstructionAlgorithm2D
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaBackProjectionAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaBackProjectionAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object. (Ignored)
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @param _iGPUindex GPU to use.
+ * @param _iPixelSuperSampling Square root of number of samples per voxel, used to compute the backprojection
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex = 0, int _iPixelSuperSampling = 1);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+};
+
+// inline functions
+inline std::string CCudaBackProjectionAlgorithm::description() const { return CCudaBackProjectionAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaBackProjectionAlgorithm3D.h b/include/astra/CudaBackProjectionAlgorithm3D.h
new file mode 100644
index 0000000..b069da6
--- /dev/null
+++ b/include/astra/CudaBackProjectionAlgorithm3D.h
@@ -0,0 +1,152 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDABACKPROJECTIONALGORITHM3D
+#define _INC_ASTRA_CUDABACKPROJECTIONALGORITHM3D
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+
+#include "Float32ProjectionData3DMemory.h"
+#include "Float32VolumeData3DMemory.h"
+#include "ReconstructionAlgorithm3D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+class _AstraExport CCudaBackProjectionAlgorithm3D : public CReconstructionAlgorithm3D {
+
+protected:
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - the projector is compatible with both data objects
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, does not initialize the object.
+ */
+ CCudaBackProjectionAlgorithm3D();
+
+ /** Constructor with initialization.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object containing the projection data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ */
+ CCudaBackProjectionAlgorithm3D(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjectionData,
+ CFloat32VolumeData3DMemory* _pReconstruction);
+
+ /** Copy constructor.
+ */
+ CCudaBackProjectionAlgorithm3D(const CCudaBackProjectionAlgorithm3D&);
+
+ /** Destructor.
+ */
+ virtual ~CCudaBackProjectionAlgorithm3D();
+
+ /** Clear this class.
+ */
+/* virtual void clear();*/
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object containing the projection data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ * @return initialization successful?
+ */
+ bool initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /**
+ * Sets the index of the used GPU index: first GPU has index 0
+ *
+ * @param _iGPUIndex New GPU index.
+ */
+ void setGPUIndex(int _iGPUIndex);
+
+protected:
+
+ int m_iGPUIndex;
+ int m_iVoxelSuperSampling;
+
+};
+
+// inline functions
+inline std::string CCudaBackProjectionAlgorithm3D::description() const { return CCudaBackProjectionAlgorithm3D::type; };
+
+} // end namespace
+
+#endif
+
+#endif
diff --git a/include/astra/CudaCglsAlgorithm.h b/include/astra/CudaCglsAlgorithm.h
new file mode 100644
index 0000000..7734d6e
--- /dev/null
+++ b/include/astra/CudaCglsAlgorithm.h
@@ -0,0 +1,122 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDACGLSALGORITHM
+#define _INC_ASTRA_CUDACGLSALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "CudaReconstructionAlgorithm2D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains a GPU implementation of the CGLS algorithm.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, integer, Geometry of the projection data.}
+ * \astra_xml_item{VolumeGeometry, integer, Geometry of the volume data.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('CGLS_CUDA');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * cfg.ReconstructionDataId = recon_id;\n
+ * cfg.option.ReconstructionMaskId = mask_id;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('iterate'\, alg_id\, 10);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ */
+
+class AstraCGLS;
+
+class _AstraExport CCudaCglsAlgorithm : public CCudaReconstructionAlgorithm2D
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaCglsAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaCglsAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, use sequential order.
+ *
+ * @param _pProjector Projector Object. (Ignored)
+ * @param _pSinogram ProjectionData2D object containing the sinogram
+ * @param _pReconstruction VolumeData2D for storing the reconstruction
+ * @param _iGPUindex Index of GPU to use. (Starting at 0.)
+ * @param _iDetectorSuperSampling Supersampling factor for the FP.
+ * @param _iPixelSuperSampling Square root of number of samples per voxel, used to compute the backprojection
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex = 0, int _iDetectorSuperSampling = 1,
+ int _iPixelSuperSampling = 1);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+};
+
+// inline functions
+inline std::string CCudaCglsAlgorithm::description() const { return CCudaCglsAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaCglsAlgorithm3D.h b/include/astra/CudaCglsAlgorithm3D.h
new file mode 100644
index 0000000..47b61af
--- /dev/null
+++ b/include/astra/CudaCglsAlgorithm3D.h
@@ -0,0 +1,173 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDACGLSALGORITHM3D
+#define _INC_ASTRA_CUDACGLSALGORITHM3D
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+
+#include "Float32ProjectionData3DMemory.h"
+#include "Float32VolumeData3DMemory.h"
+#include "ReconstructionAlgorithm3D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+class AstraCGLS3d;
+
+/**
+ * \brief
+ * This class contains the 3D implementation of the CGLS algorithm
+ *
+ */
+class _AstraExport CCudaCglsAlgorithm3D : public CReconstructionAlgorithm3D {
+
+protected:
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - the projector is compatible with both data objects
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, does not initialize the object.
+ */
+ CCudaCglsAlgorithm3D();
+
+ /** Constructor with initialization.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object containing the projection data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ */
+ CCudaCglsAlgorithm3D(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjectionData,
+ CFloat32VolumeData3DMemory* _pReconstruction);
+
+ /** Copy constructor.
+ */
+ CCudaCglsAlgorithm3D(const CCudaCglsAlgorithm3D&);
+
+ /** Destructor.
+ */
+ virtual ~CCudaCglsAlgorithm3D();
+
+ /** Clear this class.
+ */
+/* virtual void clear();*/
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object containing the projection data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ * @return initialization successful?
+ */
+ bool initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /**
+ * Sets the index of the used GPU index: first GPU has index 0
+ *
+ * @param _iGPUIndex New GPU index.
+ */
+ void setGPUIndex(int _iGPUIndex);
+
+
+ virtual void signalAbort();
+
+ /** Get the norm of the residual image.
+ * Only a few algorithms support this method.
+ *
+ * @param _fNorm if supported, the norm is returned here
+ * @return true if this operation is supported
+ */
+ virtual bool getResidualNorm(float32& _fNorm);
+
+protected:
+
+ AstraCGLS3d* m_pCgls;
+
+ int m_iGPUIndex;
+ bool m_bAstraCGLSInit;
+ int m_iDetectorSuperSampling;
+ int m_iVoxelSuperSampling;
+};
+
+// inline functions
+inline std::string CCudaCglsAlgorithm3D::description() const { return CCudaCglsAlgorithm3D::type; };
+
+} // end namespace
+
+#endif
+
+#endif
diff --git a/include/astra/CudaDartMaskAlgorithm.h b/include/astra/CudaDartMaskAlgorithm.h
new file mode 100644
index 0000000..f370f42
--- /dev/null
+++ b/include/astra/CudaDartMaskAlgorithm.h
@@ -0,0 +1,126 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDADARTMASKALGORITHM
+#define _INC_ASTRA_CUDADARTMASKALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+#include "Algorithm.h"
+#include "Float32VolumeData2D.h"
+
+
+#ifdef ASTRA_CUDA
+
+namespace astraCUDA {
+class PDART;
+}
+
+namespace astra {
+
+ class _AstraExport CCudaDartMaskAlgorithm : public CAlgorithm
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaDartMaskAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaDartMaskAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, use sequential order.
+ *
+ * @param _pSegmentation ...
+ * @param iConn ...
+ */
+ //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+
+protected:
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ unsigned int m_iConn;
+ unsigned int m_iThreshold;
+ unsigned int m_iRadius;
+ int m_iGPUIndex;
+
+ CFloat32VolumeData2D* m_pSegmentation;
+ CFloat32VolumeData2D* m_pMask;
+
+};
+
+// inline functions
+inline std::string CCudaDartMaskAlgorithm::description() const { return CCudaDartMaskAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaDartMaskAlgorithm3D.h b/include/astra/CudaDartMaskAlgorithm3D.h
new file mode 100644
index 0000000..bdbce2b
--- /dev/null
+++ b/include/astra/CudaDartMaskAlgorithm3D.h
@@ -0,0 +1,122 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDADARTMASKALGORITHM3D
+#define _INC_ASTRA_CUDADARTMASKALGORITHM3D
+
+#include "Globals.h"
+#include "Config.h"
+#include "Algorithm.h"
+#include "Float32VolumeData3DMemory.h"
+
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+ class _AstraExport CCudaDartMaskAlgorithm3D : public CAlgorithm
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaDartMaskAlgorithm3D();
+
+ /** Destructor.
+ */
+ virtual ~CCudaDartMaskAlgorithm3D();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, use sequential order.
+ *
+ * @param _pSegmentation ...
+ * @param iConn ...
+ */
+ //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+
+protected:
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ unsigned int m_iConn;
+ unsigned int m_iThreshold;
+ unsigned int m_iRadius;
+ int m_iGPUIndex;
+
+ CFloat32VolumeData3DMemory* m_pSegmentation;
+ CFloat32VolumeData3DMemory* m_pMask;
+
+};
+
+// inline functions
+inline std::string CCudaDartMaskAlgorithm3D::description() const { return CCudaDartMaskAlgorithm3D::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaDartSmoothingAlgorithm.h b/include/astra/CudaDartSmoothingAlgorithm.h
new file mode 100644
index 0000000..f90f9cf
--- /dev/null
+++ b/include/astra/CudaDartSmoothingAlgorithm.h
@@ -0,0 +1,125 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDADARTSMOOTHINGALGORITHM
+#define _INC_ASTRA_CUDADARTSMOOTHINGALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+#include "Algorithm.h"
+#include "Float32VolumeData2D.h"
+
+
+#ifdef ASTRA_CUDA
+
+namespace astraCUDA {
+class PDART;
+}
+
+namespace astra {
+
+ class _AstraExport CCudaDartSmoothingAlgorithm : public CAlgorithm
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaDartSmoothingAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaDartSmoothingAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, use sequential order.
+ *
+ * @param _pSegmentation ...
+ * @param iConn ...
+ */
+ //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+
+protected:
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ float m_fB;
+ unsigned int m_iRadius;
+ int m_iGPUIndex;
+
+ CFloat32VolumeData2D* m_pIn;
+ CFloat32VolumeData2D* m_pOut;
+
+};
+
+// inline functions
+inline std::string CCudaDartSmoothingAlgorithm::description() const { return CCudaDartSmoothingAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaDartSmoothingAlgorithm3D.h b/include/astra/CudaDartSmoothingAlgorithm3D.h
new file mode 100644
index 0000000..9942de8
--- /dev/null
+++ b/include/astra/CudaDartSmoothingAlgorithm3D.h
@@ -0,0 +1,122 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDADARTSMOOTHINGALGORITHM3D
+#define _INC_ASTRA_CUDADARTSMOOTHINGALGORITHM3D
+
+#include "Globals.h"
+#include "Config.h"
+#include "Algorithm.h"
+#include "Float32VolumeData3DMemory.h"
+
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+ class _AstraExport CCudaDartSmoothingAlgorithm3D : public CAlgorithm
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaDartSmoothingAlgorithm3D();
+
+ /** Destructor.
+ */
+ virtual ~CCudaDartSmoothingAlgorithm3D();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, use sequential order.
+ *
+ * @param _pSegmentation ...
+ * @param iConn ...
+ */
+ //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+
+protected:
+
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ float m_fB;
+ unsigned int m_iRadius;
+ int m_iGPUIndex;
+
+ CFloat32VolumeData3DMemory* m_pIn;
+ CFloat32VolumeData3DMemory* m_pOut;
+
+};
+
+// inline functions
+inline std::string CCudaDartSmoothingAlgorithm3D::description() const { return CCudaDartSmoothingAlgorithm3D::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaDataOperationAlgorithm.h b/include/astra/CudaDataOperationAlgorithm.h
new file mode 100644
index 0000000..a5ab01a
--- /dev/null
+++ b/include/astra/CudaDataOperationAlgorithm.h
@@ -0,0 +1,128 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDADATAOPERATIONALGORITHM
+#define _INC_ASTRA_CUDADATAOPERATIONALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+#include "Algorithm.h"
+#include "Float32VolumeData2D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astraCUDA {
+class PDART;
+}
+
+namespace astra {
+
+ class _AstraExport CCudaDataOperationAlgorithm : public CAlgorithm
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaDataOperationAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaDataOperationAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, use sequential order.
+ *
+ * @param _pSegmentation ...
+ * @param iConn ...
+ */
+ //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+
+protected:
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+
+
+ int m_iGPUIndex;
+
+ CFloat32Data2D* m_pMask;
+
+ vector<CFloat32Data2D*> m_pData;
+ vector<float> m_fScalar;
+
+ string m_sOperation;
+
+};
+
+// inline functions
+inline std::string CCudaDataOperationAlgorithm::description() const { return CCudaDataOperationAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaEMAlgorithm.h b/include/astra/CudaEMAlgorithm.h
new file mode 100644
index 0000000..ff22dd4
--- /dev/null
+++ b/include/astra/CudaEMAlgorithm.h
@@ -0,0 +1,92 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDAEMALGORITHM
+#define _INC_ASTRA_CUDAEMALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "CudaReconstructionAlgorithm2D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+class _AstraExport CCudaEMAlgorithm : public CCudaReconstructionAlgorithm2D
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaEMAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaEMAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object. (Ignored)
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @param _iGPUindex GPU to use.
+ * @param _iDetectorSuperSampling Supersampling factor for the FP.
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex = 0, int _iDetectorSuperSampling = 1,
+ int _iPixelSuperSampling = 1);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+};
+
+// inline functions
+inline std::string CCudaEMAlgorithm::description() const { return CCudaEMAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaFDKAlgorithm3D.h b/include/astra/CudaFDKAlgorithm3D.h
new file mode 100644
index 0000000..7ab9bbe
--- /dev/null
+++ b/include/astra/CudaFDKAlgorithm3D.h
@@ -0,0 +1,164 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDAFDKALGORITHM3D
+#define _INC_ASTRA_CUDAFDKALGORITHM3D
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+
+#include "Float32ProjectionData3DMemory.h"
+#include "Float32VolumeData3DMemory.h"
+#include "ReconstructionAlgorithm3D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains the 3D implementation of the FDK algorithm.
+ *
+ * \par XML Configuration
+ *
+ * \par MATLAB example
+ * \astra_code{
+ *
+ * }
+ *
+ */
+class _AstraExport CCudaFDKAlgorithm3D : public CReconstructionAlgorithm3D {
+
+protected:
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - the projector is compatible with both data objects
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, does not initialize the object.
+ */
+ CCudaFDKAlgorithm3D();
+
+ /** Constructor with initialization.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object containing the projection data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ */
+ CCudaFDKAlgorithm3D(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjectionData,
+ CFloat32VolumeData3DMemory* _pReconstruction);
+
+ /** Copy constructor.
+ */
+ CCudaFDKAlgorithm3D(const CCudaFDKAlgorithm3D&);
+
+ /** Destructor.
+ */
+ virtual ~CCudaFDKAlgorithm3D();
+
+ /** Clear this class.
+ */
+/* virtual void clear();*/
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object containing the projection data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ * @return initialization successful?
+ */
+ bool initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /**
+ * Sets the index of the used GPU index: first GPU has index 0
+ *
+ * @param _iGPUIndex New GPU index.
+ */
+ void setGPUIndex(int _iGPUIndex);
+
+protected:
+
+ int m_iGPUIndex;
+ int m_iVoxelSuperSampling;
+ bool m_bShortScan;
+};
+
+// inline functions
+inline std::string CCudaFDKAlgorithm3D::description() const { return CCudaFDKAlgorithm3D::type; };
+
+} // end namespace
+
+#endif
+
+#endif
diff --git a/include/astra/CudaFilteredBackProjectionAlgorithm.h b/include/astra/CudaFilteredBackProjectionAlgorithm.h
new file mode 100644
index 0000000..4b7b904
--- /dev/null
+++ b/include/astra/CudaFilteredBackProjectionAlgorithm.h
@@ -0,0 +1,94 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef CUDAFILTEREDBACKPROJECTIONALGORITHM2_H
+#define CUDAFILTEREDBACKPROJECTIONALGORITHM2_H
+
+#include <astra/Float32ProjectionData2D.h>
+#include <astra/Float32VolumeData2D.h>
+#include <astra/ReconstructionAlgorithm2D.h>
+
+#include "../../cuda/2d/astra.h"
+
+namespace astra
+{
+
+class _AstraExport CCudaFilteredBackProjectionAlgorithm : public CReconstructionAlgorithm2D
+{
+public:
+ static std::string type;
+
+private:
+ CFloat32ProjectionData2D * m_pSinogram;
+ CFloat32VolumeData2D * m_pReconstruction;
+ int m_iGPUIndex;
+ int m_iPixelSuperSampling;
+ E_FBPFILTER m_eFilter;
+ float * m_pfFilter;
+ int m_iFilterWidth; // number of elements per projection direction in filter
+ float m_fFilterParameter; // some filters allow for parameterization (value < 0.0f -> no parameter)
+ float m_fFilterD; // frequency cut-off
+
+ static E_FBPFILTER _convertStringToFilter(const char * _filterType);
+
+public:
+ CCudaFilteredBackProjectionAlgorithm();
+ virtual ~CCudaFilteredBackProjectionAlgorithm();
+
+ virtual bool initialize(const Config& _cfg);
+ bool initialize(CFloat32ProjectionData2D * _pSinogram, CFloat32VolumeData2D * _pReconstruction, E_FBPFILTER _eFilter, const float * _pfFilter = NULL, int _iFilterWidth = 0, int _iGPUIndex = 0, float _fFilterParameter = -1.0f);
+
+ virtual void run(int _iNrIterations = 0);
+
+ static int calcIdealRealFilterWidth(int _iDetectorCount);
+ static int calcIdealFourierFilterWidth(int _iDetectorCount);
+
+ //debug
+ static void testGenFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount, cufftComplex * _pFilter, int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount);
+ static int getGPUCount();
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+protected:
+ bool check();
+
+ AstraFBP* m_pFBP;
+
+ bool m_bAstraFBPInit;
+};
+
+// inline functions
+inline std::string CCudaFilteredBackProjectionAlgorithm::description() const { return CCudaFilteredBackProjectionAlgorithm::type; };
+
+}
+
+#endif /* CUDAFILTEREDBACKPROJECTIONALGORITHM2_H */
diff --git a/include/astra/CudaForwardProjectionAlgorithm.h b/include/astra/CudaForwardProjectionAlgorithm.h
new file mode 100644
index 0000000..53b6c8e
--- /dev/null
+++ b/include/astra/CudaForwardProjectionAlgorithm.h
@@ -0,0 +1,169 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDAFORWARDPROJECTIONALGORITHM2
+#define _INC_ASTRA_CUDAFORWARDPROJECTIONALGORITHM2
+
+#include "Globals.h"
+
+#include "Algorithm.h"
+
+#include "ParallelProjectionGeometry2D.h"
+#include "VolumeGeometry2D.h"
+
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains a GPU implementation of an algorithm that creates a forward projection
+ * of a volume object and stores it into a sinogram.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{VolumeGeometry, integer, Geometry of the volume data.}
+ * \astra_xml_item{ProjectionGeometry, integer, Geometry of the projection data.}
+ * \astra_xml_item{VolumeDataId, integer, Identifier of the volume data object as it is stored in the DataManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of the resulting projection data object as it is stored in the DataManager.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('FP_CUDA2');\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeDataId = vol_id;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('run'\, alg_id);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ */
+class _AstraExport CCudaForwardProjectionAlgorithm : public CAlgorithm
+{
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaForwardProjectionAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaForwardProjectionAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pVolumeGeometry Geometry of the volume.
+ * @param _pProjectionGeometry Geometry of the projection.
+ * @param _pVolume VolumeData2D object containing the phantom to compute sinogram from
+ * @param _pSinogram ProjectionData2D object to store sinogram data in.
+ * @param _iGPUindex Index of GPU to use. (Starting at 0.)
+ * @param _iDetectorSuperSampling Number of samples per detector element, used to compute the forward projection
+ * @return success
+ */
+ bool initialize(CProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry,
+ CFloat32VolumeData2D* _pVolume,
+ CFloat32ProjectionData2D* _pSinogram,
+ int _iGPUindex = 0, int _iDetectorSuperSampling = 1);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool check();
+
+ CFloat32VolumeData2D* getVolume() { return m_pVolume; }
+ CFloat32ProjectionData2D* getSinogram() { return m_pSinogram; }
+
+ /**
+ * Sets the index of the used GPU index: first GPU has index 0
+ *
+ * @param _iGPUIndex New GPU index.
+ */
+ void setGPUIndex(int _iGPUIndex);
+
+protected:
+ //< ProjectionData2D object containing the sinogram.
+ CFloat32ProjectionData2D* m_pSinogram;
+ //< VolumeData2D object containing the phantom.
+ CFloat32VolumeData2D* m_pVolume;
+
+ //< Index of GPU to use
+ int m_iGPUIndex;
+ //< Number of rays per detector element
+ int m_iDetectorSuperSampling;
+
+};
+
+// inline functions
+inline std::string CCudaForwardProjectionAlgorithm::description() const { return CCudaForwardProjectionAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaForwardProjectionAlgorithm3D.h b/include/astra/CudaForwardProjectionAlgorithm3D.h
new file mode 100644
index 0000000..72c6a00
--- /dev/null
+++ b/include/astra/CudaForwardProjectionAlgorithm3D.h
@@ -0,0 +1,135 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDAFORWARDPROJECTIONALGORITHM3D
+#define _INC_ASTRA_CUDAFORWARDPROJECTIONALGORITHM3D
+
+#include "Globals.h"
+
+#include "Algorithm.h"
+
+#include "Float32ProjectionData3DMemory.h"
+#include "Float32VolumeData3DMemory.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+class CProjector3D;
+
+class _AstraExport CCudaForwardProjectionAlgorithm3D : public CAlgorithm
+{
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaForwardProjectionAlgorithm3D();
+
+ /** Destructor.
+ */
+ virtual ~CCudaForwardProjectionAlgorithm3D();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object for storing the projection data.
+ * @param _pReconstruction VolumeData3D object containing the volume.
+ * @return initialization successful?
+ */
+ bool initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction,
+ int _iGPUindex = 0, int _iDetectorSuperSampling = 1);
+
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool check();
+
+ /**
+ * Sets the index of the used GPU index: first GPU has index 0
+ *
+ * @param _iGPUIndex New GPU index.
+ */
+ void setGPUIndex(int _iGPUIndex);
+
+protected:
+ CProjector3D* m_pProjector;
+ CFloat32ProjectionData3DMemory* m_pProjections;
+ CFloat32VolumeData3DMemory* m_pVolume;
+ int m_iGPUIndex;
+ int m_iDetectorSuperSampling;
+
+};
+
+// inline functions
+inline std::string CCudaForwardProjectionAlgorithm3D::description() const { return CCudaForwardProjectionAlgorithm3D::type; };
+
+
+}
+
+#endif
+
+#endif
diff --git a/include/astra/CudaProjector2D.h b/include/astra/CudaProjector2D.h
new file mode 100644
index 0000000..073b299
--- /dev/null
+++ b/include/astra/CudaProjector2D.h
@@ -0,0 +1,122 @@
+/*
+-----------------------------------------------------------------------
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+
+Copyright: IBBT-Vision Lab, University of Antwerp
+Contact: mailto:wim.vanaarle@ua.ac.be
+Website: http://astra.ua.ac.be
+-----------------------------------------------------------------------
+$Id$
+*/
+#ifndef _INC_ASTRA_CUDAPROJECTOR2D
+#define _INC_ASTRA_CUDAPROJECTOR2D
+
+#include "ParallelProjectionGeometry2D.h"
+#include "Float32Data2D.h"
+#include "Projector2D.h"
+#include "../../cuda/2d/astra.h"
+
+namespace astra
+{
+
+
+/** This is a two-dimensional CUDA-projector.
+ * It is essentially a fake projector, containing settings relevant for the
+ * actual CUDA code.
+ */
+class _AstraExport CCudaProjector2D : public CProjector2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - blobvalues are ok
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /** Default constructor.
+ */
+ CCudaProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ */
+ CCudaProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ ~CCudaProjector2D();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+
+ virtual int getProjectionWeightsCount(int _iProjectionIndex) { return 0; }
+
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount) {}
+
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol)
+ { std::vector<SDetector2D> x; return x; }
+
+ template <typename Policy>
+ void project(Policy& _policy) {}
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy) {}
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy) {}
+
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType();
+
+ /** get a description of the class
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+
+protected:
+
+ Cuda2DProjectionKernel m_projectionKernel;
+};
+
+//----------------------------------------------------------------------------------------
+
+inline std::string CCudaProjector2D::getType()
+{
+ return type;
+}
+
+} // namespace astra
+
+#endif
+
diff --git a/include/astra/CudaProjector3D.h b/include/astra/CudaProjector3D.h
new file mode 100644
index 0000000..66071f0
--- /dev/null
+++ b/include/astra/CudaProjector3D.h
@@ -0,0 +1,131 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef INC_ASTRA_CUDAPROJECTOR3D
+#define INC_ASTRA_CUDAPROJECTOR3D
+
+#ifdef ASTRA_CUDA
+
+#include <cmath>
+#include <vector>
+
+#include "Globals.h"
+#include "Config.h"
+#include "Projector3D.h"
+#include "../../cuda/3d/astra3d.h"
+
+namespace astra
+{
+
+/** This is a three-dimensional CUDA-projector.
+ * It is essentially a fake projector, containing settings relevant for the
+ * actual CUDA code.
+ */
+class _AstraExport CCudaProjector3D : public CProjector3D
+{
+
+protected:
+
+ /** Check variable values.
+ */
+ bool _check();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ * Should only be used by constructors. Otherwise use the clear() function.
+ */
+ void _clear();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /**
+ * Default Constructor.
+ */
+ CCudaProjector3D();
+
+ /** Destructor, is virtual to show that we are aware subclass destructor is called.
+ */
+ virtual ~CCudaProjector3D();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ */
+ void clear();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iSliceIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount) {}
+ virtual int getProjectionWeightsCount(int _iProjectionIndex) { return 0; }
+ template <typename Policy>
+ void project(Policy& _policy) {}
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy) {}
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iSlice, int _iDetector, Policy& _policy) {}
+
+
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType() { return type; }
+
+ /** get a description of the class
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+
+ Cuda3DProjectionKernel getProjectionKernel() const { return m_projectionKernel; }
+
+protected:
+
+ Cuda3DProjectionKernel m_projectionKernel;
+
+
+};
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
+
+#endif /* INC_ASTRA_CUDAPROJECTOR3D */
diff --git a/include/astra/CudaReconstructionAlgorithm2D.h b/include/astra/CudaReconstructionAlgorithm2D.h
new file mode 100644
index 0000000..88fc344
--- /dev/null
+++ b/include/astra/CudaReconstructionAlgorithm2D.h
@@ -0,0 +1,176 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDARECONSTRUCTIONALGORITHM2D
+#define _INC_ASTRA_CUDARECONSTRUCTIONALGORITHM2D
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "ReconstructionAlgorithm2D.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+namespace astraCUDA {
+class ReconAlgo;
+}
+
+namespace astra {
+
+/**
+ * This is a base class for the different CUDA implementations of 2D reconstruction algorithms.
+ * They don't use a Projector, and share GPUIndex and DetectorSuperSampling options.
+ *
+ */
+class _AstraExport CCudaReconstructionAlgorithm2D : public CReconstructionAlgorithm2D {
+
+public:
+
+ /** Default constructor, containing no code.
+ */
+ CCudaReconstructionAlgorithm2D();
+
+ /** Destructor.
+ */
+ virtual ~CCudaReconstructionAlgorithm2D();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object. (Ignored)
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object. (Ignored)
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @param _iGPUindex GPU to use.
+ * @param _iDetectorSuperSampling Supersampling factor for the FP.
+ * @param _iPixelSuperSampling Square root of number of samples per voxel, used to compute the backprojection
+ */
+ virtual bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex = 0, int _iDetectorSuperSampling = 1,
+ int _iPixelSuperSampling = 1);
+
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Get all information parameters.
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information.
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Get the norm of the residual image.
+ * Only a few algorithms support this method.
+ *
+ * @param _fNorm if supported, the norm is returned here
+ * @return true if this operation is supported
+ */
+ virtual bool getResidualNorm(float32& _fNorm);
+
+ /**
+ * Sets the index of the used GPU index: first GPU has index 0
+ *
+ * @param _iGPUIndex New GPU index.
+ */
+ void setGPUIndex(int _iGPUIndex);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ virtual void signalAbort();
+
+protected:
+
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ void _clear();
+
+ /** Set up geometry. For internal use only.
+ */
+ bool setupGeometry();
+
+
+ /** The internally used CUDA algorithm object
+ */
+ astraCUDA::ReconAlgo *m_pAlgo;
+
+ int m_iDetectorSuperSampling;
+ int m_iPixelSuperSampling;
+ int m_iGPUIndex;
+
+ bool m_bAlgoInit;
+};
+
+// inline functions
+inline std::string CCudaReconstructionAlgorithm2D::description() const { return "2D CUDA Reconstruction Algorithm"; };
+
+} // end namespace
+
+#endif
diff --git a/include/astra/CudaRoiSelectAlgorithm.h b/include/astra/CudaRoiSelectAlgorithm.h
new file mode 100644
index 0000000..1ee9c32
--- /dev/null
+++ b/include/astra/CudaRoiSelectAlgorithm.h
@@ -0,0 +1,123 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDAROISELECTALGORITHM
+#define _INC_ASTRA_CUDAROISELECTALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+#include "Algorithm.h"
+#include "Float32VolumeData2D.h"
+
+
+#ifdef ASTRA_CUDA
+
+namespace astraCUDA {
+class PDART;
+}
+
+namespace astra {
+
+ class _AstraExport CCudaRoiSelectAlgorithm : public CAlgorithm
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaRoiSelectAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaRoiSelectAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, use sequential order.
+ *
+ * @param _pSegmentation ...
+ * @param iConn ...
+ */
+ //bool initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+
+protected:
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ float32 m_fRadius;
+ int m_iGPUIndex;
+
+ CFloat32VolumeData2D* m_pData;
+
+};
+
+// inline functions
+inline std::string CCudaRoiSelectAlgorithm::description() const { return CCudaRoiSelectAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaSartAlgorithm.h b/include/astra/CudaSartAlgorithm.h
new file mode 100644
index 0000000..319e1e9
--- /dev/null
+++ b/include/astra/CudaSartAlgorithm.h
@@ -0,0 +1,112 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDASARTALGORITHM
+#define _INC_ASTRA_CUDASARTALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "CudaReconstructionAlgorithm2D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains a GPU implementation of the SART algorithm.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('SART_CUDA');\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * cfg.ReconstructionDataId = recon_id;\n
+ * cfg.option.ReconstructionMaskId = mask_id;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('iterate'\, alg_id\, 10);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ */
+class _AstraExport CCudaSartAlgorithm : public CCudaReconstructionAlgorithm2D
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaSartAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaSartAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object. (Ignored)
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @param _iGPUindex GPU to use.
+ * @param _iDetectorSuperSampling Supersampling factor for the FP.
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex = 0, int _iDetectorSuperSampling = 1);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+};
+
+// inline functions
+inline std::string CCudaSartAlgorithm::description() const { return CCudaSartAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaSirtAlgorithm.h b/include/astra/CudaSirtAlgorithm.h
new file mode 100644
index 0000000..7f3d67b
--- /dev/null
+++ b/include/astra/CudaSirtAlgorithm.h
@@ -0,0 +1,131 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDASIRTALGORITHM2
+#define _INC_ASTRA_CUDASIRTALGORITHM2
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "CudaReconstructionAlgorithm2D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains a GPU implementation of the SIRT (Simultaneous Iterative Reconstruction Technique) algorithm.
+ *
+ * The update step of pixel \f$v_j\f$ for iteration \f$k\f$ is given by:
+ * \f[
+ * v_j^{(k+1)} = v_j^{(k)} + \alpha \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}}
+ * \f]
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, integer, Geometry of the projection data.}
+ * \astra_xml_item{VolumeGeometry, integer, Geometry of the volume data.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('SIRT_CUDA2');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * cfg.ReconstructionDataId = recon_id;\n
+ * cfg.option.ReconstructionMaskId = mask_id;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('iterate'\, alg_id\, 10);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ * \par References
+ * [1] "Computational Analysis and Improvement of SIRT", J. Gregor, T. Benson, IEEE Transactions on Medical Imaging, Vol. 22, No. 7, July 2008.
+ */
+class _AstraExport CCudaSirtAlgorithm : public CCudaReconstructionAlgorithm2D
+{
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CCudaSirtAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CCudaSirtAlgorithm();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ virtual void run(int _iNrIterations);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object. (Ignored)
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @param _iGPUindex GPU to use.
+ * @param _iDetectorSuperSampling Supersampling factor for the FP.
+ * @param _iPixelSuperSampling Square root of number of samples per voxel, used to compute the backprojection
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex = 0, int _iDetectorSuperSampling = 1,
+ int _iPixelSuperSampling = 1);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+protected:
+ CFloat32VolumeData2D* m_pMinMask;
+ CFloat32VolumeData2D* m_pMaxMask;
+};
+
+// inline functions
+inline std::string CCudaSirtAlgorithm::description() const { return CCudaSirtAlgorithm::type; };
+
+} // end namespace
+
+#endif // ASTRA_CUDA
+
+#endif
diff --git a/include/astra/CudaSirtAlgorithm3D.h b/include/astra/CudaSirtAlgorithm3D.h
new file mode 100644
index 0000000..c2c794d
--- /dev/null
+++ b/include/astra/CudaSirtAlgorithm3D.h
@@ -0,0 +1,187 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_CUDASIRTALGORITHM3D
+#define _INC_ASTRA_CUDASIRTALGORITHM3D
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+
+#include "Float32ProjectionData3DMemory.h"
+#include "Float32VolumeData3DMemory.h"
+#include "ReconstructionAlgorithm3D.h"
+
+#ifdef ASTRA_CUDA
+
+namespace astra {
+
+class AstraSIRT3d;
+
+/**
+ * \brief
+ * This class contains the 3D implementation of the SIRT (Simultaneous Iterative Reconstruction Technique) algorithm.
+ *
+ * The update step of pixel \f$v_j\f$ for iteration \f$k\f$ is given by:
+ * \f[
+ * v_j^{(k+1)} = v_j^{(k)} + \alpha \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}}
+ * \f]
+ *
+ * \par XML Configuration
+ *
+ * \par MATLAB example
+ * \astra_code{
+ *
+ * }
+ *
+ * \par References
+ * [1] "Computational Analysis and Improvement of SIRT", J. Gregor, T. Benson, IEEE Transactions on Medical Imaging, Vol. 22, No. 7, July 2008.
+ */
+class _AstraExport CCudaSirtAlgorithm3D : public CReconstructionAlgorithm3D {
+
+protected:
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - the projector is compatible with both data objects
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, does not initialize the object.
+ */
+ CCudaSirtAlgorithm3D();
+
+ /** Constructor with initialization.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object containing the projection data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ */
+ CCudaSirtAlgorithm3D(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjectionData,
+ CFloat32VolumeData3DMemory* _pReconstruction);
+
+ /** Copy constructor.
+ */
+ CCudaSirtAlgorithm3D(const CCudaSirtAlgorithm3D&);
+
+ /** Destructor.
+ */
+ virtual ~CCudaSirtAlgorithm3D();
+
+ /** Clear this class.
+ */
+/* virtual void clear();*/
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pProjectionData ProjectionData3D object containing the projection data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ * @return initialization successful?
+ */
+ bool initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /**
+ * Sets the index of the used GPU index: first GPU has index 0
+ *
+ * @param _iGPUIndex New GPU index.
+ */
+ void setGPUIndex(int _iGPUIndex);
+
+
+ virtual void signalAbort();
+
+ /** Get the norm of the residual image.
+ * Only a few algorithms support this method.
+ *
+ * @param _fNorm if supported, the norm is returned here
+ * @return true if this operation is supported
+ */
+ virtual bool getResidualNorm(float32& _fNorm);
+
+protected:
+
+ AstraSIRT3d* m_pSirt;
+
+ int m_iGPUIndex;
+ bool m_bAstraSIRTInit;
+ int m_iDetectorSuperSampling;
+ int m_iVoxelSuperSampling;
+};
+
+// inline functions
+inline std::string CCudaSirtAlgorithm3D::description() const { return CCudaSirtAlgorithm3D::type; };
+
+} // end namespace
+
+#endif
+
+#endif
diff --git a/include/astra/DataProjector.h b/include/astra/DataProjector.h
new file mode 100644
index 0000000..a324625
--- /dev/null
+++ b/include/astra/DataProjector.h
@@ -0,0 +1,327 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_DATAPROJECTOR
+#define _INC_ASTRA_DATAPROJECTOR
+
+#include "Projector2D.h"
+
+#include "TypeList.h"
+
+#include "ProjectorTypelist.h"
+
+#include "DataProjectorPolicies.h"
+
+namespace astra
+{
+
+
+/**
+ * Interface class for the Data Projector. The sole purpose of this class is to force child classes to implement a series of methods
+ */
+class CDataProjectorInterface {
+public:
+ CDataProjectorInterface() { }
+ virtual ~CDataProjectorInterface() { }
+ virtual void project() = 0;
+ virtual void projectSingleProjection(int _iProjection) = 0;
+ virtual void projectSingleRay(int _iProjection, int _iDetector) = 0;
+// virtual void projectSingleVoxel(int _iRow, int _iCol) = 0;
+// virtual void projectAllVoxels() = 0;
+};
+
+/**
+ * Templated Data Projector Class. In this class a specific projector and policies are combined.
+ */
+template <typename Projector, typename Policy>
+class CDataProjector: public CDataProjectorInterface {
+
+private:
+
+ Projector* m_pProjector;
+ Policy m_pPolicy;
+
+public:
+
+ CDataProjector() {};
+
+ CDataProjector(Projector* _p, Policy _a);
+ ~CDataProjector();
+
+ virtual void project();
+
+ virtual void projectSingleProjection(int _iProjection);
+
+ virtual void projectSingleRay(int _iProjection, int _iDetector);
+
+// virtual void projectSingleVoxel(int _iRow, int _iCol);
+
+// virtual void projectAllVoxels();
+};
+
+//----------------------------------------------------------------------------------------
+/**
+ * Constructor
+*/
+template <typename Projector, typename Policy>
+CDataProjector<Projector,Policy>::CDataProjector(Projector* _p, Policy _a)
+{
+ m_pProjector = _p;
+ m_pPolicy = _a;
+}
+
+//----------------------------------------------------------------------------------------
+/**
+ * Destructor
+*/
+template <typename Projector, typename Policy>
+CDataProjector<Projector,Policy>::~CDataProjector()
+{
+ // does nothing
+}
+
+//----------------------------------------------------------------------------------------
+/**
+ * Compute projection using the algorithm specific to the projector type
+*/
+template <typename Projector, typename Policy>
+void CDataProjector<Projector,Policy>::project()
+{
+ m_pProjector->project(m_pPolicy);
+}
+
+//----------------------------------------------------------------------------------------
+/**
+ * Compute just one projection using the algorithm specific to the projector type
+*/
+template <typename Projector, typename Policy>
+void CDataProjector<Projector,Policy>::projectSingleProjection(int _iProjection)
+{
+ m_pProjector->projectSingleProjection(_iProjection, m_pPolicy);
+}
+
+//----------------------------------------------------------------------------------------
+/**
+ * Compute projection of one ray using the algorithm specific to the projector type
+*/
+template <typename Projector, typename Policy>
+void CDataProjector<Projector,Policy>::projectSingleRay(int _iProjection, int _iDetector)
+{
+ m_pProjector->projectSingleRay(_iProjection, _iDetector, m_pPolicy);
+}
+
+//----------------------------------------------------------------------------------------
+//template <typename Projector, typename Policy>
+//void CDataProjector<Projector,Policy>::projectSingleVoxel(int _iRow, int _iCol)
+//{
+// m_pProjector->projectSingleVoxel(_iRow, _iCol, m_pPolicy);
+//}
+
+//----------------------------------------------------------------------------------------
+//template <typename Projector, typename Policy>
+//void CDataProjector<Projector,Policy>::projectAllVoxels()
+//{
+// m_pProjector->projectAllVoxels(m_pPolicy);
+//}
+//----------------------------------------------------------------------------------------
+
+
+
+
+//-----------------------------------------------------------------------------------------
+// Create a new datainterface from the projector TypeList
+namespace typelist {
+ template <class TList>
+ struct CreateDataProjector {
+ template <class U, typename Policy>
+ static void find (U& functor, CProjector2D* _pProjector, const Policy& _pPolicy) {
+ if (functor(TList::Head::type)) {
+ functor.res = new CDataProjector<typename TList::Head, Policy>(static_cast<typename TList::Head*>(_pProjector), _pPolicy);
+ }
+ CreateDataProjector<typename TList::Tail>::find(functor, _pProjector, _pPolicy);
+ }
+ };
+ template <>
+ struct CreateDataProjector<NullType> {
+ template <class U, typename Policy>
+ static void find(U& functor, CProjector2D* _pProjector, const Policy& _pPolicy) {}
+ };
+
+ struct functor_find_datainterface {
+ functor_find_datainterface() { res = NULL; }
+ bool operator() (std::string name) {
+ return strcmp(tofind.c_str(), name.c_str()) == 0;
+ }
+ std::string tofind;
+ CDataProjectorInterface* res;
+ };
+}
+//-----------------------------------------------------------------------------------------
+
+/**
+ * Data Projector Dispatcher - 1 Policy
+ */
+template <typename Policy>
+static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector, const Policy& _policy)
+{
+ typelist::functor_find_datainterface finder = typelist::functor_find_datainterface();
+ finder.tofind = _pProjector->getType();
+ typelist::CreateDataProjector<Projector2DTypeList>::find(finder, _pProjector, _policy);
+ return finder.res;
+}
+
+
+
+/**
+ * Data Projector Dispatcher - 2 Policies
+ */
+template <typename Policy1, typename Policy2>
+static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector,
+ const Policy1& _policy,
+ const Policy2& _policy2,
+ bool _bUsePolicy1 = true,
+ bool _bUsePolicy2 = true)
+{
+ if (!_bUsePolicy1 && !_bUsePolicy2) {
+ return dispatchDataProjector(_pProjector, EmptyPolicy());
+ } else if (!_bUsePolicy1) {
+ return dispatchDataProjector(_pProjector, _policy2);
+ } else if (!_bUsePolicy2) {
+ return dispatchDataProjector(_pProjector, _policy);
+ } else {
+ return dispatchDataProjector(_pProjector, CombinePolicy<Policy1, Policy2>(_policy, _policy2));
+ }
+
+}
+
+/**
+ * Data Projector Dispatcher - 3 Policies
+ */
+
+template <typename Policy1, typename Policy2, typename Policy3>
+static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector,
+ const Policy1& _policy1,
+ const Policy2& _policy2,
+ const Policy3& _policy3,
+ bool _bUsePolicy1 = true,
+ bool _bUsePolicy2 = true,
+ bool _bUsePolicy3 = true)
+{
+ if (!_bUsePolicy1) {
+ return dispatchDataProjector(_pProjector, _policy2, _policy3, _bUsePolicy2, _bUsePolicy3);
+ } else if (!_bUsePolicy2) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy3, _bUsePolicy1, _bUsePolicy3);
+ } else if (!_bUsePolicy3) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy2, _bUsePolicy1, _bUsePolicy2);
+ } else {
+ return dispatchDataProjector(_pProjector, Combine3Policy<Policy1, Policy2, Policy3>(_policy1, _policy2, _policy3));
+ }
+}
+
+/**
+ * Data Projector Dispatcher - 4 Policies
+ */
+template <typename Policy1, typename Policy2, typename Policy3, typename Policy4>
+static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector,
+ const Policy1& _policy1,
+ const Policy2& _policy2,
+ const Policy3& _policy3,
+ const Policy4& _policy4,
+ bool _bUsePolicy1 = true,
+ bool _bUsePolicy2 = true,
+ bool _bUsePolicy3 = true,
+ bool _bUsePolicy4 = true)
+{
+ if (!_bUsePolicy1) {
+ return dispatchDataProjector(_pProjector, _policy2, _policy3, _policy4, _bUsePolicy2, _bUsePolicy3, _bUsePolicy4);
+ } else if (!_bUsePolicy2) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy3, _policy4, _bUsePolicy1, _bUsePolicy3, _bUsePolicy4);
+ } else if (!_bUsePolicy3) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy4, _bUsePolicy1, _bUsePolicy2, _bUsePolicy4);
+ } else if (!_bUsePolicy4) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy3, _bUsePolicy1, _bUsePolicy2, _bUsePolicy3);
+ } else {
+ return dispatchDataProjector(_pProjector, Combine4Policy<Policy1, Policy2, Policy3, Policy4>(_policy1, _policy2, _policy3, _policy4));
+ }
+}
+
+/**
+ * Data Projector Dispatcher - 5 Policies
+ */
+template <typename Policy1, typename Policy2, typename Policy3, typename Policy4, typename Policy5>
+static CDataProjectorInterface* dispatchDataProjector(CProjector2D* _pProjector,
+ const Policy1& _policy1,
+ const Policy2& _policy2,
+ const Policy3& _policy3,
+ const Policy4& _policy4,
+ const Policy5& _policy5,
+ bool _bUsePolicy1 = true,
+ bool _bUsePolicy2 = true,
+ bool _bUsePolicy3 = true,
+ bool _bUsePolicy4 = true,
+ bool _bUsePolicy5 = true)
+{
+ if (!_bUsePolicy1) {
+ return dispatchDataProjector(_pProjector, _policy2, _policy3, _policy4, _policy5, _bUsePolicy2, _bUsePolicy3, _bUsePolicy4, _bUsePolicy5);
+ } else if (!_bUsePolicy2) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy3, _policy4, _policy5, _bUsePolicy1, _bUsePolicy3, _bUsePolicy4, _bUsePolicy5);
+ } else if (!_bUsePolicy3) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy4, _policy5, _bUsePolicy1, _bUsePolicy2, _bUsePolicy4, _bUsePolicy5);
+ } else if (!_bUsePolicy4) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy3, _policy5, _bUsePolicy1, _bUsePolicy2, _bUsePolicy3, _bUsePolicy5);
+ } else if (!_bUsePolicy5) {
+ return dispatchDataProjector(_pProjector, _policy1, _policy2, _policy3, _policy4, _bUsePolicy1, _bUsePolicy2, _bUsePolicy3, _bUsePolicy4);
+ } else {
+ return dispatchDataProjector(_pProjector, CombinePolicy< Combine4Policy<Policy1, Policy2, Policy3, Policy4>, Policy5>(
+ Combine4Policy<Policy1, Policy2, Policy3, Policy4>(_policy1, _policy2, _policy3, _policy4),
+ _policy5)
+ );
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * Data Projector Project
+ */
+template <typename Policy>
+static void projectData(CProjector2D* _pProjector, const Policy& _policy)
+{
+ CDataProjectorInterface* dp = dispatchDataProjector(_pProjector, _policy);
+ dp->project();
+ delete dp;
+}
+
+
+
+
+} // namespace astra
+
+#endif
diff --git a/include/astra/DataProjectorPolicies.h b/include/astra/DataProjectorPolicies.h
new file mode 100644
index 0000000..5ec08bd
--- /dev/null
+++ b/include/astra/DataProjectorPolicies.h
@@ -0,0 +1,382 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_DATAPROJECTORPOLICIES
+#define _INC_ASTRA_DATAPROJECTORPOLICIES
+
+#include "Globals.h"
+#include "Config.h"
+
+#include <list>
+
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+namespace astra {
+
+//enum {PixelDrivenPolicy, RayDrivenPolicy, AllPolicy} PolicyType;
+
+
+//----------------------------------------------------------------------------------------
+/** Policy for Default Forward Projection (Ray Driven)
+ */
+class DefaultFPPolicy {
+
+ //< Projection Data
+ CFloat32ProjectionData2D* m_pProjectionData;
+ //< Volume Data
+ CFloat32VolumeData2D* m_pVolumeData;
+
+public:
+ FORCEINLINE DefaultFPPolicy();
+ FORCEINLINE DefaultFPPolicy(CFloat32VolumeData2D* _pVolumeData, CFloat32ProjectionData2D* _pProjectionData);
+ FORCEINLINE ~DefaultFPPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+
+//----------------------------------------------------------------------------------------
+/** Policy for Default Back Projection. (Ray+Pixel Driven)
+ * This does VolumeData += transpose(ProjectionMap) * ProjectionData.
+ */
+class DefaultBPPolicy {
+
+ //< Projection Data
+ CFloat32ProjectionData2D* m_pProjectionData;
+ //< Volume Data
+ CFloat32VolumeData2D* m_pVolumeData;
+
+public:
+ FORCEINLINE DefaultBPPolicy();
+ FORCEINLINE DefaultBPPolicy(CFloat32VolumeData2D* _pVolumeData, CFloat32ProjectionData2D* _pProjectionData);
+ FORCEINLINE ~DefaultBPPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+
+
+//----------------------------------------------------------------------------------------
+/** Policy For Calculating the Projection Difference between Volume Data and Projection Data (Ray Driven)
+ */
+class DiffFPPolicy {
+
+ CFloat32ProjectionData2D* m_pDiffProjectionData;
+ CFloat32ProjectionData2D* m_pBaseProjectionData;
+ CFloat32VolumeData2D* m_pVolumeData;
+public:
+
+ FORCEINLINE DiffFPPolicy();
+ FORCEINLINE DiffFPPolicy(CFloat32VolumeData2D* _vol_data, CFloat32ProjectionData2D* _proj_data, CFloat32ProjectionData2D* _proj_data_base);
+ FORCEINLINE ~DiffFPPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Store Pixel Weights (Ray+Pixel Driven)
+ */
+class StorePixelWeightsPolicy {
+
+ SPixelWeight* m_pPixelWeights;
+ int m_iMaxPixelCount;
+ int m_iStoredPixelCount;
+
+public:
+
+ FORCEINLINE StorePixelWeightsPolicy();
+ FORCEINLINE StorePixelWeightsPolicy(SPixelWeight* _pPixelWeights, int _iMaxPixelCount);
+ FORCEINLINE ~StorePixelWeightsPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+
+ FORCEINLINE int getStoredPixelCount();
+};
+
+
+//----------------------------------------------------------------------------------------
+/** Policy For Calculating the Total Pixel Weight Multiplied by Sinogram
+ */
+class TotalPixelWeightBySinogramPolicy {
+
+ CFloat32VolumeData2D* m_pPixelWeight;
+ CFloat32ProjectionData2D* m_pSinogram;
+
+public:
+
+ FORCEINLINE TotalPixelWeightBySinogramPolicy();
+ FORCEINLINE TotalPixelWeightBySinogramPolicy(CFloat32ProjectionData2D* _pSinogram, CFloat32VolumeData2D* _pPixelWeight);
+ FORCEINLINE ~TotalPixelWeightBySinogramPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Policy For Calculating the Total Pixel Weight
+ */
+class TotalPixelWeightPolicy {
+
+ CFloat32VolumeData2D* m_pPixelWeight;
+
+public:
+
+ FORCEINLINE TotalPixelWeightPolicy();
+ FORCEINLINE TotalPixelWeightPolicy(CFloat32VolumeData2D* _pPixelWeight);
+ FORCEINLINE ~TotalPixelWeightPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Policy For Calculating the the Total Ray Length
+ */
+class TotalRayLengthPolicy {
+
+ CFloat32ProjectionData2D* m_pRayLength;
+
+public:
+
+ FORCEINLINE TotalRayLengthPolicy();
+ FORCEINLINE TotalRayLengthPolicy(CFloat32ProjectionData2D* _pRayLength);
+ FORCEINLINE ~TotalRayLengthPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+
+//----------------------------------------------------------------------------------------
+/** Policy For Combining Two Policies
+ */
+template<typename P1, typename P2>
+class CombinePolicy {
+
+ P1 policy1;
+ P2 policy2;
+
+public:
+
+ FORCEINLINE CombinePolicy();
+ FORCEINLINE CombinePolicy(P1 _policy1, P2 _policy2);
+ FORCEINLINE ~CombinePolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Policy For Combining Three Policies
+ */
+template<typename P1, typename P2, typename P3>
+class Combine3Policy {
+
+ P1 policy1;
+ P2 policy2;
+ P3 policy3;
+
+public:
+
+ FORCEINLINE Combine3Policy();
+ FORCEINLINE Combine3Policy(P1 _policy1, P2 _policy2, P3 _policy3);
+ FORCEINLINE ~Combine3Policy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Policy For Combining Four Policies
+ */
+template<typename P1, typename P2, typename P3, typename P4>
+class Combine4Policy {
+
+ P1 policy1;
+ P2 policy2;
+ P3 policy3;
+ P4 policy4;
+
+public:
+
+ FORCEINLINE Combine4Policy();
+ FORCEINLINE Combine4Policy(P1 _policy1, P2 _policy2, P3 _policy3, P4 _policy4);
+ FORCEINLINE ~Combine4Policy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Policy For Combining a List of the same Policies
+ */
+template<typename P>
+class CombineListPolicy {
+
+ std::vector<P> policyList;
+ unsigned int size;
+
+public:
+
+ FORCEINLINE CombineListPolicy();
+ FORCEINLINE CombineListPolicy(std::vector<P> _policyList);
+ FORCEINLINE ~CombineListPolicy();
+
+ FORCEINLINE void addPolicy(P _policy);
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Empty Policy
+ */
+class EmptyPolicy {
+
+public:
+
+ FORCEINLINE EmptyPolicy();
+ FORCEINLINE ~EmptyPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Policy For SIRT Backprojection
+ */
+class SIRTBPPolicy {
+
+ CFloat32ProjectionData2D* m_pSinogram;
+ CFloat32VolumeData2D* m_pReconstruction;
+
+ CFloat32ProjectionData2D* m_pTotalRayLength;
+ CFloat32VolumeData2D* m_pTotalPixelWeight;
+
+public:
+
+ FORCEINLINE SIRTBPPolicy();
+ FORCEINLINE SIRTBPPolicy(CFloat32VolumeData2D* _pReconstruction, CFloat32ProjectionData2D* _pSinogram, CFloat32VolumeData2D* _pTotalPixelWeight, CFloat32ProjectionData2D* _pTotalRayLength);
+ FORCEINLINE ~SIRTBPPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+
+//----------------------------------------------------------------------------------------
+/** Policy For Sinogram Mask
+ */
+class SinogramMaskPolicy {
+
+ CFloat32ProjectionData2D* m_pSinogramMask;
+
+public:
+
+ FORCEINLINE SinogramMaskPolicy();
+ FORCEINLINE SinogramMaskPolicy(CFloat32ProjectionData2D* _pSinogramMask);
+ FORCEINLINE ~SinogramMaskPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+/** Policy For Reconstruction Mask
+ */
+class ReconstructionMaskPolicy {
+
+ CFloat32VolumeData2D* m_pReconstructionMask;
+
+public:
+
+ FORCEINLINE ReconstructionMaskPolicy();
+ FORCEINLINE ReconstructionMaskPolicy(CFloat32VolumeData2D* _pReconstructionMask);
+ FORCEINLINE ~ReconstructionMaskPolicy();
+
+ FORCEINLINE bool rayPrior(int _iRayIndex);
+ FORCEINLINE bool pixelPrior(int _iVolumeIndex);
+ FORCEINLINE void addWeight(int _iRayIndex, int _iVolumeIndex, float32 weight);
+ FORCEINLINE void rayPosterior(int _iRayIndex);
+ FORCEINLINE void pixelPosterior(int _iVolumeIndex);
+};
+
+//----------------------------------------------------------------------------------------
+
+#include "DataProjectorPolicies.inl"
+
+} // end namespace
+
+#endif
diff --git a/include/astra/DataProjectorPolicies.inl b/include/astra/DataProjectorPolicies.inl
new file mode 100644
index 0000000..b2166c3
--- /dev/null
+++ b/include/astra/DataProjectorPolicies.inl
@@ -0,0 +1,855 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_DATAPROJECTORPOLICIES_INLINE
+#define _INC_ASTRA_DATAPROJECTORPOLICIES_INLINE
+
+
+
+//----------------------------------------------------------------------------------------
+// DEFAULT FORWARD PROJECTION (Ray Driven)
+//----------------------------------------------------------------------------------------
+DefaultFPPolicy::DefaultFPPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+DefaultFPPolicy::DefaultFPPolicy(CFloat32VolumeData2D* _pVolumeData,
+ CFloat32ProjectionData2D* _pProjectionData)
+{
+ m_pProjectionData = _pProjectionData;
+ m_pVolumeData = _pVolumeData;
+}
+//----------------------------------------------------------------------------------------
+DefaultFPPolicy::~DefaultFPPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool DefaultFPPolicy::rayPrior(int _iRayIndex)
+{
+ m_pProjectionData->getData()[_iRayIndex] = 0.0f;
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool DefaultFPPolicy::pixelPrior(int _iVolumeIndex)
+{
+ // do nothing
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void DefaultFPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ m_pProjectionData->getData()[_iRayIndex] += m_pVolumeData->getData()[_iVolumeIndex] * _fWeight;
+}
+//----------------------------------------------------------------------------------------
+void DefaultFPPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void DefaultFPPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------------------
+// DEFAULT BACK PROJECTION (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+DefaultBPPolicy::DefaultBPPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+DefaultBPPolicy::DefaultBPPolicy(CFloat32VolumeData2D* _pVolumeData,
+ CFloat32ProjectionData2D* _pProjectionData)
+{
+ m_pProjectionData = _pProjectionData;
+ m_pVolumeData = _pVolumeData;
+}
+//----------------------------------------------------------------------------------------
+DefaultBPPolicy::~DefaultBPPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool DefaultBPPolicy::rayPrior(int _iRayIndex)
+{
+ // do nothing
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool DefaultBPPolicy::pixelPrior(int _iVolumeIndex)
+{
+ // do nothing
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void DefaultBPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ m_pVolumeData->getData()[_iVolumeIndex] += m_pProjectionData->getData()[_iRayIndex] * _fWeight;
+}
+//----------------------------------------------------------------------------------------
+void DefaultBPPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void DefaultBPPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+//----------------------------------------------------------------------------------------
+// FORWARD PROJECTION DIFFERENCE CALCULATION (Ray Driven)
+//----------------------------------------------------------------------------------------
+DiffFPPolicy::DiffFPPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+DiffFPPolicy::DiffFPPolicy(CFloat32VolumeData2D* _pVolumeData,
+ CFloat32ProjectionData2D* _pDiffProjectionData,
+ CFloat32ProjectionData2D* _pBaseProjectionData)
+{
+ m_pDiffProjectionData = _pDiffProjectionData;
+ m_pBaseProjectionData = _pBaseProjectionData;
+ m_pVolumeData = _pVolumeData;
+}
+//----------------------------------------------------------------------------------------
+DiffFPPolicy::~DiffFPPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+ bool DiffFPPolicy::rayPrior(int _iRayIndex)
+{
+ m_pDiffProjectionData->getData()[_iRayIndex] = m_pBaseProjectionData->getData()[_iRayIndex];
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool DiffFPPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void DiffFPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ m_pDiffProjectionData->getData()[_iRayIndex] -= m_pVolumeData->getData()[_iVolumeIndex] * _fWeight;
+}
+//----------------------------------------------------------------------------------------
+void DiffFPPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void DiffFPPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------------------
+// STORE PIXEL WEIGHT (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+StorePixelWeightsPolicy::StorePixelWeightsPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+StorePixelWeightsPolicy::StorePixelWeightsPolicy(SPixelWeight* _pPixelWeights, int _iMaxPixelCount)
+{
+ m_iStoredPixelCount = 0;
+ m_pPixelWeights = _pPixelWeights;
+ m_iMaxPixelCount = _iMaxPixelCount;
+}
+//----------------------------------------------------------------------------------------
+StorePixelWeightsPolicy::~StorePixelWeightsPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool StorePixelWeightsPolicy::rayPrior(int _iRayIndex)
+{
+ return (m_iStoredPixelCount < m_iMaxPixelCount);
+}
+//----------------------------------------------------------------------------------------
+bool StorePixelWeightsPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return (m_iStoredPixelCount < m_iMaxPixelCount);
+}
+//----------------------------------------------------------------------------------------
+void StorePixelWeightsPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ m_pPixelWeights[m_iStoredPixelCount].m_fWeight = _fWeight;
+ m_pPixelWeights[m_iStoredPixelCount].m_iIndex = _iVolumeIndex;
+ ++m_iStoredPixelCount;
+}
+//----------------------------------------------------------------------------------------
+void StorePixelWeightsPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void StorePixelWeightsPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+int StorePixelWeightsPolicy::getStoredPixelCount()
+{
+ return m_iStoredPixelCount;
+}
+//----------------------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------------------
+// TOTAL PIXEL WEIGHT MULTIPLIED BY SINOGRAM (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+TotalPixelWeightBySinogramPolicy::TotalPixelWeightBySinogramPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+TotalPixelWeightBySinogramPolicy::TotalPixelWeightBySinogramPolicy(CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pPixelWeight)
+{
+ m_pPixelWeight = _pPixelWeight;
+ m_pSinogram = _pSinogram;
+}
+//----------------------------------------------------------------------------------------
+TotalPixelWeightBySinogramPolicy::~TotalPixelWeightBySinogramPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool TotalPixelWeightBySinogramPolicy::rayPrior(int _iRayIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool TotalPixelWeightBySinogramPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void TotalPixelWeightBySinogramPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ m_pPixelWeight->getData()[_iVolumeIndex] += _fWeight * m_pSinogram->getData()[_iRayIndex];
+}
+//----------------------------------------------------------------------------------------
+void TotalPixelWeightBySinogramPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void TotalPixelWeightBySinogramPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+
+//----------------------------------------------------------------------------------------
+// TOTAL PIXEL WEIGHT (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+TotalPixelWeightPolicy::TotalPixelWeightPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+TotalPixelWeightPolicy::TotalPixelWeightPolicy(CFloat32VolumeData2D* _pPixelWeight)
+{
+ m_pPixelWeight = _pPixelWeight;
+}
+//----------------------------------------------------------------------------------------
+TotalPixelWeightPolicy::~TotalPixelWeightPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool TotalPixelWeightPolicy::rayPrior(int _iRayIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool TotalPixelWeightPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void TotalPixelWeightPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ m_pPixelWeight->getData()[_iVolumeIndex] += _fWeight;
+}
+//----------------------------------------------------------------------------------------
+void TotalPixelWeightPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void TotalPixelWeightPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+//----------------------------------------------------------------------------------------
+// TOTAL RAY LENGTH (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+TotalRayLengthPolicy::TotalRayLengthPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+TotalRayLengthPolicy::TotalRayLengthPolicy(CFloat32ProjectionData2D* _pRayLength)
+{
+ m_pRayLength = _pRayLength;
+}
+//----------------------------------------------------------------------------------------
+TotalRayLengthPolicy::~TotalRayLengthPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool TotalRayLengthPolicy::rayPrior(int _iRayIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool TotalRayLengthPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void TotalRayLengthPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ m_pRayLength->getData()[_iRayIndex] += _fWeight;
+}
+//----------------------------------------------------------------------------------------
+void TotalRayLengthPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void TotalRayLengthPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+
+//----------------------------------------------------------------------------------------
+// COMBINE TWO POLICIES (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2>
+CombinePolicy<P1,P2>::CombinePolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2>
+CombinePolicy<P1,P2>::CombinePolicy(P1 _policy1, P2 _policy2)
+{
+ policy1 = _policy1;
+ policy2 = _policy2;
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2>
+CombinePolicy<P1,P2>::~CombinePolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2>
+bool CombinePolicy<P1,P2>::rayPrior(int _iRayIndex)
+{
+ if (!policy1.rayPrior(_iRayIndex)) return false;
+ return policy2.rayPrior(_iRayIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2>
+bool CombinePolicy<P1,P2>::pixelPrior(int _iVolumeIndex)
+{
+ if (!policy1.pixelPrior(_iVolumeIndex)) return false;
+ return policy2.pixelPrior(_iVolumeIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2>
+void CombinePolicy<P1,P2>::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ policy1.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+ policy2.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2>
+void CombinePolicy<P1,P2>::rayPosterior(int _iRayIndex)
+{
+ policy1.rayPosterior(_iRayIndex);
+ policy2.rayPosterior(_iRayIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2>
+void CombinePolicy<P1,P2>::pixelPosterior(int _iVolumeIndex)
+{
+ policy1.pixelPosterior(_iVolumeIndex);
+ policy2.pixelPosterior(_iVolumeIndex);
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+//----------------------------------------------------------------------------------------
+// COMBINE THREE POLICIES (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3>
+Combine3Policy<P1,P2,P3>::Combine3Policy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3>
+Combine3Policy<P1,P2,P3>::Combine3Policy(P1 _policy1, P2 _policy2, P3 _policy3)
+{
+ policy1 = _policy1;
+ policy2 = _policy2;
+ policy3 = _policy3;
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3>
+Combine3Policy<P1,P2,P3>::~Combine3Policy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3>
+bool Combine3Policy<P1,P2,P3>::rayPrior(int _iRayIndex)
+{
+ if (!policy1.rayPrior(_iRayIndex)) return false;
+ if (!policy2.rayPrior(_iRayIndex)) return false;
+ return policy3.rayPrior(_iRayIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3>
+bool Combine3Policy<P1,P2,P3>::pixelPrior(int _iVolumeIndex)
+{
+ if (!policy1.pixelPrior(_iVolumeIndex)) return false;
+ if (!policy2.pixelPrior(_iVolumeIndex)) return false;
+ return policy3.pixelPrior(_iVolumeIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3>
+void Combine3Policy<P1,P2,P3>::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ policy1.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+ policy2.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+ policy3.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3>
+void Combine3Policy<P1,P2,P3>::rayPosterior(int _iRayIndex)
+{
+ policy1.rayPosterior(_iRayIndex);
+ policy2.rayPosterior(_iRayIndex);
+ policy3.rayPosterior(_iRayIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3>
+void Combine3Policy<P1,P2,P3>::pixelPosterior(int _iVolumeIndex)
+{
+ policy1.pixelPosterior(_iVolumeIndex);
+ policy2.pixelPosterior(_iVolumeIndex);
+ policy3.pixelPosterior(_iVolumeIndex);
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+
+
+//----------------------------------------------------------------------------------------
+// COMBINE FOUR POLICIES (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3, typename P4>
+Combine4Policy<P1,P2,P3,P4>::Combine4Policy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3, typename P4>
+Combine4Policy<P1,P2,P3,P4>::Combine4Policy(P1 _policy1, P2 _policy2, P3 _policy3, P4 _policy4)
+{
+ policy1 = _policy1;
+ policy2 = _policy2;
+ policy3 = _policy3;
+ policy4 = _policy4;
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3, typename P4>
+Combine4Policy<P1,P2,P3,P4>::~Combine4Policy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3, typename P4>
+bool Combine4Policy<P1,P2,P3,P4>::rayPrior(int _iRayIndex)
+{
+ if (!policy1.rayPrior(_iRayIndex)) return false;
+ if (!policy2.rayPrior(_iRayIndex)) return false;
+ if (!policy3.rayPrior(_iRayIndex)) return false;
+ return policy4.rayPrior(_iRayIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3, typename P4>
+bool Combine4Policy<P1,P2,P3,P4>::pixelPrior(int _iVolumeIndex)
+{
+ if (!policy1.pixelPrior(_iVolumeIndex)) return false;
+ if (!policy2.pixelPrior(_iVolumeIndex)) return false;
+ if (!policy3.pixelPrior(_iVolumeIndex)) return false;
+ return policy4.pixelPrior(_iVolumeIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3, typename P4>
+void Combine4Policy<P1,P2,P3,P4>::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ policy1.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+ policy2.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+ policy3.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+ policy4.addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3, typename P4>
+void Combine4Policy<P1,P2,P3,P4>::rayPosterior(int _iRayIndex)
+{
+ policy1.rayPosterior(_iRayIndex);
+ policy2.rayPosterior(_iRayIndex);
+ policy3.rayPosterior(_iRayIndex);
+ policy4.rayPosterior(_iRayIndex);
+}
+//----------------------------------------------------------------------------------------
+template<typename P1, typename P2, typename P3, typename P4>
+void Combine4Policy<P1,P2,P3,P4>::pixelPosterior(int _iVolumeIndex)
+{
+ policy1.pixelPosterior(_iVolumeIndex);
+ policy2.pixelPosterior(_iVolumeIndex);
+ policy3.pixelPosterior(_iVolumeIndex);
+ policy4.pixelPosterior(_iVolumeIndex);
+}
+//----------------------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------------------
+// COMBINE LIST OF EQUAL POLICIES (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+template<typename P>
+CombineListPolicy<P>::CombineListPolicy()
+{
+ size = 0;
+}
+//----------------------------------------------------------------------------------------
+template<typename P>
+CombineListPolicy<P>::CombineListPolicy(std::vector<P> _policyList)
+{
+ policyList = _policyList;
+ size = policyList.size();
+}
+//----------------------------------------------------------------------------------------
+template<typename P>
+CombineListPolicy<P>::~CombineListPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+template<typename P>
+void CombineListPolicy<P>::addPolicy(P _policy)
+{
+ policyList.push_back(_policy);
+ size = policyList.size();
+}
+//----------------------------------------------------------------------------------------
+template<typename P>
+bool CombineListPolicy<P>::rayPrior(int _iRayIndex)
+{
+ for(unsigned int i = 0; i < size; ++i) {
+ if (!policyList[i].rayPrior(_iRayIndex)) return false;
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------
+template<typename P>
+bool CombineListPolicy<P>::pixelPrior(int _iVolumeIndex)
+{
+ for(unsigned int i = 0; i < size; ++i) {
+ if (!policyList[i].pixelPrior(_iVolumeIndex)) return false;
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------
+template<typename P>
+void CombineListPolicy<P>::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ for(unsigned int i = 0; i < size; ++i) {
+ policyList[i].addWeight(_iRayIndex, _iVolumeIndex, _fWeight);
+ }
+}
+//----------------------------------------------------------------------------------------
+template<typename P>
+void CombineListPolicy<P>::rayPosterior(int _iRayIndex)
+{
+ for(unsigned int i = 0; i < size; ++i) {
+ policyList[i].rayPosterior(_iRayIndex);
+ }
+}
+//----------------------------------------------------------------------------------------
+template<typename P>
+void CombineListPolicy<P>::pixelPosterior(int _iVolumeIndex)
+{
+ for(unsigned int i = 0; i < size; ++i) {
+ policyList[i].pixelPosterior(_iVolumeIndex);
+ }
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+
+//----------------------------------------------------------------------------------------
+// EMPTY POLICY (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+EmptyPolicy::EmptyPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+EmptyPolicy::~EmptyPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool EmptyPolicy::rayPrior(int _iRayIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool EmptyPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void EmptyPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void EmptyPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void EmptyPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------------------
+// SIRT BACKPROJECTION (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+SIRTBPPolicy::SIRTBPPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+SIRTBPPolicy::SIRTBPPolicy(CFloat32VolumeData2D* _pReconstruction,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pTotalPixelWeight,
+ CFloat32ProjectionData2D* _pTotalRayLength)
+{
+ m_pReconstruction = _pReconstruction;
+ m_pSinogram = _pSinogram;
+ m_pTotalPixelWeight = _pTotalPixelWeight;
+ m_pTotalRayLength = _pTotalRayLength;
+}
+//----------------------------------------------------------------------------------------
+SIRTBPPolicy::~SIRTBPPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool SIRTBPPolicy::rayPrior(int _iRayIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool SIRTBPPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void SIRTBPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ float32 fGammaBeta = m_pTotalPixelWeight->getData()[_iVolumeIndex] * m_pTotalRayLength->getData()[_iRayIndex];
+ if ((fGammaBeta > 0.001f) || (fGammaBeta < -0.001f)) {
+ m_pReconstruction->getData()[_iVolumeIndex] += _fWeight * m_pSinogram->getData()[_iRayIndex] / fGammaBeta;
+ }
+}
+//----------------------------------------------------------------------------------------
+void SIRTBPPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void SIRTBPPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+
+//----------------------------------------------------------------------------------------
+// SINOGRAM MASK (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+SinogramMaskPolicy::SinogramMaskPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+SinogramMaskPolicy::SinogramMaskPolicy(CFloat32ProjectionData2D* _pSinogramMask)
+{
+ m_pSinogramMask = _pSinogramMask;
+}
+//----------------------------------------------------------------------------------------
+SinogramMaskPolicy::~SinogramMaskPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool SinogramMaskPolicy::rayPrior(int _iRayIndex)
+{
+ return (m_pSinogramMask->getData()[_iRayIndex] != 0);
+}
+//----------------------------------------------------------------------------------------
+bool SinogramMaskPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+void SinogramMaskPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void SinogramMaskPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void SinogramMaskPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+
+
+//----------------------------------------------------------------------------------------
+// RECONSTRUCTION MASK (Ray+Pixel Driven)
+//----------------------------------------------------------------------------------------
+ReconstructionMaskPolicy::ReconstructionMaskPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+ReconstructionMaskPolicy::ReconstructionMaskPolicy(CFloat32VolumeData2D* _pReconstructionMask)
+{
+ m_pReconstructionMask = _pReconstructionMask;
+}
+//----------------------------------------------------------------------------------------
+ReconstructionMaskPolicy::~ReconstructionMaskPolicy()
+{
+
+}
+//----------------------------------------------------------------------------------------
+bool ReconstructionMaskPolicy::rayPrior(int _iRayIndex)
+{
+ return true;
+}
+//----------------------------------------------------------------------------------------
+bool ReconstructionMaskPolicy::pixelPrior(int _iVolumeIndex)
+{
+ return (m_pReconstructionMask->getData()[_iVolumeIndex] != 0);
+}
+//----------------------------------------------------------------------------------------
+void ReconstructionMaskPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void ReconstructionMaskPolicy::rayPosterior(int _iRayIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+void ReconstructionMaskPolicy::pixelPosterior(int _iVolumeIndex)
+{
+ // nothing
+}
+//----------------------------------------------------------------------------------------
+
+
+
+#endif
diff --git a/include/astra/FanFlatBeamLineKernelProjector2D.h b/include/astra/FanFlatBeamLineKernelProjector2D.h
new file mode 100644
index 0000000..154504a
--- /dev/null
+++ b/include/astra/FanFlatBeamLineKernelProjector2D.h
@@ -0,0 +1,194 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FANFLATBEAMLINEKERNELPROJECTOR
+#define _INC_ASTRA_FANFLATBEAMLINEKERNELPROJECTOR
+
+#include "FanFlatProjectionGeometry2D.h"
+#include "FanFlatVecProjectionGeometry2D.h"
+#include "Float32Data2D.h"
+#include "Projector2D.h"
+
+namespace astra
+{
+
+
+/** This class implements a two-dimensional projector based on a line based kernel
+ * with a fan flat projection geometry.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('fanflat_line');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * proj_id = astra_mex_projector('create'\, cfg);\n
+ * }
+ */
+class _AstraExport CFanFlatBeamLineKernelProjector2D : public CProjector2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - blobvalues are ok
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /** Default constructor.
+ */
+ CFanFlatBeamLineKernelProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ */
+ CFanFlatBeamLineKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Destructor, is virtual to show that we are aware subclass destructor are called.
+ */
+ ~CFanFlatBeamLineKernelProjector2D();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the projector.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ * @return initialization successful?
+ */
+ virtual bool initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Returns the number of weights required for storage of all weights of one projection.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex);
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection
+ * @param _iDetectorIndex Index of the detector pixel
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol);
+
+ /** Policy-based projection of all rays. This function will calculate each non-zero projection
+ * weight and use this value for a task provided by the policy object.
+ *
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void project(Policy& _policy);
+
+ /** Policy-based projection of all rays of a single projection. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Wwhich projection should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy);
+
+ /** Policy-based projection of a single ray. This function will calculate each non-zero
+ * projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Which projection should be projected?
+ * @param _iDetector Which detector should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy);
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType();
+
+ float32 angleBetweenVectors(float32 _fAX, float32 _fAY, float32 _fBX, float32 _fBY);
+
+};
+
+//----------------------------------------------------------------------------------------
+
+inline std::string CFanFlatBeamLineKernelProjector2D::getType()
+{
+ return type;
+}
+
+
+} // namespace astra
+
+#endif
+
diff --git a/include/astra/FanFlatBeamLineKernelProjector2D.inl b/include/astra/FanFlatBeamLineKernelProjector2D.inl
new file mode 100644
index 0000000..e686532
--- /dev/null
+++ b/include/astra/FanFlatBeamLineKernelProjector2D.inl
@@ -0,0 +1,740 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+using namespace astra;
+
+//----------------------------------------------------------------------------------------
+// PROJECT ALL
+template <typename Policy>
+void CFanFlatBeamLineKernelProjector2D::project(Policy& p)
+{
+ // variables
+ float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2;
+ float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY;
+ int iVolumeIndex, iRayIndex, row, col, iAngle, iDetector, x1;
+ bool switch_t;
+
+ const CFanFlatProjectionGeometry2D* pProjectionGeometry = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry);
+ const CFanFlatVecProjectionGeometry2D* pVecProjectionGeometry = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry);
+
+ float32 old_theta, theta, alpha;
+ const SFanProjection * proj = 0;
+
+ // loop angles
+ for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) {
+
+ // get theta
+ if (pProjectionGeometry) {
+ old_theta = pProjectionGeometry->getProjectionAngle(iAngle);
+ }
+ else if (pVecProjectionGeometry) {
+ proj = &pVecProjectionGeometry->getProjectionVectors()[iAngle];
+ old_theta = atan2(-proj->fSrcX, proj->fSrcY);
+ if (old_theta < 0) old_theta += 2*PI;
+ } else {
+ assert(false);
+ }
+
+ switch_t = false;
+ if (old_theta >= 7*PIdiv4) old_theta -= 2*PI;
+ if (old_theta >= 3*PIdiv4) {
+ old_theta -= PI;
+ switch_t = true;
+ }
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get values
+ if (pProjectionGeometry) {
+ t = -pProjectionGeometry->indexToDetectorOffset(iDetector);
+ alpha = atan(t / pProjectionGeometry->getSourceDetectorDistance());
+ t = sin(alpha) * pProjectionGeometry->getOriginSourceDistance();
+ }
+ else if (pVecProjectionGeometry) {
+ float32 detX = proj->fDetSX + proj->fDetUX*(0.5f + iDetector);
+ float32 detY = proj->fDetSY + proj->fDetUY*(0.5f + iDetector);
+ alpha = angleBetweenVectors(-proj->fSrcX, -proj->fSrcY, detX - proj->fSrcX, detY - proj->fSrcY);
+ t = sin(alpha) * sqrt(proj->fSrcX*proj->fSrcX + proj->fSrcY*proj->fSrcY);
+ } else {
+ assert(false);
+ }
+
+ if (switch_t) t = -t;
+ theta = old_theta + alpha;
+
+ // precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_sin_theta = 1.0f / sin_theta;
+ inv_cos_theta = 1.0f / cos_theta;
+
+ // precalculate kernel limits
+ lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ updatePerRow = sin_theta * inv_cos_theta;
+ inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+
+ // precalculate kernel limits
+ lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ updatePerCol = cos_theta * inv_sin_theta;
+ inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+
+ // precalculate S and T
+ S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow);
+ T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol);
+
+ // vertically
+ if (old_theta <= PIdiv4) {
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get coords
+ x1 = int((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerRow;
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue;
+
+ // left
+ if (x2 < 0.5f-S) {
+ I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridColCount()*/) {//x1 is always less than or equal to gridColCount because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+S) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // right
+ else if (x2 <= 1.0f) {
+ I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridColCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ }
+
+ // horizontally
+ //else if (PIdiv4 <= old_theta && old_theta <= 3*PIdiv4) {
+ else {
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get coords
+ x1 = int((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerCol;
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue;
+
+ // up
+ if (x2 < 0.5f-T) {
+ I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridRowCount()*/) {//x1 is always less than or equal to gridRowCount because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+T) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // down
+ else if (x2 <= 1.0f) {
+ I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridRowCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ } // end loop col
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end loop detector
+ } // end loop angles
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE PROJECTION
+template <typename Policy>
+void CFanFlatBeamLineKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p)
+{
+ // variables
+ float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2;
+ float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY;
+ int iVolumeIndex, iRayIndex, row, col, iDetector, x1;
+ bool switch_t;
+
+ const CFanFlatProjectionGeometry2D* pProjectionGeometry = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry);
+ const CFanFlatVecProjectionGeometry2D* pVecProjectionGeometry = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry);
+
+ float32 old_theta, theta, alpha;
+ const SFanProjection * proj = 0;
+
+ //get theta
+ if (pProjectionGeometry) {
+ old_theta = pProjectionGeometry->getProjectionAngle(_iProjection);
+ }
+ else if (pVecProjectionGeometry) {
+ proj = &pVecProjectionGeometry->getProjectionVectors()[_iProjection];
+ old_theta = atan2(-proj->fSrcX, proj->fSrcY);
+ if (old_theta < 0) old_theta += 2*PI;
+ } else {
+ assert(false);
+ }
+
+ switch_t = false;
+ if (old_theta >= 7*PIdiv4) old_theta -= 2*PI;
+ if (old_theta >= 3*PIdiv4) {
+ old_theta -= PI;
+ switch_t = true;
+ }
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ if (pProjectionGeometry) {
+ t = -pProjectionGeometry->indexToDetectorOffset(iDetector);
+ alpha = atan(t / pProjectionGeometry->getSourceDetectorDistance());
+ t = sin(alpha) * pProjectionGeometry->getOriginSourceDistance();
+ }
+ else if (pVecProjectionGeometry) {
+ float32 detX = proj->fDetSX + proj->fDetUX*(0.5f + iDetector);
+ float32 detY = proj->fDetSY + proj->fDetUY*(0.5f + iDetector);
+ alpha = angleBetweenVectors(-proj->fSrcX, -proj->fSrcY, detX - proj->fSrcX, detY - proj->fSrcY);
+ t = sin(alpha) * sqrt(proj->fSrcX*proj->fSrcX + proj->fSrcY*proj->fSrcY);
+ } else {
+ assert(false);
+ }
+
+ if (switch_t) t = -t;
+ theta = old_theta + alpha;
+
+ // precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_sin_theta = 1.0f / sin_theta;
+ inv_cos_theta = 1.0f / cos_theta;
+
+ // precalculate kernel limits
+ lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ updatePerRow = sin_theta * inv_cos_theta;
+ inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+
+ // precalculate kernel limits
+ lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ updatePerCol = cos_theta * inv_sin_theta;
+ inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+
+ // precalculate S and T
+ S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow);
+ T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol);
+
+ // vertically
+ if (old_theta <= PIdiv4) {
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get coords
+ x1 = int((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerRow;
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue;
+
+ // left
+ if (x2 < 0.5f-S) {
+ I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridColCount()*/) {//x1 is always less than or equal to gridColCount because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+S) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // right
+ else if (x2 <= 1.0f) {
+ I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridColCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else {
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get coords
+ x1 = int((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerCol;
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue;
+
+ // up
+ if (x2 < 0.5f-T) {
+ I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridRowCount()*/) {//x1 is always less than or equal to gridRowCount because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+T) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // down
+ else if (x2 <= 1.0f) {
+ I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridRowCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ } // end loop col
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end loop detector
+
+}
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE RAY
+template <typename Policy>
+void CFanFlatBeamLineKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p)
+{
+ // variables
+ float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2;
+ float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY;
+ int iVolumeIndex, iRayIndex, row, col, x1;
+ bool switch_t;
+
+ const CFanFlatProjectionGeometry2D* pProjectionGeometry = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry);
+ const CFanFlatVecProjectionGeometry2D* pVecProjectionGeometry = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry);
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) return;
+
+ float32 old_theta, theta, alpha;
+ if (pProjectionGeometry) {
+ old_theta = pProjectionGeometry->getProjectionAngle(_iProjection);
+ t = -pProjectionGeometry->indexToDetectorOffset(_iDetector);
+ alpha = atan(t / pProjectionGeometry->getSourceDetectorDistance());
+ t = sin(alpha) * pProjectionGeometry->getOriginSourceDistance();
+ }
+ else if (pVecProjectionGeometry) {
+ const SFanProjection * proj = &pVecProjectionGeometry->getProjectionVectors()[_iProjection];
+ old_theta = atan2(-proj->fSrcX, proj->fSrcY);
+ if (old_theta < 0) old_theta += 2*PI;
+
+ float32 detX = proj->fDetSX + proj->fDetUX*(0.5f + _iDetector);
+ float32 detY = proj->fDetSY + proj->fDetUY*(0.5f + _iDetector);
+ alpha = angleBetweenVectors(-proj->fSrcX, -proj->fSrcY, detX - proj->fSrcX, detY - proj->fSrcY);
+ t = sin(alpha) * sqrt(proj->fSrcX*proj->fSrcX + proj->fSrcY*proj->fSrcY);
+ } else {
+ assert(false);
+ }
+
+ switch_t = false;
+ if (old_theta >= 7*PIdiv4) old_theta -= 2*PI;
+ if (old_theta >= 3*PIdiv4) {
+ old_theta -= PI;
+ switch_t = true;
+ }
+ if (switch_t) t = -t;
+ theta = old_theta + alpha;
+
+ // precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_sin_theta = 1.0f / sin_theta;
+ inv_cos_theta = 1.0f / cos_theta;
+
+ // precalculate kernel limits
+ lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ updatePerRow = sin_theta * inv_cos_theta;
+ inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+
+ // precalculate kernel limits
+ lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ updatePerCol = cos_theta * inv_sin_theta;
+ inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+
+ // precalculate S and T
+ S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow);
+ T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol);
+
+ // vertically
+ if (old_theta <= PIdiv4) {
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get coords
+ x1 = int((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerRow;
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue;
+
+ // left
+ if (x2 < 0.5f-S) {
+ I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridColCount()*/) {//x1 is always less than or equal to gridColCount because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+S) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // right
+ else if (x2 <= 1.0f) {
+ I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridColCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else {
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get coords
+ x1 = int((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerCol;
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue;
+
+ // up
+ if (x2 < 0.5f-T) {
+ I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1-1 >= 0 /*&& x1-1 < m_pVolumeGeometry->getGridRowCount()*/) {//x1 is always less than or equal to gridRowCount because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+T) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // down
+ else if (x2 <= 1.0f) {
+ I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (/*x1+1 >= 0 &&*/ x1+1 < m_pVolumeGeometry->getGridRowCount()) {//x1 is always greater than or equal to -1 because of the "continue" in the beginning of the for-loop
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ } // end loop col
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+}
diff --git a/include/astra/FanFlatBeamStripKernelProjector2D.h b/include/astra/FanFlatBeamStripKernelProjector2D.h
new file mode 100644
index 0000000..7fed4c8
--- /dev/null
+++ b/include/astra/FanFlatBeamStripKernelProjector2D.h
@@ -0,0 +1,191 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FANFLATBEAMSTRIPKERNELPROJECTOR
+#define _INC_ASTRA_FANFLATBEAMSTRIPKERNELPROJECTOR
+
+#include "FanFlatProjectionGeometry2D.h"
+#include "Float32Data2D.h"
+#include "Projector2D.h"
+
+namespace astra
+{
+
+
+/** This class implements a two-dimensional fan-flat-beam projector based on a strip based kernel.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('strip_fanflat');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * proj_id = astra_mex_projector('create'\, cfg);\n
+ * }
+ */
+class _AstraExport CFanFlatBeamStripKernelProjector2D : public CProjector2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - blobvalues are ok
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /** Default constructor.
+ */
+ CFanFlatBeamStripKernelProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ */
+ CFanFlatBeamStripKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Destructor, is virtual to show that we are aware subclass destructor are called.
+ */
+ ~CFanFlatBeamStripKernelProjector2D();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the projector.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ * @return initialization successful?
+ */
+ virtual bool initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Returns the number of weights required for storage of all weights of one projection.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex);
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection
+ * @param _iDetectorIndex Index of the detector pixel
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol);
+
+ /** Policy-based projection of all rays. This function will calculate each non-zero projection
+ * weight and use this value for a task provided by the policy object.
+ *
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void project(Policy& _policy);
+
+ /** Policy-based projection of all rays of a single projection. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Wwhich projection should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy);
+
+ /** Policy-based projection of a single ray. This function will calculate each non-zero
+ * projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Which projection should be projected?
+ * @param _iDetector Which detector should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy);
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType();
+
+};
+
+//----------------------------------------------------------------------------------------
+
+inline std::string CFanFlatBeamStripKernelProjector2D::getType()
+{
+ return type;
+}
+
+} // namespace astra
+
+
+
+#endif
+
diff --git a/include/astra/FanFlatBeamStripKernelProjector2D.inl b/include/astra/FanFlatBeamStripKernelProjector2D.inl
new file mode 100644
index 0000000..e3f8b29
--- /dev/null
+++ b/include/astra/FanFlatBeamStripKernelProjector2D.inl
@@ -0,0 +1,961 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+using namespace astra;
+
+//----------------------------------------------------------------------------------------
+// PROJECT ALL
+template <typename Policy>
+void CFanFlatBeamStripKernelProjector2D::project(Policy& p)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ // Some variables
+ float32 theta;
+ int row, col;
+ int iAngle, iDetector;
+ float32 res;
+ int x1L, x1R;
+ float32 x2L, x2R;
+ int iVolumeIndex, iRayIndex;
+
+ CFanFlatProjectionGeometry2D* projgeom = static_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry);
+
+ // Other precalculations
+ float32 PW = m_pVolumeGeometry->getPixelLengthX();
+ float32 PH = m_pVolumeGeometry->getPixelLengthY();
+ float32 DW = m_pProjectionGeometry->getDetectorWidth();
+ float32 inv_PW = 1.0f / PW;
+ float32 inv_PH = 1.0f / PH;
+
+ // calculate alpha's
+ float32 alpha;
+ float32* cos_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1];
+ float32* sin_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1];
+ for (int i = 0; i < m_pProjectionGeometry->getDetectorCount() + 1; ++i) {
+ alpha = -atan((i - m_pProjectionGeometry->getDetectorCount()*0.5f) * DW / projgeom->getSourceDetectorDistance());
+ cos_alpha[i] = cos(alpha);
+ sin_alpha[i] = sin(alpha);
+ }
+
+ // loop angles
+ for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) {
+
+ // get values
+ theta = m_pProjectionGeometry->getProjectionAngle(iAngle);
+ bool switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // Precalculate sin, cos, 1/cos
+ float32 sin_theta = sin(theta);
+ float32 cos_theta = cos(theta);
+
+ // [-45?,45?] and [135?,225?]
+ if (theta < PIdiv4) {
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ float32 sin_theta_left, cos_theta_left;
+ float32 sin_theta_right, cos_theta_right;
+
+ // get theta_l = alpha_left + theta and theta_r = alpha_right + theta
+ float32 t_l, t_r;
+ if (!switch_t) {
+ sin_theta_left = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1];
+ sin_theta_right = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector];
+
+ cos_theta_left = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1];
+ cos_theta_right = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector];
+
+ t_l = sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance();
+ t_r = sin_alpha[iDetector] * projgeom->getOriginSourceDistance();
+
+ } else {
+ sin_theta_left = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector];
+ sin_theta_right = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1];
+
+ cos_theta_left = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector];
+ cos_theta_right = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1];
+
+ t_l = -sin_alpha[iDetector] * projgeom->getOriginSourceDistance();
+ t_r = -sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance();
+ }
+
+ float32 inv_cos_theta_left = 1.0f / cos_theta_left;
+ float32 inv_cos_theta_right = 1.0f / cos_theta_right;
+
+ float32 updateX_left = sin_theta_left * inv_cos_theta_left;
+ float32 updateX_right = sin_theta_right * inv_cos_theta_right;
+
+ // Precalculate kernel limits
+ float32 S_l = -0.5f * updateX_left;
+ if (S_l > 0) {S_l = -S_l;}
+ float32 T_l = -S_l;
+ float32 U_l = 1.0f + S_l;
+ float32 V_l = 1.0f - S_l;
+ float32 inv_4T_l = 0.25f / T_l;
+
+ float32 S_r = -0.5f * updateX_right;
+ if (S_r > 0) {S_r = -S_r;}
+ float32 T_r = -S_r;
+ float32 U_r = 1.0f + S_r;
+ float32 V_r = 1.0f - S_r;
+ float32 inv_4T_r = 0.25f / T_r;
+
+ // calculate strip extremes (volume coordinates)
+ float32 PL = (t_l - sin_theta_left * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_left;
+ float32 PR = (t_r - sin_theta_right * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_right;
+ float32 PLimitL = PL + S_l * PH;
+ float32 PLimitR = PR - S_r * PH;
+
+ // calculate strip extremes (pixel coordinates)
+ float32 XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 xR = (PR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX_left;
+ XLimitR += updateX_right;
+ xL += updateX_left;
+ xR += updateX_right;
+
+ // for each affected col
+ for (col = x1L; col <= x1R; ++col) {
+
+ if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V_r) res = 1.0f;
+ else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r;
+ else if (x2R >= T_r) res = x2R;
+ else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S_l) {}
+ else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l;
+ else if (x2L <= U_l) res -= x2L;
+ else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end detector loop
+
+ // [45?,135?] and [225?,315?]
+ // horizontaly
+ } else {
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get theta_l = alpha_left + theta and theta_r = alpha_right + theta
+ float32 sin_theta_left, cos_theta_left;
+ float32 sin_theta_right, cos_theta_right;
+ float32 t_l, t_r;
+ if (!switch_t) {
+ sin_theta_left = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector];
+ sin_theta_right = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1];
+
+ cos_theta_left = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector];
+ cos_theta_right = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1];
+
+ t_l = sin_alpha[iDetector] * projgeom->getOriginSourceDistance();
+ t_r = sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance();
+
+ } else {
+ sin_theta_left = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1];
+ sin_theta_right = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector];
+
+ cos_theta_left = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1];
+ cos_theta_right = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector];
+
+ t_l = -sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance();
+ t_r = -sin_alpha[iDetector] * projgeom->getOriginSourceDistance();
+ }
+
+ float32 inv_sin_theta_left = 1.0f / sin_theta_left;
+ float32 inv_sin_theta_right = 1.0f / sin_theta_right;
+
+ float32 updateX_left = cos_theta_left * inv_sin_theta_left;
+ float32 updateX_right = cos_theta_right * inv_sin_theta_right;
+
+ // Precalculate kernel limits
+ float32 S_l = -0.5f * updateX_left;
+ if (S_l > 0) { S_l = -S_l; }
+ float32 T_l = -S_l;
+ float32 U_l = 1.0f + S_l;
+ float32 V_l = 1.0f - S_l;
+ float32 inv_4T_l = 0.25f / T_l;
+
+ float32 S_r = -0.5f * updateX_right;
+ if (S_r > 0) { S_r = -S_r; }
+ float32 T_r = -S_r;
+ float32 U_r = 1.0f + S_r;
+ float32 V_r = 1.0f - S_r;
+ float32 inv_4T_r = 0.25f / T_r;
+
+ // calculate strip extremes (volume coordinates)
+ float32 PL = (t_l - cos_theta_left * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_left;
+ float32 PR = (t_r - cos_theta_right * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_right;
+ float32 PLimitL = PL - S_l * PW;
+ float32 PLimitR = PR + S_r * PW;
+
+ // calculate strip extremes (pixel coordinates)
+ float32 XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH;
+ float32 XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH;
+ float32 xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH;
+ float32 xR = (m_pVolumeGeometry->getWindowMaxY() - PR) * inv_PH;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX_left;
+ XLimitR += updateX_right;
+ xL += updateX_left;
+ xR += updateX_right;
+
+ // for each affected row
+ for (row = x1L; row <= x1R; ++row) {
+
+ if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V_r) res = 1.0f;
+ else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r;
+ else if (x2R >= T_r) res = x2R;
+ else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S_l) {}
+ else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l;
+ else if (x2L <= U_l) res -= x2L;
+ else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end detector loop
+
+ } // end theta switch
+
+ } // end angle loop
+
+ delete[] cos_alpha;
+ delete[] sin_alpha;
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE PROJECTION
+template <typename Policy>
+void CFanFlatBeamStripKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ // Some variables
+ float32 theta;
+ int row, col;
+ int iDetector;
+ float32 res;
+ int x1L, x1R;
+ float32 x2L, x2R;
+ int iVolumeIndex, iRayIndex;
+
+ CFanFlatProjectionGeometry2D* projgeom = static_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry);
+
+ // Other precalculations
+ float32 PW = m_pVolumeGeometry->getPixelLengthX();
+ float32 PH = m_pVolumeGeometry->getPixelLengthY();
+ float32 DW = m_pProjectionGeometry->getDetectorWidth();
+ float32 inv_PW = 1.0f / PW;
+ float32 inv_PH = 1.0f / PH;
+
+ // calculate alpha's
+ float32 alpha;
+ float32* cos_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1];
+ float32* sin_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1];
+ for (int i = 0; i < m_pProjectionGeometry->getDetectorCount() + 1; ++i) {
+ alpha = -atan((i - m_pProjectionGeometry->getDetectorCount()*0.5f) * DW / projgeom->getSourceDetectorDistance());
+ cos_alpha[i] = cos(alpha);
+ sin_alpha[i] = sin(alpha);
+ }
+
+
+ // get values
+ theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ bool switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // Precalculate sin, cos, 1/cos
+ float32 sin_theta = sin(theta);
+ float32 cos_theta = cos(theta);
+
+ // [-45?,45?] and [135?,225?]
+ if (theta < PIdiv4) {
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ float32 sin_theta_left, cos_theta_left;
+ float32 sin_theta_right, cos_theta_right;
+
+ // get theta_l = alpha_left + theta and theta_r = alpha_right + theta
+ float32 t_l, t_r;
+ if (!switch_t) {
+ sin_theta_left = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1];
+ sin_theta_right = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector];
+
+ cos_theta_left = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1];
+ cos_theta_right = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector];
+
+ t_l = sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance();
+ t_r = sin_alpha[iDetector] * projgeom->getOriginSourceDistance();
+
+ } else {
+ sin_theta_left = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector];
+ sin_theta_right = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1];
+
+ cos_theta_left = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector];
+ cos_theta_right = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1];
+
+ t_l = -sin_alpha[iDetector] * projgeom->getOriginSourceDistance();
+ t_r = -sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance();
+ }
+
+ float32 inv_cos_theta_left = 1.0f / cos_theta_left;
+ float32 inv_cos_theta_right = 1.0f / cos_theta_right;
+
+ float32 updateX_left = sin_theta_left * inv_cos_theta_left;
+ float32 updateX_right = sin_theta_right * inv_cos_theta_right;
+
+ // Precalculate kernel limits
+ float32 S_l = -0.5f * updateX_left;
+ if (S_l > 0) {S_l = -S_l;}
+ float32 T_l = -S_l;
+ float32 U_l = 1.0f + S_l;
+ float32 V_l = 1.0f - S_l;
+ float32 inv_4T_l = 0.25f / T_l;
+
+ float32 S_r = -0.5f * updateX_right;
+ if (S_r > 0) {S_r = -S_r;}
+ float32 T_r = -S_r;
+ float32 U_r = 1.0f + S_r;
+ float32 V_r = 1.0f - S_r;
+ float32 inv_4T_r = 0.25f / T_r;
+
+ // calculate strip extremes (volume coordinates)
+ float32 PL = (t_l - sin_theta_left * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_left;
+ float32 PR = (t_r - sin_theta_right * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_right;
+ float32 PLimitL = PL + S_l * PH;
+ float32 PLimitR = PR - S_r * PH;
+
+ // calculate strip extremes (pixel coordinates)
+ float32 XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 xR = (PR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX_left;
+ XLimitR += updateX_right;
+ xL += updateX_left;
+ xR += updateX_right;
+
+ // for each affected col
+ for (col = x1L; col <= x1R; ++col) {
+
+ if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V_r) res = 1.0f;
+ else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r;
+ else if (x2R >= T_r) res = x2R;
+ else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S_l) {}
+ else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l;
+ else if (x2L <= U_l) res -= x2L;
+ else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end detector loop
+
+ // [45?,135?] and [225?,315?]
+ // horizontaly
+ } else {
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get theta_l = alpha_left + theta and theta_r = alpha_right + theta
+ float32 sin_theta_left, cos_theta_left;
+ float32 sin_theta_right, cos_theta_right;
+ float32 t_l, t_r;
+ if (!switch_t) {
+ sin_theta_left = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector];
+ sin_theta_right = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1];
+
+ cos_theta_left = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector];
+ cos_theta_right = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1];
+
+ t_l = sin_alpha[iDetector] * projgeom->getOriginSourceDistance();
+ t_r = sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance();
+
+ } else {
+ sin_theta_left = sin_theta * cos_alpha[iDetector+1] + cos_theta * sin_alpha[iDetector+1];
+ sin_theta_right = sin_theta * cos_alpha[iDetector] + cos_theta * sin_alpha[iDetector];
+
+ cos_theta_left = cos_theta * cos_alpha[iDetector+1] - sin_theta * sin_alpha[iDetector+1];
+ cos_theta_right = cos_theta * cos_alpha[iDetector] - sin_theta * sin_alpha[iDetector];
+
+ t_l = -sin_alpha[iDetector+1] * projgeom->getOriginSourceDistance();
+ t_r = -sin_alpha[iDetector] * projgeom->getOriginSourceDistance();
+ }
+
+ float32 inv_sin_theta_left = 1.0f / sin_theta_left;
+ float32 inv_sin_theta_right = 1.0f / sin_theta_right;
+
+ float32 updateX_left = cos_theta_left * inv_sin_theta_left;
+ float32 updateX_right = cos_theta_right * inv_sin_theta_right;
+
+ // Precalculate kernel limits
+ float32 S_l = -0.5f * updateX_left;
+ if (S_l > 0) { S_l = -S_l; }
+ float32 T_l = -S_l;
+ float32 U_l = 1.0f + S_l;
+ float32 V_l = 1.0f - S_l;
+ float32 inv_4T_l = 0.25f / T_l;
+
+ float32 S_r = -0.5f * updateX_right;
+ if (S_r > 0) { S_r = -S_r; }
+ float32 T_r = -S_r;
+ float32 U_r = 1.0f + S_r;
+ float32 V_r = 1.0f - S_r;
+ float32 inv_4T_r = 0.25f / T_r;
+
+ // calculate strip extremes (volume coordinates)
+ float32 PL = (t_l - cos_theta_left * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_left;
+ float32 PR = (t_r - cos_theta_right * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_right;
+ float32 PLimitL = PL - S_l * PW;
+ float32 PLimitR = PR + S_r * PW;
+
+ // calculate strip extremes (pixel coordinates)
+ float32 XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH;
+ float32 XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH;
+ float32 xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH;
+ float32 xR = (m_pVolumeGeometry->getWindowMaxY() - PR) * inv_PH;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX_left;
+ XLimitR += updateX_right;
+ xL += updateX_left;
+ xR += updateX_right;
+
+ // for each affected row
+ for (row = x1L; row <= x1R; ++row) {
+
+ if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V_r) res = 1.0f;
+ else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r;
+ else if (x2R >= T_r) res = x2R;
+ else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S_l) {}
+ else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l;
+ else if (x2L <= U_l) res -= x2L;
+ else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end detector loop
+
+ } // end theta switch
+
+ delete[] cos_alpha;
+ delete[] sin_alpha;
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE RAY
+template <typename Policy>
+void CFanFlatBeamStripKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ // Some variables
+ float32 theta;
+ int row, col;
+ float32 res;
+ int x1L, x1R;
+ float32 x2L, x2R;
+ int iVolumeIndex, iRayIndex;
+
+ CFanFlatProjectionGeometry2D* projgeom = static_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry);
+
+ // Other precalculations
+ float32 PW = m_pVolumeGeometry->getPixelLengthX();
+ float32 PH = m_pVolumeGeometry->getPixelLengthY();
+ float32 DW = m_pProjectionGeometry->getDetectorWidth();
+ float32 inv_PW = 1.0f / PW;
+ float32 inv_PH = 1.0f / PH;
+
+ // calculate alpha's
+ float32 alpha;
+ float32* cos_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1];
+ float32* sin_alpha = new float32[m_pProjectionGeometry->getDetectorCount() + 1];
+ for (int i = 0; i < m_pProjectionGeometry->getDetectorCount() + 1; ++i) {
+ alpha = -atan((i - m_pProjectionGeometry->getDetectorCount()*0.5f) * DW / projgeom->getSourceDetectorDistance());
+ cos_alpha[i] = cos(alpha);
+ sin_alpha[i] = sin(alpha);
+ }
+
+
+ // get values
+ theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ bool switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // Precalculate sin, cos, 1/cos
+ float32 sin_theta = sin(theta);
+ float32 cos_theta = cos(theta);
+
+ // [-45?,45?] and [135?,225?]
+ if (theta < PIdiv4) {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) { delete[] cos_alpha; delete[] sin_alpha; return; }
+
+ float32 sin_theta_left, cos_theta_left;
+ float32 sin_theta_right, cos_theta_right;
+
+ // get theta_l = alpha_left + theta and theta_r = alpha_right + theta
+ float32 t_l, t_r;
+ if (!switch_t) {
+ sin_theta_left = sin_theta * cos_alpha[_iDetector+1] + cos_theta * sin_alpha[_iDetector+1];
+ sin_theta_right = sin_theta * cos_alpha[_iDetector] + cos_theta * sin_alpha[_iDetector];
+
+ cos_theta_left = cos_theta * cos_alpha[_iDetector+1] - sin_theta * sin_alpha[_iDetector+1];
+ cos_theta_right = cos_theta * cos_alpha[_iDetector] - sin_theta * sin_alpha[_iDetector];
+
+ t_l = sin_alpha[_iDetector+1] * projgeom->getOriginSourceDistance();
+ t_r = sin_alpha[_iDetector] * projgeom->getOriginSourceDistance();
+
+ } else {
+ sin_theta_left = sin_theta * cos_alpha[_iDetector] + cos_theta * sin_alpha[_iDetector];
+ sin_theta_right = sin_theta * cos_alpha[_iDetector+1] + cos_theta * sin_alpha[_iDetector+1];
+
+ cos_theta_left = cos_theta * cos_alpha[_iDetector] - sin_theta * sin_alpha[_iDetector];
+ cos_theta_right = cos_theta * cos_alpha[_iDetector+1] - sin_theta * sin_alpha[_iDetector+1];
+
+ t_l = -sin_alpha[_iDetector] * projgeom->getOriginSourceDistance();
+ t_r = -sin_alpha[_iDetector+1] * projgeom->getOriginSourceDistance();
+ }
+
+ float32 inv_cos_theta_left = 1.0f / cos_theta_left;
+ float32 inv_cos_theta_right = 1.0f / cos_theta_right;
+
+ float32 updateX_left = sin_theta_left * inv_cos_theta_left;
+ float32 updateX_right = sin_theta_right * inv_cos_theta_right;
+
+ // Precalculate kernel limits
+ float32 S_l = -0.5f * updateX_left;
+ if (S_l > 0) {S_l = -S_l;}
+ float32 T_l = -S_l;
+ float32 U_l = 1.0f + S_l;
+ float32 V_l = 1.0f - S_l;
+ float32 inv_4T_l = 0.25f / T_l;
+
+ float32 S_r = -0.5f * updateX_right;
+ if (S_r > 0) {S_r = -S_r;}
+ float32 T_r = -S_r;
+ float32 U_r = 1.0f + S_r;
+ float32 V_r = 1.0f - S_r;
+ float32 inv_4T_r = 0.25f / T_r;
+
+ // calculate strip extremes (volume coordinates)
+ float32 PL = (t_l - sin_theta_left * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_left;
+ float32 PR = (t_r - sin_theta_right * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta_right;
+ float32 PLimitL = PL + S_l * PH;
+ float32 PLimitR = PR - S_r * PH;
+
+ // calculate strip extremes (pixel coordinates)
+ float32 XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ float32 xR = (PR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX_left;
+ XLimitR += updateX_right;
+ xL += updateX_left;
+ xR += updateX_right;
+
+ // for each affected col
+ for (col = x1L; col <= x1R; ++col) {
+
+ if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V_r) res = 1.0f;
+ else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r;
+ else if (x2R >= T_r) res = x2R;
+ else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S_l) {}
+ else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l;
+ else if (x2L <= U_l) res -= x2L;
+ else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ // [45?,135?] and [225?,315?]
+ // horizontaly
+ } else {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) { delete[] cos_alpha; delete[] sin_alpha; return; }
+
+ // get theta_l = alpha_left + theta and theta_r = alpha_right + theta
+ float32 sin_theta_left, cos_theta_left;
+ float32 sin_theta_right, cos_theta_right;
+ float32 t_l, t_r;
+ if (!switch_t) {
+ sin_theta_left = sin_theta * cos_alpha[_iDetector] + cos_theta * sin_alpha[_iDetector];
+ sin_theta_right = sin_theta * cos_alpha[_iDetector+1] + cos_theta * sin_alpha[_iDetector+1];
+
+ cos_theta_left = cos_theta * cos_alpha[_iDetector] - sin_theta * sin_alpha[_iDetector];
+ cos_theta_right = cos_theta * cos_alpha[_iDetector+1] - sin_theta * sin_alpha[_iDetector+1];
+
+ t_l = sin_alpha[_iDetector] * projgeom->getOriginSourceDistance();
+ t_r = sin_alpha[_iDetector+1] * projgeom->getOriginSourceDistance();
+
+ } else {
+ sin_theta_left = sin_theta * cos_alpha[_iDetector+1] + cos_theta * sin_alpha[_iDetector+1];
+ sin_theta_right = sin_theta * cos_alpha[_iDetector] + cos_theta * sin_alpha[_iDetector];
+
+ cos_theta_left = cos_theta * cos_alpha[_iDetector+1] - sin_theta * sin_alpha[_iDetector+1];
+ cos_theta_right = cos_theta * cos_alpha[_iDetector] - sin_theta * sin_alpha[_iDetector];
+
+ t_l = -sin_alpha[_iDetector+1] * projgeom->getOriginSourceDistance();
+ t_r = -sin_alpha[_iDetector] * projgeom->getOriginSourceDistance();
+ }
+
+ float32 inv_sin_theta_left = 1.0f / sin_theta_left;
+ float32 inv_sin_theta_right = 1.0f / sin_theta_right;
+
+ float32 updateX_left = cos_theta_left * inv_sin_theta_left;
+ float32 updateX_right = cos_theta_right * inv_sin_theta_right;
+
+ // Precalculate kernel limits
+ float32 S_l = -0.5f * updateX_left;
+ if (S_l > 0) { S_l = -S_l; }
+ float32 T_l = -S_l;
+ float32 U_l = 1.0f + S_l;
+ float32 V_l = 1.0f - S_l;
+ float32 inv_4T_l = 0.25f / T_l;
+
+ float32 S_r = -0.5f * updateX_right;
+ if (S_r > 0) { S_r = -S_r; }
+ float32 T_r = -S_r;
+ float32 U_r = 1.0f + S_r;
+ float32 V_r = 1.0f - S_r;
+ float32 inv_4T_r = 0.25f / T_r;
+
+ // calculate strip extremes (volume coordinates)
+ float32 PL = (t_l - cos_theta_left * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_left;
+ float32 PR = (t_r - cos_theta_right * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta_right;
+ float32 PLimitL = PL - S_l * PW;
+ float32 PLimitR = PR + S_r * PW;
+
+ // calculate strip extremes (pixel coordinates)
+ float32 XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH;
+ float32 XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH;
+ float32 xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH;
+ float32 xR = (m_pVolumeGeometry->getWindowMaxY() - PR) * inv_PH;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX_left;
+ XLimitR += updateX_right;
+ xL += updateX_left;
+ xR += updateX_right;
+
+ // for each affected row
+ for (row = x1L; row <= x1R; ++row) {
+
+ if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V_r) res = 1.0f;
+ else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r;
+ else if (x2R >= T_r) res = x2R;
+ else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S_l) {}
+ else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l;
+ else if (x2L <= U_l) res -= x2L;
+ else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end theta switch
+
+ delete[] cos_alpha;
+ delete[] sin_alpha;
+}
diff --git a/include/astra/FanFlatProjectionGeometry2D.h b/include/astra/FanFlatProjectionGeometry2D.h
new file mode 100644
index 0000000..0e790ae
--- /dev/null
+++ b/include/astra/FanFlatProjectionGeometry2D.h
@@ -0,0 +1,244 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FANFLATPROJECTIONGEOMETRY2D
+#define _INC_ASTRA_FANFLATPROJECTIONGEOMETRY2D
+
+#include "ProjectionGeometry2D.h"
+
+#include <cmath>
+
+namespace astra
+{
+
+/**
+ * This class defines a 2D fan beam geometry with a flat detector that has equally spaced detector cells.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{DetectorCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorWidth, float, Width of each detector.}
+ * \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.}
+ * \astra_xml_item{DistanceOriginDetector, float, Distance between the center of rotation and the detectorarray.}
+ * \astra_xml_item{DistanceOriginSource, float, Distance between the center of rotation the the x-ray source.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * proj_geom = astra_struct('fanflat');\n
+ * proj_geom.DetectorCount = 512;\n
+ * proj_geom.DetectorWidth = 1.0;\n
+ * proj_geom.ProjectionAngles = linspace(0,pi,100);\n
+ * proj_geom.DistanceOriginDetector = 300;\n
+ * proj_geom.DistanceOriginSource = 300;\n
+ * }
+ */
+class _AstraExport CFanFlatProjectionGeometry2D : public CProjectionGeometry2D
+{
+ /**
+ * Distance from the origin of the coordinate system to the source.
+ */
+ float32 m_fOriginSourceDistance;
+
+ /**
+ * Distance from the origin of the coordinate system to the detector (i.e., the distance between the origin and its orthogonal projection
+ * onto the detector array).
+ */
+ float32 m_fOriginDetectorDistance;
+
+public:
+
+ /** Default constructor. Sets all variables to zero. Note that this constructor leaves the object in an unusable state and must
+ * be followed by a call to init().
+ */
+ CFanFlatProjectionGeometry2D();
+
+ /** Constructor.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ * All angles are represented in radians.
+ * @param _fOriginSourceDistance Distance from the origin of the coordinate system to the source
+ * @param _fOriginDetectorDistance Distance from the origin of the coordinate system to the detector
+ */
+ CFanFlatProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ float32 _fOriginSourceDistance,
+ float32 _fOriginDetectorDistance);
+
+ /** Copy constructor.
+ */
+ CFanFlatProjectionGeometry2D(const CFanFlatProjectionGeometry2D& _projGeom);
+
+ /** Assignment operator.
+ */
+ CFanFlatProjectionGeometry2D& operator=(const CFanFlatProjectionGeometry2D& _other);
+
+ /** Destructor.
+ */
+ virtual ~CFanFlatProjectionGeometry2D();
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialization. This function MUST be called after using the default constructor and MAY be called to
+ * reset a previously initialized object.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ * @param _fOriginSourceDistance Distance from the origin of the coordinate system to the source
+ * @param _fOriginDetectorDistance Distance from the origin of the coordinate system to the detector
+ */
+ bool initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ float32 _fOriginSourceDistance,
+ float32 _fOriginDetectorDistance);
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry2D* clone();
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if _sType == "fanflat".
+ */
+ virtual bool isOfType(const std::string& _sType);
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(CProjectionGeometry2D*) const;
+
+ /** Returns the distance from the origin of the coordinate system to the source.
+ *
+ * @return Distance from the origin of the coordinate system to the source
+ */
+ float32 getOriginSourceDistance() const;
+
+ /** Returns the distance from the origin of the coordinate system to the detector
+ * (i.e., the distance between the origin and its orthogonal projection onto the detector array).
+ *
+ * @return Distance from the origin of the coordinate system to the detector
+ */
+ float32 getOriginDetectorDistance() const;
+
+ /** Returns the distance from the source to the detector
+ * (i.e., the distance between the source and its orthogonal projection onto the detector array).
+ *
+ * @return Distance from the source to the detector
+ */
+ float32 getSourceDetectorDistance() const;
+
+ /** Get the value for t and theta, based upon the row and column index.
+ *
+ * @param _iRow row index
+ * @param _iColumn column index
+ * @param _fT output: value of t
+ * @param _fTheta output: value of theta, always lies within the [0,pi[ interval.
+ */
+ virtual void getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const;
+
+ /**
+ * Returns a vector describing the direction of a ray belonging to a certain detector
+ *
+ * @param _iProjectionIndex index of projection
+ * @param _iProjectionIndex index of detector
+ *
+ * @return a unit vector describing the direction
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex);
+};
+
+
+
+// Returns the distance from the origin of the coordinate system to the source.
+inline float32 CFanFlatProjectionGeometry2D::getOriginSourceDistance() const
+{
+ return m_fOriginSourceDistance;
+}
+
+
+// Returns the distance from the origin of the coordinate system to the detector.
+inline float32 CFanFlatProjectionGeometry2D::getOriginDetectorDistance() const
+{
+ return m_fOriginDetectorDistance;
+}
+
+
+// Returns the distance from the source to the detector.
+inline float32 CFanFlatProjectionGeometry2D::getSourceDetectorDistance() const
+{
+ return (m_fOriginSourceDistance + m_fOriginDetectorDistance);
+}
+
+
+// Get T and Theta
+inline void CFanFlatProjectionGeometry2D::getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const
+{
+ assert(m_bInitialized);
+
+ // get the distance between the center of the detector array and the detector.
+ float32 det_offset = indexToDetectorOffset(_iColumn);
+
+ // get the angle between the center ray of the projection and the projection.
+ float32 alpha = atan(det_offset / getSourceDetectorDistance());
+
+ // calculate t and theta
+ _fT = m_fOriginSourceDistance * sin(alpha);
+ _fTheta = getProjectionAngle(_iRow) + alpha;
+
+ // if theta is larger than pi, flip of the origin
+ if (PI <= _fTheta) {
+ _fTheta -= PI;
+ _fT = -_fT;
+ }
+ // if theta is below 0, flip
+ if (_fTheta < 0) {
+ _fTheta += PI;
+ _fT = -_fT;
+ }
+}
+
+
+
+} // namespace astra
+
+#endif /* _INC_ASTRA_FANFLATPROJECTIONGEOMETRY2D */
+
diff --git a/include/astra/FanFlatVecProjectionGeometry2D.h b/include/astra/FanFlatVecProjectionGeometry2D.h
new file mode 100644
index 0000000..d370b24
--- /dev/null
+++ b/include/astra/FanFlatVecProjectionGeometry2D.h
@@ -0,0 +1,155 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FANFLATVECPROJECTIONGEOMETRY2D
+#define _INC_ASTRA_FANFLATVECPROJECTIONGEOMETRY2D
+
+#include "ProjectionGeometry2D.h"
+#include "../cuda/2d/dims.h"
+
+#include <cmath>
+
+// FIXME: Avoid using
+using astraCUDA::SFanProjection;
+
+namespace astra
+{
+
+/**
+ * This class defines a 2D fan beam geometry.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{DetectorCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{Vectors, matrix defining the 2D position of source and detector.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * proj_geom = astra_struct('fanflat_vec');\n
+ * proj_geom.DetectorCount = 512;\n
+ * proj_geom.Vectors = V;\n
+ * }
+ */
+class _AstraExport CFanFlatVecProjectionGeometry2D : public CProjectionGeometry2D
+{
+protected:
+
+ SFanProjection *m_pProjectionAngles;
+
+public:
+
+ /** Default constructor. Sets all variables to zero. Note that this constructor leaves the object in an unusable state and must
+ * be followed by a call to init().
+ */
+ CFanFlatVecProjectionGeometry2D();
+
+ /** Constructor.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ CFanFlatVecProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ const SFanProjection* _pfProjectionAngles);
+
+ /** Copy constructor.
+ */
+ CFanFlatVecProjectionGeometry2D(const CFanFlatVecProjectionGeometry2D& _projGeom);
+
+ /** Assignment operator.
+ */
+ CFanFlatVecProjectionGeometry2D& operator=(const CFanFlatVecProjectionGeometry2D& _other);
+
+ /** Destructor.
+ */
+ virtual ~CFanFlatVecProjectionGeometry2D();
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialization. This function MUST be called after using the default constructor and MAY be called to
+ * reset a previously initialized object.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ bool initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ const SFanProjection* _pfProjectionAngles);
+
+ virtual bool _check();
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry2D* clone();
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if _sType == "fanflat_vec".
+ */
+ virtual bool isOfType(const std::string& _sType);
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(CProjectionGeometry2D*) const;
+
+ /** Get the value for t and theta, based upon the row and column index.
+ *
+ * @param _iRow row index
+ * @param _iColumn column index
+ * @param _fT output: value of t
+ * @param _fTheta output: value of theta, always lies within the [0,pi[ interval.
+ */
+ virtual void getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const;
+
+ /**
+ * Returns a vector describing the direction of a ray belonging to a certain detector
+ *
+ * @param _iProjectionIndex index of projection
+ * @param _iProjectionIndex index of detector
+ *
+ * @return a unit vector describing the direction
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex);
+
+ const SFanProjection* getProjectionVectors() const { return m_pProjectionAngles; }
+};
+
+
+} // namespace astra
+
+#endif /* _INC_ASTRA_FANFLATVECPROJECTIONGEOMETRY2D */
+
diff --git a/include/astra/FilteredBackProjectionAlgorithm.h b/include/astra/FilteredBackProjectionAlgorithm.h
new file mode 100644
index 0000000..cda7962
--- /dev/null
+++ b/include/astra/FilteredBackProjectionAlgorithm.h
@@ -0,0 +1,155 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FILTEREDBACKPROJECTION
+#define _INC_ASTRA_FILTEREDBACKPROJECTION
+
+#include "ReconstructionAlgorithm2D.h"
+
+#include "Globals.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains the implementation of the filtered back projection (FBP)
+ * reconstruction algorithm.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{VolumeDataId, integer, Identifier of the volume data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of the resulting projection data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ProjectionIndex, integer, 0, Only reconstruct this specific projection angle. }
+
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('FP');\n
+ * cfg.ProjectorId = proj_id;\n
+ * cfg.ReconstructionDataId = vol_id;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('run'\, alg_id);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ */
+class _AstraExport CFilteredBackProjectionAlgorithm : public CReconstructionAlgorithm2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - valid projector
+ * - valid data objects
+ * - projection order all within range
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CFilteredBackProjectionAlgorithm();
+
+ /** Destructor.
+ */
+ virtual ~CFilteredBackProjectionAlgorithm();
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector to use.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @return success
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32VolumeData2D* _pReconstruction,
+ CFloat32ProjectionData2D* _pSinogram);
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Performs the filtering of the projection data.
+ *
+ * @param _pFilteredSinogram will contain filtered sinogram afterwards
+ */
+ void performFiltering(CFloat32ProjectionData2D * _pFilteredSinogram);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+};
+
+// inline functions
+inline std::string CFilteredBackProjectionAlgorithm::description() const { return CFilteredBackProjectionAlgorithm::type; };
+
+} // end namespace
+
+#endif
diff --git a/include/astra/Float32Data.h b/include/astra/Float32Data.h
new file mode 100644
index 0000000..99bbaf3
--- /dev/null
+++ b/include/astra/Float32Data.h
@@ -0,0 +1,88 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32DATA
+#define _INC_ASTRA_FLOAT32DATA
+
+#include "Globals.h"
+
+namespace astra {
+
+/**
+ * This is a virtual base class for floating point data classes.
+ */
+class _AstraExport CFloat32Data {
+
+protected:
+
+ // Protected Member Variables
+ bool m_bInitialized; ///< has the object been initialized?
+ int m_iDimensions; ///< the number of dimensions
+
+public:
+
+ /**
+ * Default constructor.
+ */
+ CFloat32Data();
+
+ /**
+ * Destructor. Free allocated memory
+ */
+ virtual ~CFloat32Data();
+
+ /**
+ * Get the initialization state of the object.
+ *
+ * @return true iff the object has been initialized
+ */
+ bool isInitialized() const;
+
+ /**
+ * Get the number of dimensions of this object.
+ *
+ * @return number of dimensions
+ */
+ virtual int getDimensionCount() const = 0;
+
+};
+
+//----------------------------------------------------------------------------------------
+// Inline member functions
+//----------------------------------------------------------------------------------------
+
+// Get the initialization state of the object.
+inline bool CFloat32Data::isInitialized() const
+{
+ return m_bInitialized;
+}
+//----------------------------------------------------------------------------------------
+
+} // end namespace
+
+#endif
diff --git a/include/astra/Float32Data2D.h b/include/astra/Float32Data2D.h
new file mode 100644
index 0000000..c89e9f8
--- /dev/null
+++ b/include/astra/Float32Data2D.h
@@ -0,0 +1,544 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32DATA2D
+#define _INC_ASTRA_FLOAT32DATA2D
+
+#include "Globals.h"
+#include "Float32Data.h"
+
+#include <sstream>
+
+namespace astra {
+
+/**
+ * This class represents a two-dimensional block of float32ing point data.
+ * It contains member functions for accessing this data and for performing
+ * elementary computations on the data.
+ * The data block is "owned" by the class, meaning that the class is
+ * responsible for deallocation of the memory involved.
+ */
+class _AstraExport CFloat32Data2D : public CFloat32Data {
+
+protected:
+
+ int m_iWidth; ///< width of the data (x)
+ int m_iHeight; ///< height of the data (y)
+ int m_iSize; ///< total size of the data
+
+ /** Pointer to the data block, represented as a 1-dimensional array.
+ * Note that the data memory is "owned" by this class, meaning that the
+ * class is responsible for deallocation of the memory involved.
+ * To access element (ix, iy) internally, use
+ * m_pData[iy * m_iWidth + ix]
+ */
+ float32* m_pfData;
+
+ /** Array of float32 pointers, each pointing to a single horizontal
+ * line in the m_pfData memory block.
+ * To access element (ix, iy) internally, use m_ppfData2D[iy][ix]
+ */
+ float32** m_ppfData2D;
+
+ float32 m_fGlobalMin; ///< minimum value of the data
+ float32 m_fGlobalMax; ///< maximum value of the data
+ float32 m_fGlobalMean; ///< mean value of the data
+
+ /** Allocate memory for m_pfData and m_ppfData2D arrays.
+ *
+ * The allocated block consists of m_iSize float32s. The block is
+ * not cleared after allocation and its contents is undefined.
+ * This function may NOT be called if memory has already been allocated.
+ */
+ void _allocateData();
+
+ /** Free memory for m_pfData and m_ppfData2D arrays.
+ *
+ * This function may ONLY be called if the memory for both blocks has been
+ * allocated before.
+ */
+ void _freeData();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ */
+ void _clear();
+
+ /** Un-initialize the object, bringing it back in the uninitialized state.
+ */
+ void _unInit();
+
+ /** Find the minimum and maximum data value and store them in
+ * m_fGlobalMin and m_fGlobalMax
+ */
+ void _computeGlobalMinMax();
+
+ /** Initialization. Initializes an instance of the CFloat32Data2D class, without filling the data block.
+ * Can only be called by derived classes.
+ *
+ * Initializes an instance of the CFloat32Data2D class. Memory is allocated for the
+ * data block. The allocated memory is not cleared and its contents after
+ * construction is undefined. Initialization may be followed by a call to
+ * copyData() to fill the memory block. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ * This function does not set m_bInitialized to true if everything is ok.
+ *
+ * @param _iWidth width of the 2D data (x-axis), must be > 0
+ * @param _iHeight height of the 2D data (y-axis), must be > 0
+ * @return initialization of the base class successfull
+ */
+ bool _initialize(int _iWidth, int _iHeight);
+
+ /** Initialization. Initializes an instance of the CFloat32Data2D class with initialization of the data block.
+ * Can only be called by derived classes.
+ *
+ * Initializes an instance of the CFloat32Data2D class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ * This function does not set m_bInitialized to true if everything is ok.
+ *
+ * @param _iWidth width of the 2D data (x-axis), must be > 0
+ * @param _iHeight height of the 2D data (y-axis), must be > 0
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ bool _initialize(int _iWidth, int _iHeight, const float32* _pfData);
+
+ /** Initialization. Initializes an instance of the CFloat32Data2D class with initialization of the data
+ * block with a scalar value. Can only be called by derived classes.
+ *
+ * Initializes an instance of the CFloat32Data2D class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ * This function does not set m_bInitialized to true if everything is ok.
+ *
+ * @param _iWidth width of the 2D data (x-axis), must be > 0
+ * @param _iHeight height of the 2D data (y-axis), must be > 0
+ * @param _fScalar scalar value to put at each index
+ */
+ bool _initialize(int _iWidth, int _iHeight, float32 _fScalar);
+
+ /** Constructor. Create an instance of the CFloat32Data2D class without initializing the data block.
+ * Can only be called by derived classes.
+ *
+ * Creates an instance of the CFloat32Data2D class. Memory is allocated for the
+ * data block. The allocated memory is not cleared and its contents after
+ * construction is undefined. Construction may be followed by a call to
+ * copyData() to fill the memory block.
+ *
+ * @param _iWidth width of the 2D data (x-axis), must be > 0
+ * @param _iHeight height of the 2D data (y-axis), must be > 0
+ */
+ CFloat32Data2D(int _iWidth, int _iHeight);
+
+ /** Constructor. Create an instance of the CFloat32Data2D class with initialization of the data block.
+ * Can only be called by derived classes.
+ *
+ * Creates an instance of the CFloat32Data2D class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ *
+ * @param _iWidth width of the 2D data (x-axis), must be > 0
+ * @param _iHeight height of the 2D data (y-axis), must be > 0
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ CFloat32Data2D(int _iWidth, int _iHeight, const float32* _pfData);
+
+ /** Constructor. Create an instance of the CFloat32Data2D class with initialization of the data block
+ * with a scalar value. Can only be called by derived classes.
+ *
+ * Creates an instance of the CFloat32Data2D class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ *
+ * @param _iWidth width of the 2D data (x-axis), must be > 0
+ * @param _iHeight height of the 2D data (y-axis), must be > 0
+ * @param _fScalar scalar value to put at each index
+ */
+ CFloat32Data2D(int _iWidth, int _iHeight, float32 _fScalar);
+
+ /** Copy constructor.
+ */
+ CFloat32Data2D(const CFloat32Data2D&);
+
+public:
+
+ /** Typedef with available datatypes: BASE, PROJECTION, VOLUME.
+ */
+ typedef enum {BASE,
+ PROJECTION,
+ VOLUME} EDataType;
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the initialize() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ *
+ */
+ CFloat32Data2D();
+
+ /** Destructor. Free allocated memory
+ */
+ virtual ~CFloat32Data2D();
+
+ /** Copy the data block pointed to by _pfData to the data block pointed to by m_pfData.
+ * The pointer _pfData must point to a block of m_iSize float32s.
+ *
+ * @param _pfData source data block
+ */
+ void copyData(const float32* _pfData);
+
+ /** scale the grey value of the data from 0-255.
+ *
+ */
+ void scale();
+
+ /** Set each element of the data to a specified scalar value.
+ *
+ * @param _fScalar scalar value
+ */
+ void setData(float32 _fScalar);
+
+ /** Set all data to zero
+ */
+ void clearData();
+
+ /** Get a pointer to the data block, represented as a 1-dimensional
+ * array of float32 values. The data memory is still "owned" by the
+ * CFloat32Data2D instance; this memory may NEVER be freed by the
+ * caller of this function. If changes are made to this data, the
+ * function updateStatistics() should be called after completion of
+ * all changes.
+ *
+ * @return pointer to the 1-dimensional 32-bit floating point data block
+ */
+ float32* getData();
+
+ /** Get a const pointer to the data block, represented as a 1-dimensional
+ * array of float32 values. The data memory is still "owned" by the
+ * CFloat32Data2D instance; this memory may NEVER be freed by the
+ * caller of this function. If changes are made to this data, the
+ * function updateStatistics() should be called after completion of
+ * all changes.
+ *
+ * @return pointer to the 1-dimensional 32-bit floating point data block
+ */
+ const float32* getDataConst() const;
+
+ /** Get a float32** to the data block, represented as a 2-dimensional array of float32 values.
+ *
+ * After the call p = getData2D(), use p[iy][ix] to access element (ix, iy).
+ * The data memory and pointer array are still "owned" by the CFloat32Data2D
+ * instance; this memory may NEVER be freed by the caller of this function.
+ * If changes are made to this data, the function updateStatistics()
+ * should be called after completion of all changes.
+ *
+ * @return pointer to the 2-dimensional 32-bit floating point data block
+ */
+ float32** getData2D();
+
+ /** Get a const float32** to the data block, represented as a 2-dimensional array of float32 values.
+ *
+ * After the call p = getData2D(), use p[iy][ix] to access element (ix, iy).
+ * The data memory and pointer array are still "owned" by the CFloat32Data2D
+ * instance; this memory may NEVER be freed by the caller of this function.
+ * If changes are made to this data, the function updateStatistics()
+ * should be called after completion of all changes.
+ *
+ * @return pointer to the 2-dimensional 32-bit floating point data block
+ */
+ const float32** getData2DConst() const;
+
+ /** Update data statistics, such as minimum and maximum value, after the data has been modified.
+ */
+ virtual void updateStatistics();
+
+ /** Get the minimum value in the data block.
+ * If the data has been changed after construction, the function
+ * updateStatistics() must be called at least once before
+ * a query can be made on this value.
+ *
+ * @return minimum value in the data block
+ */
+ virtual float32 getGlobalMin() const;
+
+ /** Get the maximum value in the data block
+ * If the data has been changed after construction, the function
+ * updateStatistics() must be called at least once before
+ * a query can be made on this value.
+ *
+ * @return maximum value in the data block
+ */
+ virtual float32 getGlobalMax() const;
+
+ /** Get the mean value in the data block
+ * If the data has been changed after construction, the function
+ * updateStatistics() must be called at least once before
+ * a query can be made on this value.
+ *
+ * @return maximum value in the data block
+ */
+ virtual float32 getGlobalMean() const;
+
+
+ /** Get the width of the data block.
+ *
+ * @return width of the data block
+ */
+ int getWidth() const;
+
+ /** Get the height of the data block.
+ *
+ * @return height of the data block
+ */
+ int getHeight() const;
+
+ /** Get the total size (width*height) of the data block.
+ *
+ * @return size of the data block
+ */
+ int getSize() const;
+
+ /** which type is this class?
+ *
+ * @return DataType: ASTRA_DATATYPE_FLOAT32_PROJECTION or
+ * ASTRA_DATATYPE_FLOAT32_VOLUME
+ */
+ virtual EDataType getType() const;
+
+ /** get a description of the class
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Get the number of dimensions of this object.
+ *
+ * @return number of dimensions
+ */
+ int getDimensionCount() const;
+
+ /**
+ * Clamp data to minimum value
+ *
+ * @param _fMin minimum value
+ * @return l-value
+ */
+ CFloat32Data2D& clampMin(float32& _fMin);
+
+ /**
+ * Clamp data to maximum value
+ *
+ * @param _fMax maximum value
+ * @return l-value
+ */
+ CFloat32Data2D& clampMax(float32& _fMax);
+
+ /**
+ * Overloaded Operator: data += data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32Data2D& operator+=(const CFloat32Data2D& _data);
+
+ /**
+ * Overloaded Operator: data -= data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32Data2D& operator-=(const CFloat32Data2D& _data);
+
+ /**
+ * Overloaded Operator: data *= data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32Data2D& operator*=(const CFloat32Data2D& _data);
+
+ /**
+ * Overloaded Operator: data *= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32Data2D& operator*=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data /= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32Data2D& operator/=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data += scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32Data2D& operator+=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data -= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32Data2D& operator-=(const float32& _fScalar);
+
+ CFloat32Data2D& operator=(const CFloat32Data2D& _dataIn);
+
+ float32& getData(int _index);
+
+};
+
+
+//----------------------------------------------------------------------------------------
+// Inline member functions
+//----------------------------------------------------------------------------------------
+
+// Get the number of dimensions of this object.
+inline int CFloat32Data2D::getDimensionCount() const
+{
+ return 2;
+}
+
+//----------------------------------------------------------------------------------------
+inline std::string CFloat32Data2D::description() const
+{
+ std::stringstream res;
+ res << m_iWidth << "x" << m_iHeight;
+ if (getType() == CFloat32Data2D::PROJECTION) res << " sinogram data \t";
+ if (getType() == CFloat32Data2D::VOLUME) res << " volume data \t";
+ return res.str();
+}
+
+//----------------------------------------------------------------------------------------
+// Get the type of this object.
+inline CFloat32Data2D::EDataType CFloat32Data2D::getType() const
+{
+ return BASE;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the width of the data block.
+inline int CFloat32Data2D::getWidth() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iWidth;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the height of the data block.
+inline int CFloat32Data2D::getHeight() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iHeight;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the total size (width*height*depth) of the data block.
+inline int CFloat32Data2D::getSize() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iSize;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a pointer to the data block, represented as a 1-dimensional array of float32 values.
+inline float32* CFloat32Data2D::getData()
+{
+ //ASTRA_ASSERT(m_bInitialized);
+ return m_pfData;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a pointer to the data block, represented as a 1-dimensional array of float32 values.
+inline float32& CFloat32Data2D::getData(int _index)
+{
+ //ASTRA_ASSERT(m_bInitialized);
+ return m_pfData[_index];
+}
+
+//----------------------------------------------------------------------------------------
+// Get a const pointer to the data block, represented as a 1-dimensional array of float32 values.
+inline const float32* CFloat32Data2D::getDataConst() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return (const float32*)m_pfData;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a float32** to the data block, represented as a 2-dimensional array of float32 values.
+inline float32** CFloat32Data2D::getData2D()
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_ppfData2D;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a const float32** to the data block, represented as a 2-dimensional array of float32 values.
+inline const float32** CFloat32Data2D::getData2DConst() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return (const float32**)m_ppfData2D;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the minimum value in the data block.
+inline float32 CFloat32Data2D::getGlobalMin() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fGlobalMin;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the maximum value in the data block
+inline float32 CFloat32Data2D::getGlobalMax() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fGlobalMax;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the mean value in the data block
+inline float32 CFloat32Data2D::getGlobalMean() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fGlobalMean;
+}
+
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32DATA2D
diff --git a/include/astra/Float32Data3D.h b/include/astra/Float32Data3D.h
new file mode 100644
index 0000000..8666890
--- /dev/null
+++ b/include/astra/Float32Data3D.h
@@ -0,0 +1,199 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32DATA3D
+#define _INC_ASTRA_FLOAT32DATA3D
+
+#include "Globals.h"
+#include "Float32Data.h"
+#include "Float32Data2D.h"
+
+namespace astra {
+
+/**
+ * This class represents a three-dimensional block of float32ing point data.
+ */
+class _AstraExport CFloat32Data3D : public CFloat32Data {
+
+protected:
+
+ int m_iWidth; ///< width of the data (x)
+ int m_iHeight; ///< height of the data (y)
+ int m_iDepth; ///< depth of the data (z)
+ size_t m_iSize; ///< size of the data (width*height*depth)
+
+ /**
+ * Compares the size of two CFloat32Data instances.
+ *
+ * @param _pA CFloat32Data3D instance A
+ * @param _pB CFloat32Data3D instance B
+ * @return True if they have the same size
+ */
+ static bool _data3DSizesEqual(const CFloat32Data3D * _pA, const CFloat32Data3D * _pB);
+
+public:
+
+ typedef enum {BASE, PROJECTION, VOLUME} EDataType;
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ */
+ CFloat32Data3D();
+
+ /** Destructor.
+ */
+ virtual ~CFloat32Data3D();
+
+ /** Get the width of the data block.
+ *
+ * @return width of the data block
+ */
+ int getWidth() const;
+
+ /** Get the height of the data block.
+ *
+ * @return height of the data block
+ */
+ int getHeight() const;
+
+ /** Get the depth of the data block.
+ *
+ * @return depth of the data block
+ */
+ int getDepth() const;
+
+ /** Get the size of the data block.
+ *
+ * @return size of the data block
+ */
+ int getSize() const;
+
+ /** Which type is this class?
+ *
+ * @return DataType: PROJECTION or VOLUME
+ */
+ virtual EDataType getType() const;
+
+ /** Get the number of dimensions of this object.
+ *
+ * @return number of dimensions
+ */
+ int getDimensionCount() const;
+
+ /**
+ * Clamp data to minimum value
+ *
+ * @param _fMin minimum value
+ * @return l-value
+ */
+ virtual CFloat32Data3D& clampMin(float32& _fMin) = 0;
+
+ /**
+ * Clamp data to maximum value
+ *
+ * @param _fMax maximum value
+ * @return l-value
+ */
+ virtual CFloat32Data3D& clampMax(float32& _fMax) = 0;
+
+ /** get a description of the class
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+};
+//----------------------------------------------------------------------------------------
+
+
+
+//----------------------------------------------------------------------------------------
+// Get dimension count.
+inline int CFloat32Data3D::getDimensionCount() const
+{
+ return 3;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the width of the data block.
+inline int CFloat32Data3D::getWidth() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iWidth;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the height of the data block.
+inline int CFloat32Data3D::getHeight() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iHeight;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the height of the data block.
+inline int CFloat32Data3D::getDepth() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iDepth;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the size of the data block.
+inline int CFloat32Data3D::getSize() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iSize;
+}
+
+
+//----------------------------------------------------------------------------------------
+// get type
+inline CFloat32Data3D::EDataType CFloat32Data3D::getType() const
+{
+ return BASE;
+}
+
+//----------------------------------------------------------------------------------------
+// To String
+inline std::string CFloat32Data3D::description() const
+{
+ std::stringstream res;
+ res << m_iWidth << "x" << m_iHeight << "x" << m_iDepth;
+ if (getType() == CFloat32Data3D::PROJECTION) res << " sinogram data \t";
+ if (getType() == CFloat32Data3D::VOLUME) res << " volume data \t";
+ return res.str();
+}
+//----------------------------------------------------------------------------------------
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32DATA2D
diff --git a/include/astra/Float32Data3DMemory.h b/include/astra/Float32Data3DMemory.h
new file mode 100644
index 0000000..3a445b6
--- /dev/null
+++ b/include/astra/Float32Data3DMemory.h
@@ -0,0 +1,338 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32DATA3DMEMORY
+#define _INC_ASTRA_FLOAT32DATA3DMEMORY
+
+#include "Globals.h"
+#include "Float32Data3D.h"
+
+namespace astra {
+
+/**
+ * This class represents a three-dimensional block of float32ing point data.
+ * It contains member functions for accessing this data and for performing
+ * elementary computations on the data.
+ * The data block is "owned" by the class, meaning that the class is
+ * responsible for deallocation of the memory involved.
+ */
+class _AstraExport CFloat32Data3DMemory : public virtual CFloat32Data3D {
+
+protected:
+
+ /** Pointer to the data block, represented as a 1-dimensional array.
+ * Note that the data memory is "owned" by this class, meaning that the
+ * class is responsible for deallocation of the memory involved.
+ * To access element (ix, iy, iz) internally, use
+ * m_pData[iz * m_iWidth * m_iHeight + iy * m_iWidth + ix]
+ */
+ float32* m_pfData;
+
+ /** Array of float32 pointers, each pointing to a single row
+ * in the m_pfData memory block.
+ * To access element (ix, iy, iz) internally, use m_ppfDataRowInd[iz * m_iHeight + iy][ix]
+ */
+ float32** m_ppfDataRowInd;
+
+ /** Array of float32 pointers, each pointing to a single slice
+ * in the m_pfData memory block.
+ * To access element (ix, iy, iz) internally, use m_pppfDataSliceInd[iz][iy][ix]
+ */
+ float32*** m_pppfDataSliceInd;
+
+ float32 m_fGlobalMin; ///< minimum value of the data
+ float32 m_fGlobalMax; ///< maximum value of the data
+
+ /** Allocate memory for m_pfData, m_ppfDataRowInd and m_pppfDataSliceInd arrays.
+ *
+ * The allocated block consists of m_iSize float32s. The block is
+ * not cleared after allocation and its contents is undefined.
+ * This function may NOT be called if memory has already been allocated.
+ */
+ void _allocateData();
+
+ /** Free memory for m_pfData, m_ppfDataRowInd and m_pppfDataSliceInd arrays.
+ *
+ * This function may ONLY be called if the memory for both blocks has been
+ * allocated before.
+ */
+ void _freeData();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ */
+ void _clear();
+
+ /** Un-initialize the object, bringing it back in the unitialized state.
+ */
+ void _unInit();
+
+ /** Find the minimum and maximum data value and store them in
+ * m_fGlobalMin and m_fGlobalMax
+ */
+ void _computeGlobalMinMax();
+
+ /** Initialization. Initializes an instance of the CFloat32Data3DMemory class, without filling the data block.
+ * Can only be called by derived classes.
+ *
+ * Initializes an instance of the CFloat32Data3DMemory class. Memory is allocated for the
+ * data block. The allocated memory is not cleared and its contents after
+ * construction is undefined. Initialization may be followed by a call to
+ * copyData() to fill the memory block. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ * This function does not set m_bInitialized to true if everything is ok.
+ *
+ * @param _iWidth width of the 3D data (x-axis), must be > 0
+ * @param _iHeight height of the 3D data (y-axis), must be > 0
+ * @param _iDepth depth of the 3D data (z-axis), must be > 0
+ * @return initialization of the base class successfull
+ */
+ bool _initialize(int _iWidth, int _iHeight, int _iDepth);
+
+ /** Initialization. Initializes an instance of the CFloat32Data3DMemory class with initialization of the data block.
+ * Can only be called by derived classes.
+ *
+ * Initializes an instance of the CFloat32Data3DMemory class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ * This function does not set m_bInitialized to true if everything is ok.
+ *
+ * @param _iWidth width of the 2D data (x-axis), must be > 0
+ * @param _iHeight height of the 2D data (y-axis), must be > 0
+ * @param _iDepth depth of the 2D data (z-axis), must be > 0
+ * @param _pfData pointer to a one-dimensional float32 data block
+ * @return initialization of the base class successfull
+ */
+ bool _initialize(int _iWidth, int _iHeight, int _iDepth, const float32* _pfData);
+
+ /** Initialization. Initializes an instance of the CFloat32Data3DMemory class with initialization of the data block.
+ * Can only be called by derived classes.
+ *
+ * Initializes an instance of the CFloat32Data3DMemory class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ * This function does not set m_bInitialized to true if everything is ok.
+ *
+ * @param _iWidth width of the 2D data (x-axis), must be > 0
+ * @param _iHeight height of the 2D data (y-axis), must be > 0
+ * @param _iDepth depth of the 2D data (z-axis), must be > 0
+ * @param _fScalar scalar value to fill the data
+ * @return initialization of the base class successfull
+ */
+ bool _initialize(int _iWidth, int _iHeight, int _iDepth, float32 _fScalar);
+
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the initialize() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ *
+ */
+ CFloat32Data3DMemory();
+
+ /** Destructor. Free allocated memory
+ */
+ virtual ~CFloat32Data3DMemory();
+
+ /** Copy the data block pointed to by _pfData to the data block pointed to by m_pfData.
+ * The pointer _pfData must point to a block of m_iSize float32s.
+ *
+ * @param _pfData source data block
+ * @param _iSize total number of data elements, must be equal to the allocated size of the object.
+ */
+ void copyData(const float32* _pfData, size_t _iSize);
+
+ /** Set each element of the data to a specified scalar value.
+ *
+ * @param _fScalar scalar value
+ */
+ void setData(float32 _fScalar);
+
+ /** Set all data to zero
+ */
+ void clearData();
+
+ /** Get a pointer to the data block, represented as a 1-dimensional
+ * array of float32 values. The data memory is still "owned" by the
+ * CFloat32Data3DMemory instance; this memory may NEVER be freed by the
+ * caller of this function. If changes are made to this data, the
+ * function updateStatistics() should be called after completion of
+ * all changes.
+ *
+ * @return pointer to the 1-dimensional 32-bit floating point data block
+ */
+ float32* getData();
+
+ /** Get a const pointer to the data block, represented as a 1-dimensional
+ * array of float32 values. The data memory is still "owned" by the
+ * CFloat32Data3DMemory instance; this memory may NEVER be freed by the
+ * caller of this function. If changes are made to this data, the
+ * function updateStatistics() should be called after completion of
+ * all changes.
+ *
+ * @return pointer to the 1-dimensional 32-bit floating point data block
+ */
+ const float32* getDataConst() const;
+
+ /** Get a float32*** to the data block, represented as a 3-dimensional array of float32 values.
+ *
+ * After the call p = getData3D(), use p[iz][iy][ix] to access element (ix, iy, iz).
+ * The data memory and pointer array are still "owned" by the CFloat32Data3DMemory
+ * instance; this memory may NEVER be freed by the caller of this function.
+ * If changes are made to this data, the function updateStatistics()
+ * should be called after completion of all changes.
+ *
+ * @return pointer to the 3-dimensional 32-bit floating point data block
+ */
+ float32*** getData3D();
+
+ /** Get a const float32*** to the data block, represented as a 3-dimensional array of float32 values.
+ *
+ * After the call p = getData3D(), use p[iy][ix] to access element (ix, iy, iz).
+ * The data memory and pointer array are still "owned" by the CFloat32Data3DMemory
+ * instance; this memory may NEVER be freed by the caller of this function.
+ * If changes are made to this data, the function updateStatistics()
+ * should be called after completion of all changes.
+ *
+ * @return pointer to the 3-dimensional 32-bit floating point data block
+ */
+ const float32*** getData3DConst() const;
+
+ /** Update data statistics, such as minimum and maximum value, after the data has been modified.
+ */
+ virtual void updateStatistics();
+
+ /** Get the minimum value in the data block.
+ * If the data has been changed after construction, the function
+ * updateStatistics() must be called at least once before
+ * a query can be made on this value.
+ *
+ * @return minimum value in the data block
+ */
+ virtual float32 getGlobalMin() const;
+
+ /** Get the maximum value in the data block
+ * If the data has been changed after construction, the function
+ * updateStatistics() must be called at least once before
+ * a query can be made on this value.
+ *
+ * @return maximum value in the data block
+ */
+ virtual float32 getGlobalMax() const;
+
+ /** which type is this class?
+ *
+ * @return DataType: ASTRA_DATATYPE_FLOAT32_PROJECTION or
+ * ASTRA_DATATYPE_FLOAT32_VOLUME
+ */
+ virtual EDataType getType() const;
+
+ /**
+ * Clamp data to minimum value
+ *
+ * @param _fMin minimum value
+ * @return l-value
+ */
+ virtual CFloat32Data3D& clampMin(float32& _fMin);
+
+ /**
+ * Clamp data to maximum value
+ *
+ * @param _fMax maximum value
+ * @return l-value
+ */
+ virtual CFloat32Data3D& clampMax(float32& _fMax);
+};
+
+
+//----------------------------------------------------------------------------------------
+// Inline member functions
+//----------------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------------
+// Get the type of this object.
+inline CFloat32Data3DMemory::EDataType CFloat32Data3DMemory::getType() const
+{
+ return BASE;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the minimum value in the data block.
+inline float32 CFloat32Data3DMemory::getGlobalMin() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fGlobalMin;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the maximum value in the data block
+inline float32 CFloat32Data3DMemory::getGlobalMax() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fGlobalMax;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a pointer to the data block, represented as a 1-dimensional array of float32 values.
+inline float32* CFloat32Data3DMemory::getData()
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_pfData;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a const pointer to the data block, represented as a 1-dimensional array of float32 values.
+inline const float32* CFloat32Data3DMemory::getDataConst() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return (const float32*)m_pfData;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a float32** to the data block, represented as a 3-dimensional array of float32 values.
+inline float32*** CFloat32Data3DMemory::getData3D()
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_pppfDataSliceInd;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a const float32** to the data block, represented as a 3-dimensional array of float32 values.
+inline const float32*** CFloat32Data3DMemory::getData3DConst() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return (const float32***)m_pppfDataSliceInd;
+}
+//----------------------------------------------------------------------------------------
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32DATA2D
diff --git a/include/astra/Float32ProjectionData2D.h b/include/astra/Float32ProjectionData2D.h
new file mode 100644
index 0000000..d9fe51a
--- /dev/null
+++ b/include/astra/Float32ProjectionData2D.h
@@ -0,0 +1,247 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32PROJECTIONDATA2D
+#define _INC_ASTRA_FLOAT32PROJECTIONDATA2D
+
+#include "Float32Data2D.h"
+#include "ProjectionGeometry2D.h"
+
+namespace astra {
+
+/**
+ * This class represents two-dimensional Projection Data.
+ *
+ * It contains member functions for accessing this data and for performing
+ * elementary computations on the data.
+ * The data block is "owned" by the class, meaning that the class is
+ * responsible for deallocation of the memory involved.
+ *
+ * The projection data is stored as a series of consecutive rows, where
+ * each row contains the data for a single projection.
+ */
+class _AstraExport CFloat32ProjectionData2D : public CFloat32Data2D {
+
+public:
+
+ /**
+ * Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ *
+ */
+ CFloat32ProjectionData2D();
+
+ /**
+ * Constructor. Create an instance of the CFloat32ProjectionData2D class without initializing the data.
+ *
+ * Memory is allocated for the data block. The allocated memory is not cleared and
+ * its contents after construction is undefined. Construction may be followed by a
+ * call to copyData() to fill the memory block.
+ * The size of the data is determined by the specified projection geometry object.
+ *
+ * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class.
+ */
+ CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry);
+
+ /**
+ * Constructor. Create an instance of the CFloat32ProjectionData2D class with initialization of the data.
+ *
+ * Creates an instance of the CFloat32ProjectionData2D class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified projection geometry object.
+ *
+ * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class.
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32* _pfData);
+
+ /**
+ * Constructor. Create an instance of the CFloat32ProjectionData2D class with initialization of the data.
+ *
+ * Creates an instance of the CFloat32ProjectionData2D class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified projection geometry object.
+ *
+ * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class.
+ * @param _fScalar scalar value to be put at each index.
+ */
+ CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32 _fScalar);
+
+ /**
+ * Copy constructor
+ */
+ CFloat32ProjectionData2D(const CFloat32ProjectionData2D& _other);
+
+ /**
+ * Assignment operator
+ */
+ CFloat32ProjectionData2D& operator=(const CFloat32ProjectionData2D& _other);
+
+ /**
+ * Destructor.
+ */
+ virtual ~CFloat32ProjectionData2D();
+
+ /** Initialization. Initializes an instance of the CFloat32ProjectionData2D class, without filling the data block.
+ *
+ * Initializes an instance of the CFloat32Data2D class. Memory is allocated for the
+ * data block. The allocated memory is not cleared and its contents after
+ * construction is undefined. Initialization may be followed by a call to
+ * copyData() to fill the memory block. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class.
+ * @return Initialization of the base class successfull.
+ */
+ bool initialize(CProjectionGeometry2D* _pGeometry);
+
+ /** Initialization. Initializes an instance of the CFloat32Data2D class with initialization of the data block.
+ *
+ * Initializes an instance of the CFloat32Data2D class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class.
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ bool initialize(CProjectionGeometry2D* _pGeometry, const float32* _pfData);
+
+ /** Initialization. Initializes an instance of the CFloat32Data2D class with initialization of the data block.
+ *
+ * Initializes an instance of the CFloat32Data2D class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class.
+ * @param _fScalar scalar value to be put at each index.
+ */
+ bool initialize(CProjectionGeometry2D* _pGeometry, float32 _fScalar);
+
+ /** Get the number of detectors.
+ *
+ * @return number of detectors
+ */
+ int getDetectorCount() const;
+
+ /** Get the number of projection angles.
+ *
+ * @return number of projection angles
+ */
+ int getAngleCount() const;
+
+ /** Get a pointer to the data of a single projection angle.
+ *
+ * The data memory is still "owned" by the
+ * CFloat32ProjectionData2D instance; this memory may NEVER be freed by the
+ * caller of this function. If changes are made to this data, the
+ * function updateStatistics() should be called after completion of
+ * all changes.
+ *
+ * @return pointer to the data
+ */
+ float32* getSingleProjectionData(int _iAngleIndex);
+
+ /** Get a const pointer to the data of a single projection angle.
+ *
+ * The data memory is still "owned" by the
+ * CFloat32ProjectionData2D instance; this memory may NEVER be freed by the
+ * caller of this function.
+ *
+ * @return pointer to the data
+ */
+ const float32* getSingleProjectionDataConst(int _iAngleIndex) const;
+
+ /** Which type is this class?
+ *
+ * @return DataType: PROJECTION
+ */
+ virtual EDataType getType() const;
+
+ /** Get the projection geometry.
+ *
+ * @return pointer to projection geometry.
+ */
+ virtual CProjectionGeometry2D* getGeometry() const;
+
+ /** Change the projection geometry.
+ * Note that this can't change the dimensions of the data.
+ */
+ virtual void changeGeometry(CProjectionGeometry2D* pGeometry);
+
+protected:
+
+ /** The projection geometry for this data.
+ */
+ CProjectionGeometry2D* m_pGeometry;
+
+};
+//----------------------------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------------------
+// Get the number of detectors.
+inline int CFloat32ProjectionData2D::getDetectorCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iWidth;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of projection angles.
+inline int CFloat32ProjectionData2D::getAngleCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iHeight;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the projection geometry.
+inline CProjectionGeometry2D* CFloat32ProjectionData2D::getGeometry() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_pGeometry;
+}
+
+//----------------------------------------------------------------------------------------
+// Get type.
+inline CFloat32Data2D::EDataType CFloat32ProjectionData2D::getType() const
+{
+ return PROJECTION;
+}
+//----------------------------------------------------------------------------------------
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32PROJECTIONDATA2D
diff --git a/include/astra/Float32ProjectionData3D.h b/include/astra/Float32ProjectionData3D.h
new file mode 100644
index 0000000..92122a7
--- /dev/null
+++ b/include/astra/Float32ProjectionData3D.h
@@ -0,0 +1,257 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32PROJECTIONDATA3D
+#define _INC_ASTRA_FLOAT32PROJECTIONDATA3D
+
+#include "Float32Data3D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+#include "ProjectionGeometry3D.h"
+
+namespace astra {
+
+/**
+ * This asbtract class represents three-dimensional Projection Data.
+ */
+class _AstraExport CFloat32ProjectionData3D : public virtual CFloat32Data3D
+{
+protected:
+ /** The projection geometry for this data.
+ */
+ CProjectionGeometry3D* m_pGeometry;
+
+public:
+
+ /** Default constructor.
+ */
+ CFloat32ProjectionData3D();
+
+ /** Destructor.
+ */
+ virtual ~CFloat32ProjectionData3D();
+
+ /** Get the number of detectors in one detector column.
+ *
+ * @return number of detectors
+ */
+ int getDetectorRowCount() const;
+
+ /** Get the number of detectors in one detector row.
+ *
+ * @return number of detectors
+ */
+ int getDetectorColCount() const;
+
+ /** Get the total number of detectors.
+ *
+ * @return number of detectors
+ */
+ int getDetectorTotCount() const;
+
+ /** Get the number of projection angles.
+ *
+ * @return number of projection angles
+ */
+ int getAngleCount() const;
+
+ /** Which type is this class?
+ *
+ * @return DataType: ASTRA_DATATYPE_FLOAT32_PROJECTION
+ */
+ virtual CFloat32Data3D::EDataType getType() const;
+
+ /** Fetch a COPY of a projection of the data. Note that if you update the 2D data slice, the data in the
+ * 3d data object will remain unaltered. To copy the data back in the 3D-volume you must return the data by calling 'returnProjection'.
+ *
+ * @param _iProjectionNr projection number
+ * @return Volume data object
+ */
+ virtual CFloat32VolumeData2D* fetchProjection(int _iProjectionNr) const = 0;
+
+ /** Return a projection slice to the 3d data. The data will be deleted. If the slice was fetched with
+ * 'fetchProjection', the data will be stored first.
+ *
+ * @param _iProjectionNr projection number
+ * @param _pProjection 2D Projection Data
+ */
+ virtual void returnProjection(int _iProjectionNr, CFloat32VolumeData2D* _pProjection) = 0;
+
+ /** Fetch a COPY of a sinogram slice of the data. Note that if you update the 2D data slice, the data in the
+ * 3d data object will remain unaltered. To copy the data back in the 3D-volume you must return the data by calling 'returnSlice'.
+ *
+ * @param _iSliceNr slice number
+ * @return Sinogram data object
+ */
+ virtual CFloat32ProjectionData2D* fetchSinogram(int _iSliceNr) const = 0;
+
+ /** Return a sinogram slice to the 3d data. The data will be stored in the 3D Data object.
+ *
+ * @param _iSliceNr slice number
+ * @param _pSinogram2D 2D Sinogram Object.
+ */
+ virtual void returnSinogram(int _iSliceNr, CFloat32ProjectionData2D* _pSinogram2D) = 0;
+
+ /** This SLOW function returns a detector value stored a specific index in the array.
+ * Reading values in this way might cause a lot of unnecessar__y memory operations, don't
+ * use it in time-critical code.
+ *
+ * @param _iIndex Index in the array if the data were stored completely in main memory
+ * @return The value the location specified by _iIndex
+ */
+ virtual float32 getDetectorValue(int _iIndex) = 0;
+
+ /** This SLOW function stores a detector value at a specific index in the array.
+ * Writing values in this way might cause a lot of unnecessary memory operations, don't
+ * use it in time-critical code.
+ *
+ * @param _iIndex Index in the array if the data were stored completely in main memory
+ * @param _fValue The value to be stored at the location specified by _iIndex
+ */
+ virtual void setDetectorValue(int _iIndex, float32 _fValue) = 0;
+
+ /**
+ * Overloaded Operator: data += data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32ProjectionData3D& operator+=(const CFloat32ProjectionData3D& _data);
+
+ /**
+ * Overloaded Operator: data -= data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32ProjectionData3D& operator-=(const CFloat32ProjectionData3D& _data);
+
+ /**
+ * Overloaded Operator: data *= data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32ProjectionData3D& operator*=(const CFloat32ProjectionData3D& _data);
+
+ /**
+ * Overloaded Operator: data *= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32ProjectionData3D& operator*=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data /= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32ProjectionData3D& operator/=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data += scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32ProjectionData3D& operator+=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data -= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32ProjectionData3D& operator-=(const float32& _fScalar);
+
+ /** Get the projection geometry.
+ *
+ * @return pointer to projection geometry.
+ */
+ virtual CProjectionGeometry3D* getGeometry() const;
+};
+
+
+//----------------------------------------------------------------------------------------
+// Inline member functions
+//----------------------------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------------------
+// Get the number of detectors.
+inline int CFloat32ProjectionData3D::getDetectorColCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iWidth;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of detectors.
+inline int CFloat32ProjectionData3D::getDetectorRowCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iDepth;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of detectors.
+inline int CFloat32ProjectionData3D::getDetectorTotCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iWidth * m_iDepth;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of projection angles.
+inline int CFloat32ProjectionData3D::getAngleCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iHeight;
+}
+
+//----------------------------------------------------------------------------------------
+// Get type
+inline CFloat32Data3D::EDataType CFloat32ProjectionData3D::getType() const
+{
+ return PROJECTION;
+}
+//----------------------------------------------------------------------------------------
+// Get the projection geometry.
+inline CProjectionGeometry3D* CFloat32ProjectionData3D::getGeometry() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_pGeometry;
+}
+//----------------------------------------------------------------------------------------
+
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32PROJECTIONDATA3D
diff --git a/include/astra/Float32ProjectionData3DMemory.h b/include/astra/Float32ProjectionData3DMemory.h
new file mode 100644
index 0000000..8b61d45
--- /dev/null
+++ b/include/astra/Float32ProjectionData3DMemory.h
@@ -0,0 +1,218 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32PROJECTIONDATA3DMEMORY
+#define _INC_ASTRA_FLOAT32PROJECTIONDATA3DMEMORY
+
+#include "Float32Data3DMemory.h"
+#include "Float32ProjectionData3D.h"
+#include "ParallelProjectionGeometry2D.h" // TEMP
+
+namespace astra {
+
+/**
+ * This class represents three-dimensional Projection Data.
+ *
+ * It contains member functions for accessing this data and for performing
+ * elementary computations on the data.
+ * The data block is "owned" by the class, meaning that the class is
+ * responsible for deallocation of the memory involved.
+ *
+ * The projection data is stored as a series of consecutive rows, where
+ * each row contains the data for a single projection.
+ */
+class _AstraExport CFloat32ProjectionData3DMemory : public CFloat32Data3DMemory, public CFloat32ProjectionData3D {
+
+public:
+
+ /**
+ * Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ *
+ */
+ CFloat32ProjectionData3DMemory();
+
+ /**
+ * Constructor. Create an instance of the CFloat32ProjectionData3DMemory class without initializing the data.
+ *
+ * Memory is allocated for the data block. The allocated memory is not cleared and
+ * its contents after construction is undefined. Construction may be followed by a
+ * call to copyData() to fill the memory block.
+ * The size of the data is determined by the specified projection geometry object.
+ *
+ * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class.
+ */
+ CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry);
+
+ /**
+ * Constructor. Create an instance of the CFloat32ProjectionData3DMemory class with initialization of the data.
+ *
+ * Creates an instance of the CFloat32ProjectionData3DMemory class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified projection geometry object.
+ *
+ * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class.
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32* _pfData);
+
+ /**
+ * Constructor. Create an instance of the CFloat32ProjectionData3DMemory class filled with scalar data.
+ *
+ * Creates an instance of the CFloat32ProjectionData3DMemory class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified projection geometry object.
+ *
+ * @param _pGeometry Projection Geometry object. This object will be HARDCOPIED into this class.
+ * @param _fScalar scalar data
+ */
+ CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32 _fScalar);
+
+ /**
+ * Destructor.
+ */
+ virtual ~CFloat32ProjectionData3DMemory();
+
+ /** Initialization. Initializes an instance of the CFloat32ProjectionData3DMemory class, without filling the data block.
+ *
+ * Initializes an instance of the CFloat32ProjectionData3DMemory class. Memory is allocated for the
+ * data block. The allocated memory is not cleared and its contents after
+ * construction is undefined. Initialization may be followed by a call to
+ * copyData() to fill the memory block. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class.
+ * @return Initialization of the base class successfull.
+ */
+ bool initialize(CProjectionGeometry3D* _pGeometry);
+
+ /** Initialization. Initializes an instance of the CFloat32ProjectionData3DMemory class with scalar initialization.
+ *
+ * Initializes an instance of the CFloat32ProjectionData3DMemory class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class.
+ * @param _fScalar scalar value
+ */
+ bool initialize(CProjectionGeometry3D* _pGeometry, float32 _fScalar);
+
+ /** Initialization. Initializes an instance of the CFloat32ProjectionData3DMemory class with initialization of the data block.
+ *
+ * Initializes an instance of the CFloat32ProjectionData3DMemory class. Memory
+ * is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory. If the object has been initialized before, the
+ * object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _pGeometry Projection Geometry of the data. This object will be HARDCOPIED into this class.
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ bool initialize(CProjectionGeometry3D* _pGeometry, const float32* _pfData);
+
+ /** Fetch a COPY of a projection of the data. Note that if you update the 2D data slice, the data in the
+ * 3D data object will remain unaltered. To copy the data back in the 3D-volume you must return the data by calling 'returnProjection'.
+ *
+ * @param _iProjectionNr projection number
+ * @return Volume data object
+ */
+ virtual CFloat32VolumeData2D* fetchProjection(int _iProjectionNr) const;
+
+ /** Return a projection slice to the 3D data. The data will be deleted. If the slice was fetched with
+ * 'fetchProjection', the data will be stored first.
+ *
+ * @param _iProjectionNr projection number
+ * @param _pProjection 2D Projection image
+ */
+ virtual void returnProjection(int _iProjectionNr, CFloat32VolumeData2D* _pProjection);
+
+ /** Fetch a COPY of a sinogram slice of the data. Note that if you update the 2D data slice, the data in the
+ * 3D data object will remain unaltered. To copy the data back in the 3D-volume you must return the data by calling 'returnSlice'.
+ *
+ * @param _iSliceNr slice number
+ * @return Sinogram data object
+ */
+ virtual CFloat32ProjectionData2D* fetchSinogram(int _iSliceNr) const;
+
+ /** This SLOW function returns a detector value stored a specific index in the array.
+ * Reading values in this way might cause a lot of unnecessary memory operations, don't
+ * use it in time-critical code.
+ *
+ * @param _iIndex Index in the array if the data were stored completely in main memory
+ * @return The value the location specified by _iIndex
+ */
+ virtual float32 getDetectorValue(int _iIndex);
+
+ /** This SLOW function stores a detector value at a specific index in the array.
+ * Writing values in this way might cause a lot of unnecessary memory operations, don't
+ * use it in time-critical code.
+ *
+ * @param _iIndex Index in the array if the data were stored completely in main memory
+ * @param _fValue The value to be stored at the location specified by _iIndex
+ */
+ virtual void setDetectorValue(int _iIndex, float32 _fValue);
+
+ /** Return a sinogram slice to the 3d data. The data will be stored in the 3D Data object.
+ *
+ * @param _iSliceNr slice number
+ * @param _pSinogram2D 2D Sinogram Object.
+ */
+ virtual void returnSinogram(int _iSliceNr, CFloat32ProjectionData2D* _pSinogram2D);
+
+ /** Which type is this class?
+ *
+ * @return DataType: PROJECTION
+ */
+ virtual EDataType getType() const;
+
+ /**
+ * Overloaded Operator: data = data (pointwise)
+ *
+ * @param _dataIn r-value
+ * @return l-value
+ */
+ CFloat32ProjectionData3DMemory& operator=(const CFloat32ProjectionData3DMemory& _dataIn);
+};
+//----------------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------------
+// Get type.
+inline CFloat32Data3D::EDataType CFloat32ProjectionData3DMemory::getType() const
+{
+ return PROJECTION;
+}
+//----------------------------------------------------------------------------------------
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32PROJECTIONDATA3DMEMORY
diff --git a/include/astra/Float32VolumeData2D.h b/include/astra/Float32VolumeData2D.h
new file mode 100644
index 0000000..d7bf2f6
--- /dev/null
+++ b/include/astra/Float32VolumeData2D.h
@@ -0,0 +1,183 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32VOLUMEDATA2D
+#define _INC_ASTRA_FLOAT32VOLUMEDATA2D
+
+#include "Float32Data2D.h"
+#include "VolumeGeometry2D.h"
+
+namespace astra {
+
+/**
+ * This class represents two-dimensional Volume Data.
+ *
+ * It contains member functions for accessing this data and for performing
+ * elementary computations on the data.
+ * The data block is "owned" by the class, meaning that the class is
+ * responsible for deallocation of the memory involved.
+ */
+class _AstraExport CFloat32VolumeData2D : public CFloat32Data2D {
+
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ *
+ */
+ CFloat32VolumeData2D();
+
+ /** Constructor. Create an instance of the CFloat32VolumeData2D class without initializing the data.
+ *
+ * Memory is allocated for the data block. The allocated memory is not cleared and
+ * its contents after construction is undefined. Construction may be followed by a
+ * call to copyData() to fill the memory block.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class.
+ */
+ CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry);
+
+ /** Constructor. Create an instance of the CFloat32VolumeData2D class with initialization of the data.
+ *
+ * Memory is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class.
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32* _pfData);
+
+ /** Constructor. Create an instance of the CFloat32VolumeData2D class with a scalar initialization of the data.
+ *
+ * Memory is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class.
+ * @param _fScalar scalar value to be put at each index.
+ */
+ CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32 _fScalar);
+
+ /**
+ * Copy constructor
+ */
+ CFloat32VolumeData2D(const CFloat32VolumeData2D& _other);
+
+ /**
+ * Assignment operator
+ */
+ CFloat32VolumeData2D& operator=(const CFloat32VolumeData2D& _other);
+
+ /** Initialization. Initializes of the CFloat32VolumeData2D class without initializing the data.
+ *
+ * Memory is allocated for the data block. The allocated memory is not cleared and
+ * its contents after construction is undefined. Construction may be followed by a
+ * call to copyData() to fill the memory block.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class.
+ * @return Initialization of the base class successfull.
+ */
+ bool initialize(CVolumeGeometry2D* _pGeometry);
+
+ /** Initialization. Initializes an instance of the CFloat32VolumeData2D class with initialization of the data.
+ *
+ * Memory is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class.
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ bool initialize(CVolumeGeometry2D* _pGeometry, const float32* _pfData);
+
+
+ /** Initialization. Initializes an instance of the CFloat32VolumeData2D class with scalar initialization of the data.
+ *
+ * Memory is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class.
+ * @param _fScalar scalar value to be put at each index.
+ */
+ bool initialize(CVolumeGeometry2D* _pGeometry, float32 _fScalar);
+
+ /** Destructor.
+ */
+ virtual ~CFloat32VolumeData2D();
+
+ /** Which type is this class?
+ *
+ * @return DataType: VOLUME
+ */
+ virtual EDataType getType() const;
+
+ /** Get the volume geometry.
+ *
+ * @return pointer to volume geometry.
+ */
+ virtual CVolumeGeometry2D* getGeometry() const;
+
+ /** Change the projection geometry.
+ * Note that this can't change the dimensions of the data.
+ */
+ virtual void changeGeometry(CVolumeGeometry2D* pGeometry);
+
+protected:
+
+ /** The projection geometry for this data.
+ */
+ CVolumeGeometry2D* m_pGeometry;
+
+};
+
+//----------------------------------------------------------------------------------------
+// Get the projection geometry.
+inline CVolumeGeometry2D* CFloat32VolumeData2D::getGeometry() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_pGeometry;
+}
+
+//----------------------------------------------------------------------------------------
+// Get type
+inline CFloat32Data2D::EDataType CFloat32VolumeData2D::getType() const
+{
+ return VOLUME;
+}
+
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32VOLUMEDATA2D
diff --git a/include/astra/Float32VolumeData3D.h b/include/astra/Float32VolumeData3D.h
new file mode 100644
index 0000000..0b1bd96
--- /dev/null
+++ b/include/astra/Float32VolumeData3D.h
@@ -0,0 +1,265 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32VOLUMEDATA3D
+#define _INC_ASTRA_FLOAT32VOLUMEDATA3D
+
+#include "Float32Data3D.h"
+#include "Float32VolumeData2D.h"
+#include "VolumeGeometry3D.h"
+
+namespace astra {
+
+/**
+ * This asbtract class represents three-dimensional Volume Data.
+ */
+class _AstraExport CFloat32VolumeData3D : public virtual CFloat32Data3D
+{
+protected:
+ CVolumeGeometry3D * m_pGeometry;
+
+public:
+ /** Default constructor.
+ */
+ CFloat32VolumeData3D();
+
+ /** Destructor.
+ */
+ virtual ~CFloat32VolumeData3D();
+
+ /**
+ * Returns number of rows
+ *
+ * @return number of rows
+ */
+ int getRowCount() const;
+
+ /**
+ * Returns number of columns
+ *
+ * @return number of columns
+ */
+ int getColCount() const;
+
+ /**
+ * Returns number of slices
+ *
+ * @return number of slices
+ */
+ int getSliceCount() const;
+
+ /**
+ * Returns total number of volumes
+ *
+ * @return total number of volumes
+ */
+ int getVoxelTotCount() const;
+
+ /** Which type is this class?
+ *
+ * @return DataType: VOLUME
+ */
+ virtual CFloat32Data3D::EDataType getType() const;
+
+ /** Fetch a slice from the data in the x direction. Note that if you update the 2D data slice, the data in the
+ * 3d data object will remain unaltered. To copy the data you must return the data by calling 'returnSliceX'.
+ * You should not delete data fetched with this function yourself, instead call the 'returnSliceX' function.
+ *
+ * @param _iColumnIndex slice number
+ * @return Volume data object
+ */
+ virtual CFloat32VolumeData2D* fetchSliceX(int _iColumnIndex) const = 0;
+
+ /** Fetch a slice from the data in the y direction. Note that if you update the 2D data slice, the data in the
+ * 3d data object will remain unaltered. To copy the data you must return the data by calling 'returnSliceY'.
+ * You should not delete data fetched with this function yourself, instead call the 'returnSliceY' function.
+ *
+ * @param _iRowIndex slice number
+ * @return Volume data object
+ */
+ virtual CFloat32VolumeData2D* fetchSliceY(int _iRowIndex) const = 0;
+
+ /** Fetch a slice from the data in the z direction. Note that if you update the 2D data slice, the data in the
+ * 3d data object will remain unaltered. To copy the data you must return the data by calling 'returnSliceZ'.
+ * You should not delete data fetched with this function yourself, instead call the 'returnSliceZ' function.
+ *
+ * @param _iSliceIndex slice number
+ * @return Volume data object
+ */
+ virtual CFloat32VolumeData2D* fetchSliceZ(int _iSliceIndex) const = 0;
+
+ /** Return a slice from the data in the x direction to the 3d data. The data will be deleted. If the slice was
+ * fetched with 'fetchSliceX', the data will be stored first.
+ *
+ * @param _iColumnIndex slice number
+ */
+ virtual void returnSliceX(int _iColumnIndex, CFloat32VolumeData2D * _pSlice) = 0;
+
+ /** Return a slice from the data in the y direction to the 3d data. The data will be deleted. If the slice was
+ * fetched with 'fetchSliceY', the data will be stored first.
+ *
+ * @param _iRowIndex slice number
+ */
+ virtual void returnSliceY(int _iRowIndex, CFloat32VolumeData2D * _pSlice) = 0;
+
+ /** Return a slice from the data in the z direction to the 3d data. The data will be deleted. If the slice was
+ * fetched with 'fetchSliceZ', the data will be stored first.
+ *
+ * @param _iSliceIndex slice number
+ */
+ virtual void returnSliceZ(int _iSliceIndex, CFloat32VolumeData2D * _pSlice) = 0;
+
+ /** This SLOW function returns a voxel value stored at a specific index in the array.
+ * Reading values in this way might cause a lot of unnecessary memory operations, don't
+ * use it in time-critical code.
+ *
+ * @param _iIndex Index in the array if the data were stored completely in main memory
+ * @return The value stored at the location specified by _iIndex
+ */
+ virtual float32 getVoxelValue(int _iIndex) = 0;
+
+ /** This SLOW function stores a voxel value at a specific index in the array.
+ * Writing values in this way might cause a lot of unnecessary memory operations, don't
+ * use it in time-critical code.
+ *
+ * @param _iIndex Index in the array if the data were stored completely in main memory
+ * @param _fValue The value to be stored at the location specified by _iIndex
+ */
+ virtual void setVoxelValue(int _iIndex, float32 _fValue) = 0;
+
+ /**
+ * Overloaded Operator: data += data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32VolumeData3D& operator+=(const CFloat32VolumeData3D& _data);
+
+ /**
+ * Overloaded Operator: data -= data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32VolumeData3D& operator-=(const CFloat32VolumeData3D& _data);
+
+ /**
+ * Overloaded Operator: data *= data (pointwise)
+ *
+ * @param _data r-value
+ * @return l-value
+ */
+ CFloat32VolumeData3D& operator*=(const CFloat32VolumeData3D& _data);
+
+ /**
+ * Overloaded Operator: data *= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32VolumeData3D& operator*=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data /= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32VolumeData3D& operator/=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data += scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32VolumeData3D& operator+=(const float32& _fScalar);
+
+ /**
+ * Overloaded Operator: data -= scalar (pointwise)
+ *
+ * @param _fScalar r-value
+ * @return l-value
+ */
+ CFloat32VolumeData3D& operator-=(const float32& _fScalar);
+
+ /**
+ * Gives access to the geometry stored in this class
+ *
+ * @return The geometry describing the data stored in this volume
+ */
+ virtual CVolumeGeometry3D* getGeometry() const;
+};
+
+//----------------------------------------------------------------------------------------
+// get row count
+inline int CFloat32VolumeData3D::getRowCount() const
+{
+ return m_iHeight;
+}
+
+//----------------------------------------------------------------------------------------
+// get column count
+inline int CFloat32VolumeData3D::getColCount() const
+{
+ return m_iWidth;
+}
+
+//----------------------------------------------------------------------------------------
+// get slice count
+inline int CFloat32VolumeData3D::getSliceCount() const
+{
+ return m_iDepth;
+}
+
+//----------------------------------------------------------------------------------------
+// get total voxel count
+inline int CFloat32VolumeData3D::getVoxelTotCount() const
+{
+ return m_iHeight * m_iWidth * m_iDepth;
+}
+
+//----------------------------------------------------------------------------------------
+// get type
+inline CFloat32Data3D::EDataType CFloat32VolumeData3D::getType() const
+{
+ return CFloat32Data3D::VOLUME;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the volume geometry.
+inline CVolumeGeometry3D* CFloat32VolumeData3D::getGeometry() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_pGeometry;
+}
+//----------------------------------------------------------------------------------------
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32VOLUMEDATA2D
diff --git a/include/astra/Float32VolumeData3DMemory.h b/include/astra/Float32VolumeData3DMemory.h
new file mode 100644
index 0000000..51df93e
--- /dev/null
+++ b/include/astra/Float32VolumeData3DMemory.h
@@ -0,0 +1,213 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FLOAT32VOLUMEDATA3DMEMORY
+#define _INC_ASTRA_FLOAT32VOLUMEDATA3DMEMORY
+
+#include "Float32Data3DMemory.h"
+#include "VolumeGeometry3D.h"
+#include "Float32VolumeData3D.h"
+
+namespace astra {
+
+/**
+ * This class represents three-dimensional Volume Data where the entire data block is stored in memory.
+ */
+class _AstraExport CFloat32VolumeData3DMemory : public CFloat32Data3DMemory, public CFloat32VolumeData3D
+{
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ *
+ */
+ CFloat32VolumeData3DMemory();
+
+ /** Constructor. Create an instance of the CFloat32VolumeData3DMemory class without initializing the data.
+ *
+ * Memory is allocated for the data block. The allocated memory is not cleared and
+ * its contents after construction is undefined. Construction may be followed by a
+ * call to copyData() to fill the memory block.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class.
+ */
+ CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry);
+
+ /** Constructor. Create an instance of the CFloat32VolumeData3DMemory class with initialization of the data.
+ *
+ * Memory is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class.
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, const float32* _pfData);
+
+ /** Constructor. Create an instance of the CFloat32VolumeData3DMemory class with scalar initialization of the data.
+ *
+ * Memory is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry object. This object will be HARDCOPIED into this class.
+ * @param _fScalar scalar value
+ */
+ CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, float32 _fScalar);
+
+ /** Destructor.
+ */
+ virtual ~CFloat32VolumeData3DMemory();
+
+ /** Initialization. Initializes of the CFloat32VolumeData3DMemory class without initializing the data.
+ *
+ * Memory is allocated for the data block. The allocated memory is not cleared and
+ * its contents after construction is undefined. Construction may be followed by a
+ * call to copyData() to fill the memory block.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class.
+ * @return Initialization of the base class successful.
+ */
+ bool initialize(CVolumeGeometry3D* _pGeometry);
+
+ /** Initialization. Initializes an instance of the CFloat32VolumeData3DMemory class with initialization of the data.
+ *
+ * Memory is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class.
+ * @param _pfData pointer to a one-dimensional float32 data block
+ */
+ bool initialize(CVolumeGeometry3D* _pGeometry, const float32* _pfData);
+
+ /** Initialization. Initializes an instance of the CFloat32VolumeData3DMemory class with scalar initialization of the data.
+ *
+ * Memory is allocated for the data block and the contents of the memory pointed to by
+ * _pfData is copied into the allocated memory.
+ * The size of the data is determined by the specified volume geometry object.
+ *
+ * @param _pGeometry Volume Geometry of the data. This object will be HARDCOPIED into this class.
+ * @param _fScalar scalar value
+ */
+ bool initialize(CVolumeGeometry3D* _pGeometry, float32 _fScalar);
+
+ /** Which type is this class?
+ *
+ * @return DataType: VOLUME
+ */
+ virtual CFloat32Data3D::EDataType getType() const;
+
+ /** Get the volume geometry.
+ *
+ * @return pointer to volume geometry.
+ */
+ CVolumeGeometry3D* getGeometry();
+
+ /**
+ * Gets a slice, containing all voxels with a given x (= column) index.
+ */
+ CFloat32VolumeData2D * fetchSliceX(int _iColumnIndex) const;
+
+ /**
+ * Gets a slice, containing all voxels with a given y (= row) index.
+ */
+ CFloat32VolumeData2D * fetchSliceY(int _iRowIndex) const;
+
+ /**
+ * Gets a slice, containing all voxels with a given z (= slice) index.
+ */
+ CFloat32VolumeData2D * fetchSliceZ(int _iSliceIndex) const;
+
+ /**
+ * Gets a slice, containing all voxels with a given x (= column) index.
+ */
+ void returnSliceX(int _iColumnIndex, CFloat32VolumeData2D * _pSliceData);
+
+ /**
+ * Gets a slice, containing all voxels with a given y (= row) index.
+ */
+ void returnSliceY(int _iRowIndex, CFloat32VolumeData2D * _pSliceData);
+
+ /**
+ * Copies data from a 2D slice containing all voxels with a given z (= slice) index to the
+ * 3D memory stored in this class.
+ */
+ void returnSliceZ(int _iSliceIndex, CFloat32VolumeData2D * _pSliceData);
+
+ /** This SLOW function returns a volume value stored a specific index in the array.
+ * Reading values in this way might cause a lot of unnecessary memory operations, don't
+ * use it in time-critical code.
+ *
+ * @param _iIndex Index in the array if the data were stored completely in main memory
+ * @return The value the location specified by _iIndex
+ */
+ virtual float32 getVoxelValue(int _iIndex);
+
+ /** This SLOW function stores a voxel value at a specific index in the array.
+ * Writing values in this way might cause a lot of unnecessary memory operations, don't
+ * use it in time-critical code.
+ *
+ * @param _iIndex Index in the array if the data were stored completely in main memory
+ * @param _fValue The value to be stored at the location specified by _iIndex
+ */
+ virtual void setVoxelValue(int _iIndex, float32 _fValue);
+
+ /**
+ * Overloaded Operator: data = data (pointwise)
+ *
+ * @param _dataIn r-value
+ * @return l-value
+ */
+ CFloat32VolumeData3DMemory& operator=(const CFloat32VolumeData3DMemory& _dataIn);
+};
+
+//----------------------------------------------------------------------------------------
+// Get the projection geometry.
+inline CVolumeGeometry3D* CFloat32VolumeData3DMemory::getGeometry()
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_pGeometry;
+}
+
+//----------------------------------------------------------------------------------------
+// Get type
+inline CFloat32Data3D::EDataType CFloat32VolumeData3DMemory::getType() const
+{
+ return VOLUME;
+}
+
+
+} // end namespace astra
+
+#endif // _INC_ASTRA_FLOAT32VOLUMEDATA3DMEMORY
diff --git a/include/astra/ForwardProjectionAlgorithm.h b/include/astra/ForwardProjectionAlgorithm.h
new file mode 100644
index 0000000..147002b
--- /dev/null
+++ b/include/astra/ForwardProjectionAlgorithm.h
@@ -0,0 +1,225 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FORWARDPROJECTIONALGORITHM
+#define _INC_ASTRA_FORWARDPROJECTIONALGORITHM
+
+#include "Algorithm.h"
+
+#include "Globals.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+#include "DataProjector.h"
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains the implementation of an algorithm that creates a forward projection
+ * of a volume object and stores it into a sinogram.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{VolumeDataId, integer, Identifier of the volume data object as it is stored in the DataManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of the resulting projection data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{VolumeMaskId, integer, not used, Identifier of a volume data object that acts as a volume mask. 0 = don't use this pixel. 1 = use this pixel. }
+ * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 0 = don't use this ray. 1 = use this ray.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('FP');\n
+ * cfg.ProjectorId = proj_id;\n
+ * cfg.VolumeDataId = vol_id;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('run'\, alg_id);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ */
+class _AstraExport CForwardProjectionAlgorithm : public CAlgorithm {
+
+protected:
+
+ /** Init stuff
+ */
+ virtual void _init();
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - valid projector
+ * - valid data objects
+ */
+ virtual bool _check();
+
+ //< Projector object.
+ CProjector2D* m_pProjector;
+ //< ProjectionData2D object containing the sinogram.
+ CFloat32ProjectionData2D* m_pSinogram;
+ //< VolumeData2D object containing the phantom.
+ CFloat32VolumeData2D* m_pVolume;
+
+ // data projector
+ astra::CDataProjectorInterface* m_pForwardProjector;
+
+ // ray or voxel-driven projector code?
+ bool m_bUseVoxelProjector;
+
+ //< Dataobject containing fixed volume mask (0 = don't project)
+ CFloat32VolumeData2D* m_pVolumeMask;
+ //< Use the fixed reconstruction mask?
+ bool m_bUseVolumeMask;
+
+ //< Dataobject containing fixed reconstruction mask (0 = don't project)
+ CFloat32ProjectionData2D* m_pSinogramMask;
+ //< Use the fixed reconstruction mask?
+ bool m_bUseSinogramMask;
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CForwardProjectionAlgorithm();
+
+ /** Initializing constructor.
+ *
+ * @param _pProjector Projector to use.
+ * @param _pVolume VolumeData2D object containing the phantom to compute sinogram from
+ * @param _pSinogram ProjectionData2D object to store sinogram data in.
+ */
+ CForwardProjectionAlgorithm(CProjector2D* _pProjector,
+ CFloat32VolumeData2D* _pVolume,
+ CFloat32ProjectionData2D* _pSinogram);
+
+ /** Destructor.
+ */
+ virtual ~CForwardProjectionAlgorithm();
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector to use.
+ * @param _pVolume VolumeData2D object containing the phantom to compute sinogram from
+ * @param _pSinogram ProjectionData2D object to store sinogram data in.
+ * @return success
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32VolumeData2D* _pVolume,
+ CFloat32ProjectionData2D* _pSinogram);
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Set a fixed reconstruction mask. A pixel will only be used in the reconstruction if the
+ * corresponding value in the mask is 1.
+ *
+ * @param _pMask Volume Data object containing fixed reconstruction mask
+ * @param _bEnable enable the use of this mask
+ */
+ void setVolumeMask(CFloat32VolumeData2D* _pMask, bool _bEnable = true);
+
+ /** Set a fixed sinogram mask. A detector value will only be used in the reconstruction if the
+ * corresponding value in the mask is 1.
+ *
+ * @param _pMask Projection Data object containing fixed sinogram mask
+ * @param _bEnable enable the use of this mask
+ */
+ void setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable = true);
+
+ /** Get projector object
+ *
+ * @return projector
+ */
+ CProjector2D* getProjector() const;
+
+ /** Get sinogram data object
+ *
+ * @return sinogram data object
+ */
+ CFloat32ProjectionData2D* getSinogram() const;
+
+ /** Get volume data object
+ *
+ * @return volume data object
+ */
+ CFloat32VolumeData2D* getVolume() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+
+};
+
+// inline functions
+inline std::string CForwardProjectionAlgorithm::description() const { return CForwardProjectionAlgorithm::type; };
+inline CProjector2D* CForwardProjectionAlgorithm::getProjector() const { return m_pProjector; }
+inline CFloat32ProjectionData2D* CForwardProjectionAlgorithm::getSinogram() const { return m_pSinogram; }
+inline CFloat32VolumeData2D* CForwardProjectionAlgorithm::getVolume() const { return m_pVolume; }
+
+} // end namespace
+
+#endif
diff --git a/include/astra/Fourier.h b/include/astra/Fourier.h
new file mode 100644
index 0000000..290c094
--- /dev/null
+++ b/include/astra/Fourier.h
@@ -0,0 +1,127 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_FOURIER
+#define _INC_ASTRA_FOURIER
+
+#include "Globals.h"
+
+namespace astra {
+
+
+/**
+ * Perform a 1D DFT or inverse DFT.
+ *
+ * @param iLength number of elements
+ * @param pfRealIn real part of input
+ * @param pfImaginaryIn imaginary part of input
+ * @param pfRealOut real part of output
+ * @param pfImaginaryOut imaginary part of output
+ * @param iStrideIn distance between elements in pf*In
+ * @param iStrideOut distance between elements in pf*Out
+ * @param bInverse if true, perform an inverse DFT
+ */
+
+void _AstraExport discreteFourierTransform1D(unsigned int iLength,
+ const float32* pfRealIn,
+ const float32* pfImaginaryIn,
+ float32* pfRealOut,
+ float32* pfImaginaryOut,
+ unsigned int iStrideIn,
+ unsigned int iStrideOut,
+ bool bInverse);
+
+/**
+ * Perform a 2D DFT or inverse DFT.
+ *
+ * @param iHeight number of rows
+ * @param iWidth number of columns
+ * @param pfRealIn real part of input
+ * @param pfImaginaryIn imaginary part of input
+ * @param pfRealOut real part of output
+ * @param pfImaginaryOut imaginary part of output
+ * @param bInverse if true, perform an inverse DFT
+ */
+
+void _AstraExport discreteFourierTransform2D(unsigned int iHeight, unsigned int iWidth,
+ const float32* pfRealIn,
+ const float32* pfImaginaryIn,
+ float32* pfRealOut,
+ float32* pfImaginaryOut,
+ bool bInverse);
+
+/**
+ * Perform a 1D FFT or inverse FFT. The size must be a power of two.
+ * This transform can be done in-place, so the input and output pointers
+ * may point to the same data.
+ *
+ * @param iLength number of elements, must be a power of two
+ * @param pfRealIn real part of input
+ * @param pfImaginaryIn imaginary part of input
+ * @param pfRealOut real part of output
+ * @param pfImaginaryOut imaginary part of output
+ * @param iStrideIn distance between elements in pf*In
+ * @param iStrideOut distance between elements in pf*Out
+ * @param bInverse if true, perform an inverse DFT
+ */
+
+void _AstraExport fastTwoPowerFourierTransform1D(unsigned int iLength,
+ const float32* pfRealIn,
+ const float32* pfImaginaryIn,
+ float32* pfRealOut,
+ float32* pfImaginaryOut,
+ unsigned int iStrideIn,
+ unsigned int iStrideOut,
+ bool bInverse);
+
+/**
+ * Perform a 2D FFT or inverse FFT. The size must be a power of two.
+ * This transform can be done in-place, so the input and output pointers
+ * may point to the same data.
+ *
+ * @param iHeight number of rows, must be a power of two
+ * @param iWidth number of columns, must be a power of two
+ * @param pfRealIn real part of input
+ * @param pfImaginaryIn imaginary part of input
+ * @param pfRealOut real part of output
+ * @param pfImaginaryOut imaginary part of output
+ * @param bInverse if true, perform an inverse DFT
+ */
+
+void _AstraExport fastTwoPowerFourierTransform2D(unsigned int iHeight,
+ unsigned int iWidth,
+ const float32* pfRealIn,
+ const float32* pfImaginaryIn,
+ float32* pfRealOut,
+ float32* pfImaginaryOut,
+ bool bInverse);
+
+
+}
+
+#endif
diff --git a/include/astra/Globals.h b/include/astra/Globals.h
new file mode 100644
index 0000000..9407ef9
--- /dev/null
+++ b/include/astra/Globals.h
@@ -0,0 +1,309 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_GLOBALS
+#define _INC_ASTRA_GLOBALS
+
+/*! \mainpage The ASTRA-toolbox
+ *
+ * <img src="../images/logo_big.png"/>
+ */
+
+
+//----------------------------------------------------------------------------------------
+
+#ifdef _MSC_VER
+
+// disable warning: 'fopen' was declared deprecated
+#pragma warning (disable : 4996)
+// disable warning: C++ exception handler used, but unwind semantics are not enables
+#pragma warning (disable : 4530)
+// disable warning: no suitable definition provided for explicit template instantiation request
+#pragma warning (disable : 4661)
+
+#endif
+
+//----------------------------------------------------------------------------------------
+// standard includes
+#include <cassert>
+#include <iostream>
+#include <fstream>
+#include <math.h>
+#include <boost/static_assert.hpp>
+#include <boost/throw_exception.hpp>
+
+//----------------------------------------------------------------------------------------
+// macro's
+
+#define ASTRA_TOOLBOXVERSION_MAJOR 1
+#define ASTRA_TOOLBOXVERSION_MINOR 1
+#define ASTRA_TOOLBOXVERSION ((ASTRA_TOOLBOXVERSION_MAJOR)*100 + (ASTRA_TOOLBOXVERSION_MINOR))
+#define ASTRA_TOOLBOXVERSION_STRING "1.1"
+
+
+#define ASTRA_ASSERT(a) assert(a)
+
+#define ASTRA_CONFIG_CHECK(value, type, msg) if (!(value)) { cout << "Configuration Error in " << type << ": " << msg << endl; return false; }
+
+#define ASTRA_CONFIG_WARNING(type, msg) { cout << "Warning in " << type << ": " << msg << endl; }
+
+
+#define ASTRA_DELETE(a) if (a) { delete a; a = NULL; }
+#define ASTRA_DELETE_ARRAY(a) if (a) { delete[] a; a = NULL; }
+
+#ifdef _MSC_VER
+
+#ifdef DLL_EXPORTS
+#define _AstraExport __declspec(dllexport)
+#define EXPIMP_TEMPLATE
+#else
+#define _AstraExport __declspec(dllimport)
+#define EXPIMP_TEMPLATE extern
+#endif
+
+#else
+
+#define _AstraExport
+
+#endif
+
+
+//----------------------------------------------------------------------------------------
+// typedefs
+namespace astra {
+ typedef float float32;
+ typedef double float64;
+ typedef unsigned short int uint16;
+ typedef signed short int sint16;
+ typedef unsigned char uchar8;
+ typedef signed char schar8;
+
+ typedef int int32;
+ typedef short int int16;
+}
+
+//----------------------------------------------------------------------------------------
+// globals vars & functions
+//namespace astra {
+//#define ToolboxVersion 0.1f;
+
+//float32 getVersion() { return ToolboxVersion; }
+
+//_AstraExport bool cudaEnabled() {
+//#ifdef ASTRA_CUDA
+// return true;
+//#else
+// return false;
+//#endif
+//}
+//}
+
+//----------------------------------------------------------------------------------------
+// errors
+namespace astra {
+
+typedef enum {ASTRA_SUCCESS,
+ ASTRA_ERROR_NOT_INITIALIZED,
+ ASTRA_ERROR_INVALID_FILE,
+ ASTRA_ERROR_OUT_OF_RANGE,
+ ASTRA_ERROR_DIMENSION_MISMATCH,
+ ASTRA_ERROR_EXTERNAL_LIBRARY,
+ ASTRA_ERROR_ALLOCATION,
+ ASTRA_ERROR_NOT_IMPLEMENTED} AstraError;
+}
+
+
+//----------------------------------------------------------------------------------------
+// variables
+namespace astra {
+ const float32 PI = 3.14159265358979323846264338328f;
+ const float32 PI32 = 3.14159265358979323846264338328f;
+ const float32 PIdiv2 = PI / 2;
+ const float32 PIdiv4 = PI / 4;
+ const float32 eps = 1e-7f;
+}
+
+//----------------------------------------------------------------------------------------
+// math
+namespace astra {
+
+ inline float32 cos_73s(float32 x)
+ {
+ /*
+ const float32 c1 = 0.999999953464f;
+ const float32 c2 = -0.4999999053455f;
+ const float32 c3 = 0.0416635846769f;
+ const float32 c4 = -0.0013853704264f;
+ const float32 c5 = 0.000023233f;
+ */
+ const float c1= (float)0.99940307;
+ const float c2= (float)-0.49558072;
+ const float c3= (float)0.03679168;
+
+ float32 x2;
+ x2 = x * x;
+ //return (c1 + x2*(c2 + x2*(c3 + x2*(c4 + c5*x2))));
+ return (c1 + x2*(c2 + c3 * x2));
+ }
+
+ inline float32 fast_cos(float32 x)
+ {
+ int quad;
+
+ //x = fmod(x, 2*PI); // Get rid of values > 2* pi
+ if (x < 0) x =- x; // cos(-x) = cos(x)
+ quad = int(x/PIdiv2); // Get quadrant # (0 to 3)
+ switch (quad) {
+ case 0: return cos_73s(x);
+ case 1: return -cos_73s(PI-x);
+ case 2: return -cos_73s(x-PI);
+ case 3: return cos_73s(2*PI-x);
+ }
+ return 0.0f;
+ }
+
+ inline float32 fast_sin(float32 x){
+ return fast_cos(PIdiv2-x);
+ }
+
+}
+
+//----------------------------------------------------------------------------------------
+// structs
+namespace astra {
+ /**
+ * Struct for storing pixel weigths
+ **/
+ struct SPixelWeight
+ {
+ int m_iIndex;
+ float32 m_fWeight;
+ };
+
+ /**
+ * Struct combining some properties of a detector in 1D detector row
+ **/
+ struct SDetector2D
+ {
+ int m_iIndex;
+ int m_iAngleIndex;
+ int m_iDetectorIndex;
+ };
+
+ /**
+ * Struct combining some properties of a detector in 2D detector array
+ **/
+ struct SDetector3D
+ {
+ int m_iIndex;
+ int m_iAngleIndex;
+ int m_iDetectorIndex;
+ int m_iSliceIndex;
+ };
+}
+//----------------------------------------------------------------------------------------
+// some toys
+
+// safe reinterpret cast
+template <class To, class From>
+To safe_reinterpret_cast(From from)
+{
+ BOOST_STATIC_ASSERT(sizeof(From) <= sizeof(To));
+ return reinterpret_cast<To>(from);
+}
+
+//----------------------------------------------------------------------------------------
+// functions for testing
+template<typename T>
+inline void writeArray(T*** arr, int dim1, int dim2, int dim3, const std::string& filename)
+{
+ std::ofstream out(filename.c_str());
+ int i1, i2, i3;
+ for (i1 = 0; i1 < dim1; ++i1) {
+ for (i2 = 0; i2 < dim2; ++i2) {
+ for (i3 = 0; i3 < dim3; ++i3) {
+ out << arr[i1][i2][i3] << " ";
+ }
+ out << std::endl;
+ }
+ out << std::endl;
+ }
+ out.close();
+}
+
+template<typename T>
+inline void writeArray(T** arr, int dim1, int dim2, const std::string& filename)
+{
+ std::ofstream out(filename.c_str());
+ for (int i1 = 0; i1 < dim1; i1++) {
+ for (int i2 = 0; i2 < dim2; i2++) {
+ out << arr[i1][i2] << " ";
+ }
+ out << std::endl;
+ }
+ out.close();
+}
+
+template<typename T>
+inline void writeArray(T* arr, int dim1, const std::string& filename)
+{
+ std::ofstream out(filename.c_str());
+ for (int i1 = 0; i1 < dim1; i1++) {
+ out << arr[i1] << " ";
+ }
+ out.close();
+}
+namespace astra {
+_AstraExport inline int getVersion() { return ASTRA_TOOLBOXVERSION; }
+_AstraExport inline const char* getVersionString() { return ASTRA_TOOLBOXVERSION_STRING; }
+#ifdef ASTRA_CUDA
+_AstraExport inline bool cudaEnabled() { return true; }
+#else
+_AstraExport inline bool cudaEnabled() { return false; }
+#endif
+}
+//----------------------------------------------------------------------------------------
+// portability between MSVC and Linux/gcc
+
+#ifndef _MSC_VER
+#include "swrap.h"
+#define EXPIMP_TEMPLATE
+
+#if !defined(FORCEINLINE) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define FORCEINLINE inline __attribute__((__always_inline__))
+#else
+#define FORCEINLINE inline
+#endif
+
+#else
+
+#define FORCEINLINE __forceinline
+
+#endif
+
+#endif
diff --git a/include/astra/Logger.h b/include/astra/Logger.h
new file mode 100644
index 0000000..ae064fe
--- /dev/null
+++ b/include/astra/Logger.h
@@ -0,0 +1,72 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_LOGGER
+#define _INC_ASTRA_LOGGER
+
+#include <cstdio>
+
+namespace astra
+{
+
+/**
+ * This is the first stab at a decent logger. If the file "astra_logger.txt", it will be replaced
+ * with the text sent to this logger. If the file doesn't exist when the app starts, nothing is written.
+ */
+class CLogger
+{
+ static std::FILE * m_pOutFile;
+ static bool m_bInitialized;
+
+ static void _assureIsInitialized();
+
+ CLogger();
+
+public:
+
+ /**
+ * Writes a line to the log file (newline is added). Ignored if logging is turned off.
+ *
+ * @param _text char pointer to text in line
+ */
+ static void writeLine(const char * _text);
+
+ /**
+ * Formats and writes a CUDA error to the log file. Ignored if logging is turned off.
+ *
+ * @param _fileName filename where error occurred (typically __FILE__)
+ * @param _line line in file (typically __LINE__)
+ * @param _errString string describing the error, can be output of cudaGetErrorString
+ */
+ static void writeTerminalCUDAError(const char * _fileName, int _iLine, const char * _errString);
+};
+
+}
+
+#endif /* _INC_ASTRA_LOGGER */
+
diff --git a/include/astra/ParallelBeamBlobKernelProjector2D.h b/include/astra/ParallelBeamBlobKernelProjector2D.h
new file mode 100644
index 0000000..38b209c
--- /dev/null
+++ b/include/astra/ParallelBeamBlobKernelProjector2D.h
@@ -0,0 +1,232 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PARALLELBEAMBLOBPROJECTOR
+#define _INC_ASTRA_PARALLELBEAMBLOBPROJECTOR
+
+#include "ParallelProjectionGeometry2D.h"
+#include "Float32Data2D.h"
+#include "Projector2D.h"
+
+namespace astra
+{
+
+/** This class implements a two-dimensional projector based on a blob-kernel.
+ * A more detailed description (in dutch) is available at
+ * http://www.astra.ua.ac.be/wiki/images/6/6e/Uitleg_blob_projector.pdf
+ *
+ * \par XML Configuration
+ * type = "blob"
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ * \astra_xml_item{Kernel, xml node, Kernel details. See below.}
+ *
+ * \par XML Configuration of the Kernel
+ * \astra_xml_item{KernelSize, float, Radius of the kernel.}
+ * \astra_xml_item{SampleRate, float, Sample rate of the kernel.}
+ * \astra_xml_item{SampleCount, integer, Number of samples.}
+ * \astra_xml_item{KernelValues, vector of float, Samples of the kernels starting at distance 0.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('blob');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * cfg.Kernel.KernelSize = 2;\n
+ * cfg.Kernel.SampleRate = 0.01;\n
+ * cfg.Kernel.SampleCount = length(0:0.01:2);\n
+ * cfg.Kernel.KernelValues = kaiserBessel(2\, 10.4\, 2\, 0:0.01:2);\n
+ * proj_id = astra_mex_projector('create'\, cfg);\n
+ * }
+ */
+class _AstraExport CParallelBeamBlobKernelProjector2D : public CProjector2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - blobvalues are ok
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /** Default constructor.
+ */
+ CParallelBeamBlobKernelProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ * @param _fBlobSize Width of the blob. In units of PixelSize.
+ * @param _fBlobSampleRate Spacing between two blob samples. (= _fBlobSize/_iBlobSampleCount)
+ * @param _iBlobSampleCount Number of samples.
+ * @param _pfBlobValues Array of _iBlobSampleCount blob evaluations.
+ */
+ CParallelBeamBlobKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry,
+ float32 _fBlobSize,
+ float32 _fBlobSampleRate,
+ int _iBlobSampleCount,
+ float32* _pfBlobValues);
+
+ /** Destructor, is virtual to show that we are aware subclass destructor are called.
+ */
+ ~CParallelBeamBlobKernelProjector2D();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the projector.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ * @param _fBlobSize Width of the blob. In units of PixelSize.
+ * @param _fBlobSampleRate Spacing between two blob samples. (= _fBlobSize/_iBlobSampleCount)
+ * @param _iBlobSampleCount Number of samples.
+ * @param _pfBlobValues Array of _iBlobSampleCount blob evaluations. Will be HARDCOPIED.
+ */
+ bool initialize(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry,
+ float32 _fBlobSize,
+ float32 _fBlobSampleRate,
+ int _iBlobSampleCount,
+ float32* _pfBlobValues);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Returns the number of weights required for storage of all weights of one projection.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex);
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection
+ * @param _iDetectorIndex Index of the detector pixel
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol);
+
+ /** Policy-based projection of all rays. This function will calculate each non-zero projection
+ * weight and use this value for a task provided by the policy object.
+ *
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void project(Policy& _policy);
+
+ /** Policy-based projection of all rays of a single projection. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Wwhich projection should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy);
+
+ /** Policy-based projection of a single ray. This function will calculate each non-zero
+ * projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Which projection should be projected?
+ * @param _iDetector Which detector should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy);
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType();
+
+protected:
+
+ /** Evaluate the blob kernel for a given distance from its center.
+ *
+ * @param _fDiff distance between hit point and blob center
+ * @return blob value
+ */
+ float32 _getBlobValue(float32 _fDiff);
+
+ float32 m_fBlobSize; //< Width of the blob
+ float32 m_fBlobSampleRate; //< At which interval are the inserted blob values evaluated?
+ int m_iBlobSampleCount; //< Number of evaluated blob samples
+ float32* m_pfBlobValues; //< Evaluated blob values
+ float32* m_pfBlobValuesNeg; //< Evaluated blob values
+
+};
+
+//----------------------------------------------------------------------------------------
+
+inline std::string CParallelBeamBlobKernelProjector2D::getType()
+{
+ return type;
+}
+
+} // namespace astra
+
+#endif
+
diff --git a/include/astra/ParallelBeamBlobKernelProjector2D.inl b/include/astra/ParallelBeamBlobKernelProjector2D.inl
new file mode 100644
index 0000000..70764b1
--- /dev/null
+++ b/include/astra/ParallelBeamBlobKernelProjector2D.inl
@@ -0,0 +1,212 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT ALL
+template <typename Policy>
+void CParallelBeamBlobKernelProjector2D::project(Policy& p)
+{
+ for (int iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) {
+ for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+ projectSingleRay(iAngle, iDetector, p);
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE PROJECTION
+template <typename Policy>
+void CParallelBeamBlobKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p)
+{
+ for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+ projectSingleRay(_iProjection, iDetector, p);
+ }
+}
+
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE RAY
+template <typename Policy>
+void CParallelBeamBlobKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) return;
+
+ // get values
+ float32 t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector);
+ float32 theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+
+ bool flip = false;
+
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ t = -t;
+ flip = true;
+ }
+
+
+ if (theta <= PIdiv4) { // -pi/4 <= theta <= pi/4
+
+ // precalculate sin, cos, 1/cos
+ float32 sin_theta = sin(theta);
+ float32 cos_theta = cos(theta);
+ float32 inv_cos_theta = 1.0f / cos_theta;
+
+ // precalculate other stuff
+ float32 lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ float32 updatePerRow = sin_theta * lengthPerRow;
+ float32 inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+ float32 pixelLengthX_over_blobSize = m_pVolumeGeometry->getPixelLengthX() / m_fBlobSize;
+
+ // some variables
+ int row, col, xmin, xmax;
+ float32 P, x, d;
+
+ // calculate P and x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // calculate extent
+ xmin = (int)ceil((P - m_fBlobSize - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f);
+ xmax = (int)floor((P + m_fBlobSize - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f);
+
+ // add pixels
+ for (col = xmin; col <= xmax; col++) {
+ if (col >= 0 && col < m_pVolumeGeometry->getGridColCount()) {
+ //d = abs(x - col) * pixelLengthX_over_blobSize;
+ //index = (int)(d*m_iBlobSampleCount+0.5f);
+ //float32 fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)] * lengthPerRow;
+
+ float32 fWeight;
+ int index;
+ if ((x >= col) ^ flip) {
+ d = abs(x - col) * pixelLengthX_over_blobSize * cos_theta;
+ index = (int)(d*m_iBlobSampleCount+0.5f);
+ fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)];
+ } else {
+ d = abs(x - col) * pixelLengthX_over_blobSize * cos_theta;
+ index = (int)(d*m_iBlobSampleCount+0.5f);
+ fWeight = m_pfBlobValuesNeg[min(index,m_iBlobSampleCount-1)];
+ }
+
+ int iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, fWeight);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // update P and x
+ P += updatePerRow;
+ x += updatePerRow * inv_pixelLengthX;
+ }
+
+ } else { // pi/4 < theta < 3pi/4
+
+ // precalculate sin cos
+ float32 sin_90_theta = sin(PIdiv2-theta);
+ float32 cos_90_theta = cos(PIdiv2-theta);
+ float32 inv_cos_90_theta = 1.0f / cos_90_theta;
+
+ // precalculate other stuff
+ float32 lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_cos_90_theta;
+ float32 updatePerCol = sin_90_theta * lengthPerCol;
+ float32 inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+ float32 pixelLengthY_over_blobSize = m_pVolumeGeometry->getPixelLengthY() / m_fBlobSize;
+
+ // some variables
+ int row, col, xmin, xmax;
+ float32 P,x, d;
+
+ // calculate P and x for col 0
+ P = (sin_90_theta * m_pVolumeGeometry->pixelColToCenterX(0) - t) * inv_cos_90_theta;
+ x = (P - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // calculate extent
+ xmin = (int)ceil((P - m_fBlobSize - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f);
+ xmax = (int)floor((P + m_fBlobSize - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f);
+
+ // add pixels
+ for (row = xmin; row <= xmax; row++) {
+ if (row >= 0 && row < m_pVolumeGeometry->getGridRowCount()) {
+ //d = abs(x - row) * pixelLengthY_over_blobSize;
+ //int index = (int)(d*m_iBlobSampleCount+0.5f);
+ //float32 fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)] * lengthPerCol;
+
+ float32 fWeight;
+ int index;
+ if ((x <= row) ^ flip) {
+ d = abs(x - row) * pixelLengthY_over_blobSize * cos_90_theta;
+ index = (int)(d*m_iBlobSampleCount+0.5f);
+ fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)];
+ } else {
+ d = abs(x - row) * pixelLengthY_over_blobSize * cos_90_theta;
+ index = (int)(d*m_iBlobSampleCount+0.5f);
+ fWeight = m_pfBlobValuesNeg[min(index,m_iBlobSampleCount-1)];
+ }
+
+
+ int iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, fWeight);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // update P and x
+ P += updatePerCol;
+ x += updatePerCol * inv_pixelLengthY;
+ }
+
+ }
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+
+
+}
diff --git a/include/astra/ParallelBeamLineKernelProjector2D.h b/include/astra/ParallelBeamLineKernelProjector2D.h
new file mode 100644
index 0000000..9e2cc5a
--- /dev/null
+++ b/include/astra/ParallelBeamLineKernelProjector2D.h
@@ -0,0 +1,186 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PARALLELBEAMLINEKERNELPROJECTOR
+#define _INC_ASTRA_PARALLELBEAMLINEKERNELPROJECTOR
+
+#include "ParallelProjectionGeometry2D.h"
+#include "Float32Data2D.h"
+#include "Projector2D.h"
+
+namespace astra
+{
+
+/** This class implements a two-dimensional projector based on a line based kernel.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('line');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * proj_id = astra_mex_projector('create'\, cfg);\n
+ * }
+ */
+class _AstraExport CParallelBeamLineKernelProjector2D : public CProjector2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - blobvalues are ok
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /** Default constructor.
+ */
+ CParallelBeamLineKernelProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ */
+ CParallelBeamLineKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Destructor, is virtual to show that we are aware subclass destructor are called.
+ */
+ ~CParallelBeamLineKernelProjector2D();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the projector.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ * @return initialization successful?
+ */
+ virtual bool initialize(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Returns the number of weights required for storage of all weights of one projection.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex);
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection
+ * @param _iDetectorIndex Index of the detector pixel
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol);
+
+ /** Policy-based projection of all rays. This function will calculate each non-zero projection
+ * weight and use this value for a task provided by the policy object.
+ *
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void project(Policy& _policy);
+
+ /** Policy-based projection of all rays of a single projection. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Wwhich projection should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy);
+
+ /** Policy-based projection of a single ray. This function will calculate each non-zero
+ * projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Which projection should be projected?
+ * @param _iDetector Which detector should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy);
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType();
+
+};
+
+inline std::string CParallelBeamLineKernelProjector2D::getType()
+{
+ return type;
+}
+
+} // namespace astra
+
+#endif
+
diff --git a/include/astra/ParallelBeamLineKernelProjector2D.inl b/include/astra/ParallelBeamLineKernelProjector2D.inl
new file mode 100644
index 0000000..08bbe5f
--- /dev/null
+++ b/include/astra/ParallelBeamLineKernelProjector2D.inl
@@ -0,0 +1,731 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT ALL
+template <typename Policy>
+void CParallelBeamLineKernelProjector2D::project(Policy& p)
+{
+ // variables
+ float32 theta, sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2;
+ float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY;
+ int iVolumeIndex, iRayIndex, row, col, iAngle, iDetector, x1;
+ bool switch_t;
+
+ // loop angles
+ for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) {
+
+ // get theta
+ theta = m_pProjectionGeometry->getProjectionAngle(iAngle);
+ switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_sin_theta = 1.0f / sin_theta;
+ inv_cos_theta = 1.0f / cos_theta;
+
+ // precalculate kernel limits
+ lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ updatePerRow = sin_theta * inv_cos_theta;
+ inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+
+ // precalculate kernel limits
+ lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ updatePerCol = cos_theta * inv_sin_theta;
+ inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+
+ // precalculate S and T
+ S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow);
+ T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol);
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
+ if (switch_t) t = -t;
+
+ // vertically
+ if (theta <= PIdiv4) {
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX;
+
+ // get coords
+ int nextx1 = int((x > 0.0f) ? x : x-1.0f);
+ float nextx2 = x - nextx1;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ x1 = nextx1;
+ x2 = nextx2;
+
+ nextx2 += updatePerRow;
+ while (nextx2 >= 1.0f) {
+ nextx2 -= 1.0f;
+ nextx1++;
+ }
+ while (nextx2 < 0.0f) {
+ nextx2 += 1.0f;
+ nextx1--;
+ }
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue;
+
+ // left
+ if (x2 < 0.5f-S) {
+ I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+S) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // right
+ else {
+ I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else if (PIdiv4 <= theta && theta <= 3*PIdiv4) {
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY;
+
+ // get coords
+ int nextx1 = int((x > 0.0f) ? x : x-1.0f);
+ float nextx2 = x - nextx1;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ x1 = nextx1;
+ x2 = nextx2;
+
+ nextx2 += updatePerCol;
+ while (nextx2 >= 1.0f) {
+ nextx2 -= 1.0f;
+ nextx1++;
+ }
+ while (nextx2 < 0.0f) {
+ nextx2 += 1.0f;
+ nextx1--;
+ }
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue;
+
+ // up
+ if (x2 < 0.5f-T) {
+ I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+T) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // down
+ else {
+ I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ } // end loop col
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end loop detector
+ } // end loop angles
+
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE PROJECTION
+template <typename Policy>
+void CParallelBeamLineKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p)
+{
+ // variables
+ float32 theta, sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, S, T, t, I, P, x, x2;
+ float32 lengthPerRow, updatePerRow, inv_pixelLengthX, lengthPerCol, updatePerCol, inv_pixelLengthY;
+ int iVolumeIndex, iRayIndex, row, col, iDetector, x1;
+ bool switch_t;
+
+ // get theta
+ theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_sin_theta = 1.0f / sin_theta;
+ inv_cos_theta = 1.0f / cos_theta;
+
+ // precalculate kernel limits
+ lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ updatePerRow = sin_theta * inv_cos_theta;
+ inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+
+ // precalculate kernel limits
+ lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ updatePerCol = cos_theta * inv_sin_theta;
+ inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+
+ // precalculate S and T
+ S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow);
+ T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol);
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
+ if (switch_t) t = -t;
+
+ // vertically
+ if (theta <= PIdiv4) {
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX;
+
+ // get coords
+ int nextx1 = int((x > 0.0f) ? x : x-1.0f);
+ float nextx2 = x - nextx1;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ x1 = nextx1;
+ x2 = nextx2;
+
+ nextx2 += updatePerRow;
+ while (nextx2 >= 1.0f) {
+ nextx2 -= 1.0f;
+ nextx1++;
+ }
+ while (nextx2 < 0.0f) {
+ nextx2 += 1.0f;
+ nextx1--;
+ }
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue;
+
+ // left
+ if (x2 < 0.5f-S) {
+ I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+S) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // right
+ else {
+ I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else if (PIdiv4 <= theta && theta <= 3*PIdiv4) {
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY;
+
+ // get coords
+ int nextx1 = int((x > 0.0f) ? x : x-1.0f);
+ float nextx2 = x - nextx1;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ x1 = nextx1;
+ x2 = nextx2;
+
+ nextx2 += updatePerCol;
+ while (nextx2 >= 1.0f) {
+ nextx2 -= 1.0f;
+ nextx1++;
+ }
+ while (nextx2 < 0.0f) {
+ nextx2 += 1.0f;
+ nextx1--;
+ }
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue;
+
+ // up
+ if (x2 < 0.5f-T) {
+ I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+T) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // down
+ else {
+ I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ } // end loop col
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end loop detector
+}
+
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE RAY
+template <typename Policy>
+void CParallelBeamLineKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p)
+{
+ int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) return;
+
+ // variables
+ float32 t, I, P, x, x2;
+ int iVolumeIndex, row, col, x1;
+
+ // get theta
+ float32 theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ bool switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector);
+ if (switch_t) t = -t;
+
+ // vertically
+ if (theta <= PIdiv4) {
+
+ float32 sin_theta = sin(theta);
+ float32 inv_cos_theta = 1.0f / cos(theta);
+
+ // precalculate kernel limits
+ float32 lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ float32 updatePerRow = sin_theta * inv_cos_theta;
+ float32 inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+ float32 S = 0.5f - 0.5f * ((updatePerRow < 0) ? -updatePerRow : updatePerRow);
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX;
+
+ // get coords
+ int nextx1 = int((x > 0.0f) ? x : x-1.0f);
+ float nextx2 = x - nextx1;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ x1 = nextx1;
+ x2 = nextx2;
+
+ nextx2 += updatePerRow;
+ while (nextx2 >= 1.0f) {
+ nextx2 -= 1.0f;
+ nextx1++;
+ }
+ while (nextx2 < 0.0f) {
+ nextx2 += 1.0f;
+ nextx1--;
+ }
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridColCount()) continue;
+
+ // left
+ if (x2 < 0.5f-S) {
+ I = (0.5f - S + x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1-1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+S) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // right
+ else {
+ I = (1.5f - S - x2) / (1.0f - 2.0f*S) * lengthPerRow;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerRow-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else if (PIdiv4 <= theta && theta <= 3*PIdiv4) {
+
+ float32 cos_theta = cos(theta);
+ float32 inv_sin_theta = 1.0f / sin(theta);
+
+ // precalculate kernel limits
+ float32 lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ float32 updatePerCol = cos_theta * inv_sin_theta;
+ float32 inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+ float32 T = 0.5f - 0.5f * ((updatePerCol < 0) ? -updatePerCol : updatePerCol);
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = (m_pVolumeGeometry->getWindowMaxY() - P) * inv_pixelLengthY;
+
+ // get coords
+ int nextx1 = int((x > 0.0f) ? x : x-1.0f);
+ float nextx2 = x - nextx1;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ x1 = nextx1;
+ x2 = nextx2;
+
+ nextx2 += updatePerCol;
+ while (nextx2 >= 1.0f) {
+ nextx2 -= 1.0f;
+ nextx1++;
+ }
+ while (nextx2 < 0.0f) {
+ nextx2 += 1.0f;
+ nextx1--;
+ }
+
+ if (x1 < -1 || x1 > m_pVolumeGeometry->getGridRowCount()) continue;
+
+ // up
+ if (x2 < 0.5f-T) {
+ I = (0.5f - T + x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1-1 >= 0 && x1-1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1-1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // center
+ else if (x2 <= 0.5f+T) {
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+
+ // down
+ else {
+ I = (1.5f - T - x2) / (1.0f - 2.0f*T) * lengthPerCol;
+
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, lengthPerCol-I);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+ } // end loop col
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+}
diff --git a/include/astra/ParallelBeamLinearKernelProjector2D.h b/include/astra/ParallelBeamLinearKernelProjector2D.h
new file mode 100644
index 0000000..ac5899e
--- /dev/null
+++ b/include/astra/ParallelBeamLinearKernelProjector2D.h
@@ -0,0 +1,194 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PARALLELLINEARKERNELPROJECTOR
+#define _INC_ASTRA_PARALLELLINEARKERNELPROJECTOR
+
+#include "ParallelProjectionGeometry2D.h"
+#include "Float32Data2D.h"
+#include "Projector2D.h"
+
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+namespace astra
+{
+
+/** This class implements a two-dimensional projector based on a lineary interpolated kernel.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('linear');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * proj_id = astra_mex_projector('create'\, cfg);\n
+ * }
+ */
+class _AstraExport CParallelBeamLinearKernelProjector2D : public CProjector2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - blobvalues are ok
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /** Default constructor.
+ */
+ CParallelBeamLinearKernelProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ */
+ CParallelBeamLinearKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Destructor, is virtual to show that we are aware subclass destructor are called.
+ */
+ ~CParallelBeamLinearKernelProjector2D();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the projector.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ * @return initialization successful?
+ */
+ virtual bool initialize(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Returns the number of weights required for storage of all weights of one projection.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex);
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection
+ * @param _iDetectorIndex Index of the detector pixel
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol);
+
+
+ /** Policy-based projection of all rays. This function will calculate each non-zero projection
+ * weight and use this value for a task provided by the policy object.
+ *
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void project(Policy& _policy);
+
+ /** Policy-based projection of all rays of a single projection. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Which projection should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy);
+
+ /** Policy-based projection of a single ray. This function will calculate each non-zero
+ * projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Which projection should be projected?
+ * @param _iDetector Which detector should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy);
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType();
+
+};
+
+//----------------------------------------------------------------------------------------
+
+inline std::string CParallelBeamLinearKernelProjector2D::getType()
+{
+ return type;
+}
+
+
+} // namespace astra
+
+
+#endif
+
diff --git a/include/astra/ParallelBeamLinearKernelProjector2D.inl b/include/astra/ParallelBeamLinearKernelProjector2D.inl
new file mode 100644
index 0000000..66b1cb2
--- /dev/null
+++ b/include/astra/ParallelBeamLinearKernelProjector2D.inl
@@ -0,0 +1,416 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT ALL
+template <typename Policy>
+void CParallelBeamLinearKernelProjector2D::project(Policy& p)
+{
+ // variables
+ float32 theta, sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, t;
+ float32 lengthPerRow, updatePerRow, inv_pixelLengthX;
+ float32 lengthPerCol, updatePerCol, inv_pixelLengthY;
+ bool switch_t;
+ int iAngle, iDetector, iVolumeIndex, iRayIndex;
+ int row, col, x1;
+ float32 P,x,x2;
+
+ // loop angles
+ for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) {
+
+ // get theta
+ theta = m_pProjectionGeometry->getProjectionAngle(iAngle);
+ switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_cos_theta = 1.0f / cos_theta;
+ inv_sin_theta = 1.0f / sin_theta;
+
+ // precalculate kernel limits
+ lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ updatePerRow = sin_theta * inv_cos_theta;
+ inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+
+ // precalculate kernel limits
+ lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ updatePerCol = cos_theta * inv_sin_theta;
+ inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
+ if (switch_t) {
+ t = -t;
+ }
+
+ // vertically
+ if (theta <= PIdiv4) {
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = m_pVolumeGeometry->coordXToColF(P) - 0.5f;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get coords
+ x1 = int((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerRow;
+
+ // add weights
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (x2) * lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else if (PIdiv4 <= theta && theta <= 3*PIdiv4) {
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = m_pVolumeGeometry->coordYToRowF(P) - 0.5f;
+
+ // for each row
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get coords
+ x1 = int((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerCol;
+
+ // add weights
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, x2 * lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end loop detector
+ } // end loop angles
+
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE PROJECTION
+template <typename Policy>
+void CParallelBeamLinearKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p)
+{
+ // variables
+ float32 theta, sin_theta, cos_theta, inv_sin_theta, inv_cos_theta, t;
+ float32 lengthPerRow, updatePerRow, inv_pixelLengthX;
+ float32 lengthPerCol, updatePerCol, inv_pixelLengthY;
+ bool switch_t;
+ int iDetector, iVolumeIndex, iRayIndex;
+ int row, col, x1;
+ float32 P,x,x2;
+
+ // get theta
+ theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_cos_theta = 1.0f / cos_theta;
+ inv_sin_theta = 1.0f / sin_theta;
+
+ // precalculate kernel limits
+ lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ updatePerRow = sin_theta * inv_cos_theta;
+ inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX();
+
+ // precalculate kernel limits
+ lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ updatePerCol = cos_theta * inv_sin_theta;
+ inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY();
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
+ if (switch_t) {
+ t = -t;
+ }
+
+ // vertically
+ if (theta <= PIdiv4) {
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = m_pVolumeGeometry->coordXToColF(P) - 0.5f;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get coords
+ x1 = (int)((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerRow;
+
+ // add weights
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (x2) * lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else if (PIdiv4 <= theta && theta <= 3*PIdiv4) {
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = m_pVolumeGeometry->coordYToRowF(P) - 0.5f;
+
+ // for each row
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get coords
+ x1 = (int)((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerCol;
+
+ // add weights
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, x2 * lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end loop detector
+}
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE RAY
+template <typename Policy>
+void CParallelBeamLinearKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p)
+{
+ int iVolumeIndex, iRayIndex;
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) return;
+
+ // get theta
+ float32 theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ bool switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // get t
+ float32 t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector);
+ if (switch_t) {
+ t = -t;
+ }
+
+ // vertically
+ if (theta <= PIdiv4) {
+
+ // precalculate sin, 1/cos
+ float32 sin_theta = sin(theta);
+ float32 inv_cos_theta = 1.0f / cos(theta);
+
+ // precalculate kernel limits
+ float32 lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta;
+ float32 updatePerRow = sin_theta * inv_cos_theta;
+
+ int row, x1;
+ float32 P,x,x2;
+
+ // calculate x for row 0
+ P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta;
+ x = m_pVolumeGeometry->coordXToColF(P) - 0.5f;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get coords
+ x1 = (int)((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerRow;
+
+ // add weights
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridColCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, x1+1);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (x2) * lengthPerRow);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else if (PIdiv4 <= theta && theta <= 3*PIdiv4) {
+
+ // precalculate cos 1/sin
+ float32 cos_theta = cos(theta);
+ float32 inv_sin_theta = 1.0f / sin(theta);
+
+ // precalculate kernel limits
+ float32 lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_sin_theta;
+ float32 updatePerCol = cos_theta * inv_sin_theta;
+
+ int col, x1;
+ float32 P,x,x2;
+
+ // calculate point P
+ P = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0)) * inv_sin_theta;
+ x = m_pVolumeGeometry->coordYToRowF(P) - 0.5f;
+
+ // for each row
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get coords
+ x1 = (int)((x > 0.0f) ? x : x-1.0f);
+ x2 = x - x1;
+ x += updatePerCol;
+
+ // add weights
+ if (x1 >= 0 && x1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, (1.0f - x2) * lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ if (x1+1 >= 0 && x1+1 < m_pVolumeGeometry->getGridRowCount()) {
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(x1+1, col);
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+ p.addWeight(iRayIndex, iVolumeIndex, x2 * lengthPerCol);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+}
diff --git a/include/astra/ParallelBeamStripKernelProjector2D.h b/include/astra/ParallelBeamStripKernelProjector2D.h
new file mode 100644
index 0000000..de056de
--- /dev/null
+++ b/include/astra/ParallelBeamStripKernelProjector2D.h
@@ -0,0 +1,191 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PARALLELBEAMSTROKEKERNELPROJECTOR
+#define _INC_ASTRA_PARALLELBEAMSTROKEKERNELPROJECTOR
+
+#include "ParallelProjectionGeometry2D.h"
+#include "Float32Data2D.h"
+#include "Projector2D.h"
+
+namespace astra
+{
+
+
+/** This class implements a two-dimensional projector based on a strip based kernel.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('strip');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * proj_id = astra_mex_projector('create'\, cfg);\n
+ * }
+ */
+class _AstraExport CParallelBeamStripKernelProjector2D : public CProjector2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - blobvalues are ok
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /** Default constructor.
+ */
+ CParallelBeamStripKernelProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ */
+ CParallelBeamStripKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Destructor, is virtual to show that we are aware subclass destructor are called.
+ */
+ ~CParallelBeamStripKernelProjector2D();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the projector.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ * @return initialization successful?
+ */
+ virtual bool initialize(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Returns the number of weights required for storage of all weights of one projection.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex);
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection
+ * @param _iDetectorIndex Index of the detector pixel
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol);
+
+ /** Policy-based projection of all rays. This function will calculate each non-zero projection
+ * weight and use this value for a task provided by the policy object.
+ *
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void project(Policy& _policy);
+
+ /** Policy-based projection of all rays of a single projection. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Wwhich projection should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy);
+
+ /** Policy-based projection of a single ray. This function will calculate each non-zero
+ * projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Which projection should be projected?
+ * @param _iDetector Which detector should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy);
+
+protected:
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType();
+
+};
+
+//----------------------------------------------------------------------------------------
+
+inline std::string CParallelBeamStripKernelProjector2D::getType()
+{
+ return type;
+}
+
+} // namespace astra
+
+#endif
+
diff --git a/include/astra/ParallelBeamStripKernelProjector2D.inl b/include/astra/ParallelBeamStripKernelProjector2D.inl
new file mode 100644
index 0000000..c55fa8e
--- /dev/null
+++ b/include/astra/ParallelBeamStripKernelProjector2D.inl
@@ -0,0 +1,739 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT ALL
+template <typename Policy>
+void CParallelBeamStripKernelProjector2D::project(Policy& p)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ // Some variables
+ float32 theta, t;
+ int row, col;
+ int iAngle;
+ int iDetector;
+ float32 res;
+ float32 PL, PLimitL, PLimitR;
+ float32 xL, xR, XLimitL, XLimitR;
+ int x1L,x1R;
+ float32 x2L, x2R, updateX;
+ int iVolumeIndex, iRayIndex;
+
+ float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta;
+ float32 fabs_sin_theta, fabs_cos_theta, fabs_inv_sin_theta, fabs_inv_cos_theta;
+ float32 PW, PH, DW, inv_PW, inv_PH;
+ float32 S, T, U, V, inv_4T;
+
+ // loop angles
+ for (iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) {
+
+ // get values
+ theta = m_pProjectionGeometry->getProjectionAngle(iAngle);
+ bool switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // Precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_cos_theta = 1.0f / cos_theta;
+ inv_sin_theta = 1.0f / sin_theta;
+
+ fabs_sin_theta = (sin_theta < 0.0f) ? -sin_theta : sin_theta;
+ fabs_cos_theta = (cos_theta < 0.0f) ? -cos_theta : cos_theta;
+ fabs_inv_cos_theta = (inv_cos_theta < 0.0f) ? -inv_cos_theta : inv_cos_theta;
+ fabs_inv_sin_theta = (inv_sin_theta < 0.0f) ? -inv_sin_theta : inv_sin_theta;
+
+ // Other precalculations
+ PW = m_pVolumeGeometry->getPixelLengthX();
+ PH = m_pVolumeGeometry->getPixelLengthY();
+ DW = m_pProjectionGeometry->getDetectorWidth();
+ inv_PW = 1.0f / PW;
+ inv_PH = 1.0f / PH;
+
+ // [-45?,45?] and [135?,225?]
+ if (theta < PIdiv4) {
+
+ // Precalculate kernel limits
+ S = -0.5f * fabs_sin_theta * fabs_inv_cos_theta;
+ T = -S;
+ U = 1.0f + S;
+ V = 1.0f - S;
+ inv_4T = 0.25f / T;
+
+ updateX = sin_theta * inv_cos_theta;
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
+ if (switch_t) t = -t;
+
+ // calculate left strip extremes (volume coordinates)
+ PL = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0) - DW*0.5f) * inv_cos_theta;
+ PLimitL = PL - 0.5f * fabs_sin_theta * fabs_inv_cos_theta * PH;
+ PLimitR = PLimitL + DW * inv_cos_theta + PH * fabs_sin_theta * fabs_inv_cos_theta;
+
+ // calculate strip extremes (pixel coordinates)
+ XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ xR = xL + (DW * inv_cos_theta) * inv_PW;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX;
+ XLimitR += updateX;
+ xL += updateX;
+ xR += updateX;
+
+ // for each affected col
+ for (col = x1L; col <= x1R; ++col) {
+
+ if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V) res = 1.0f;
+ else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T;
+ else if (x2R >= T) res = x2R;
+ else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S) {} // - 0.0f
+ else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T;
+ else if (x2L <= U) res -= x2L;
+ else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end detector loop
+
+ // [45?,135?] and [225?,315?]
+ // horizontaly
+ } else {
+
+ // Precalculate kernel limits
+ S = -0.5f * fabs_cos_theta * fabs_inv_sin_theta;
+ T = -S;
+ U = 1.0f + S;
+ V = 1.0f - S;
+ inv_4T = 0.25f / T;
+
+ updateX = cos_theta * inv_sin_theta;
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
+ if (switch_t) t = -t;
+
+ // calculate left strip extremes (volume coordinates)
+ PL = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0) + DW*0.5f) * inv_sin_theta;
+ PLimitL = PL + 0.5f * fabs_cos_theta * fabs_inv_sin_theta * PW;
+ PLimitR = PLimitL - DW * inv_sin_theta - PH * fabs_cos_theta * fabs_inv_sin_theta;
+
+ // calculate strip extremes (pixel coordinates)
+ XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH;
+ XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH;
+ xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH;
+ xR = xL + (DW * fabs_inv_sin_theta) * inv_PH;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX;
+ XLimitR += updateX;
+ xL += updateX;
+ xR += updateX;
+
+ // for each affected col
+ for (row = x1L; row <= x1R; ++row) {
+
+ if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V) res = 1.0f;
+ else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T;
+ else if (x2R >= T) res = x2R;
+ else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S) {} // - 0.0f
+ else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T;
+ else if (x2L <= U) res -= x2L;
+ else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end row loop
+
+ } // end col loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end detector loop
+
+
+ } // end theta switch
+
+ } // end angle loop
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE PROJECTION
+template <typename Policy>
+void CParallelBeamStripKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p)
+{
+ // Some variables
+ float32 theta, t;
+ int row, col, iDetector;
+ float32 res;
+ float32 PL, PLimitL, PLimitR;
+ float32 xL, xR, XLimitL, XLimitR;
+ int x1L,x1R;
+ float32 x2L, x2R, updateX;
+ int iVolumeIndex, iRayIndex;
+
+ float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta;
+ float32 fabs_sin_theta, fabs_cos_theta, fabs_inv_sin_theta, fabs_inv_cos_theta;
+ float32 PW, PH, DW, inv_PW, inv_PH;
+ float32 S, T, U, V, inv_4T;
+
+ // get values
+ theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ bool switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // Precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_cos_theta = 1.0f / cos_theta;
+ inv_sin_theta = 1.0f / sin_theta;
+
+ fabs_sin_theta = (sin_theta < 0.0f) ? -sin_theta : sin_theta;
+ fabs_cos_theta = (cos_theta < 0.0f) ? -cos_theta : cos_theta;
+ fabs_inv_cos_theta = (inv_cos_theta < 0.0f) ? -inv_cos_theta : inv_cos_theta;
+ fabs_inv_sin_theta = (inv_sin_theta < 0.0f) ? -inv_sin_theta : inv_sin_theta;
+
+ // Other precalculations
+ PW = m_pVolumeGeometry->getPixelLengthX();
+ PH = m_pVolumeGeometry->getPixelLengthY();
+ DW = m_pProjectionGeometry->getDetectorWidth();
+ inv_PW = 1.0f / PW;
+ inv_PH = 1.0f / PH;
+
+ // [-45?,45?] and [135?,225?]
+ if (theta < PIdiv4) {
+
+ // Precalculate kernel limits
+ S = -0.5f * fabs_sin_theta * fabs_inv_cos_theta;
+ T = -S;
+ U = 1.0f + S;
+ V = 1.0f - S;
+ inv_4T = 0.25f / T;
+
+ updateX = sin_theta * inv_cos_theta;
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
+ if (switch_t) t = -t;
+
+ // calculate left strip extremes (volume coordinates)
+ PL = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0) - DW*0.5f) * inv_cos_theta;
+ PLimitL = PL - 0.5f * fabs_sin_theta * fabs_inv_cos_theta * PH;
+ PLimitR = PLimitL + DW * inv_cos_theta + PH * fabs_sin_theta * fabs_inv_cos_theta;
+
+ // calculate strip extremes (pixel coordinates)
+ XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ xR = xL + (DW * inv_cos_theta) * inv_PW;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX;
+ XLimitR += updateX;
+ xL += updateX;
+ xR += updateX;
+
+ // for each affected col
+ for (col = x1L; col <= x1R; ++col) {
+
+ if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V) res = 1.0f;
+ else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T;
+ else if (x2R >= T) res = x2R;
+ else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S) {} // - 0.0f
+ else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T;
+ else if (x2L <= U) res -= x2L;
+ else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end detector loop
+
+ // [45?,135?] and [225?,315?]
+ // horizontaly
+ } else {
+
+ // Precalculate kernel limits
+ S = -0.5f * fabs_cos_theta * fabs_inv_sin_theta;
+ T = -S;
+ U = 1.0f + S;
+ V = 1.0f - S;
+ inv_4T = 0.25f / T;
+
+ updateX = cos_theta * inv_sin_theta;
+
+ // loop detectors
+ for (iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) {
+
+ iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
+ if (switch_t) t = -t;
+
+ // calculate left strip extremes (volume coordinates)
+ PL = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0) + DW*0.5f) * inv_sin_theta;
+ PLimitL = PL + 0.5f * fabs_cos_theta * fabs_inv_sin_theta * PW;
+ PLimitR = PLimitL - DW * inv_sin_theta - PH * fabs_cos_theta * fabs_inv_sin_theta;
+
+ // calculate strip extremes (pixel coordinates)
+ XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH;
+ XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH;
+ xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH;
+ xR = xL + (DW * fabs_inv_sin_theta) * inv_PH;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX;
+ XLimitR += updateX;
+ xL += updateX;
+ xR += updateX;
+
+ // for each affected col
+ for (row = x1L; row <= x1R; ++row) {
+
+ if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V) res = 1.0f;
+ else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T;
+ else if (x2R >= T) res = x2R;
+ else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S) {} // - 0.0f
+ else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T;
+ else if (x2L <= U) res -= x2L;
+ else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end row loop
+
+ } // end col loop
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end detector loop
+
+ } // end theta switch
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE RAY
+template <typename Policy>
+void CParallelBeamStripKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p)
+{
+ int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector;
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) return;
+
+ // Some variables
+ float32 theta, t;
+ int row, col;
+ float32 res;
+ float32 PL, PLimitL, PLimitR;
+ float32 xL, xR, XLimitL, XLimitR;
+ int x1L,x1R;
+ float32 x2L, x2R, updateX;
+ int iVolumeIndex;
+
+ float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta;
+ float32 fabs_sin_theta, fabs_cos_theta, fabs_inv_sin_theta, fabs_inv_cos_theta;
+ float32 PW, PH, DW, inv_PW, inv_PH;
+ float32 S, T, U, V, inv_4T;
+
+ // get values
+ theta = m_pProjectionGeometry->getProjectionAngle(_iProjection);
+ bool switch_t = false;
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ switch_t = true;
+ }
+
+ // Precalculate sin, cos, 1/cos
+ sin_theta = sin(theta);
+ cos_theta = cos(theta);
+ inv_cos_theta = 1.0f / cos_theta;
+ inv_sin_theta = 1.0f / sin_theta;
+
+ fabs_sin_theta = (sin_theta < 0.0f) ? -sin_theta : sin_theta;
+ fabs_cos_theta = (cos_theta < 0.0f) ? -cos_theta : cos_theta;
+ fabs_inv_cos_theta = (inv_cos_theta < 0.0f) ? -inv_cos_theta : inv_cos_theta;
+ fabs_inv_sin_theta = (inv_sin_theta < 0.0f) ? -inv_sin_theta : inv_sin_theta;
+
+ // Other precalculations
+ PW = m_pVolumeGeometry->getPixelLengthX();
+ PH = m_pVolumeGeometry->getPixelLengthY();
+ DW = m_pProjectionGeometry->getDetectorWidth();
+ inv_PW = 1.0f / PW;
+ inv_PH = 1.0f / PH;
+
+ // [-45?,45?] and [135?,225?]
+ if (theta < PIdiv4) {
+
+ // Precalculate kernel limits
+ S = -0.5f * fabs_sin_theta * fabs_inv_cos_theta;
+ T = -S;
+ U = 1.0f + S;
+ V = 1.0f - S;
+ inv_4T = 0.25f / T;
+
+ updateX = sin_theta * inv_cos_theta;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector);
+ if (switch_t) t = -t;
+
+ // calculate left strip extremes (volume coordinates)
+ PL = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0) - DW*0.5f) * inv_cos_theta;
+ PLimitL = PL - 0.5f * fabs_sin_theta * fabs_inv_cos_theta * PH;
+ PLimitR = PLimitL + DW * inv_cos_theta + PH * fabs_sin_theta * fabs_inv_cos_theta;
+
+ // calculate strip extremes (pixel coordinates)
+ XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
+ xR = xL + (DW * inv_cos_theta) * inv_PW;
+
+ // for each row
+ for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX;
+ XLimitR += updateX;
+ xL += updateX;
+ xR += updateX;
+
+ // for each affected col
+ for (col = x1L; col <= x1R; ++col) {
+
+ if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V) res = 1.0f;
+ else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T;
+ else if (x2R >= T) res = x2R;
+ else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S) {} // - 0.0f
+ else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T;
+ else if (x2L <= U) res -= x2L;
+ else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end col loop
+
+ } // end row loop
+
+ // [45?,135?] and [225?,315?]
+ // horizontaly
+ } else {
+
+ // Precalculate kernel limits
+ S = -0.5f * fabs_cos_theta * fabs_inv_sin_theta;
+ T = -S;
+ U = 1.0f + S;
+ V = 1.0f - S;
+ inv_4T = 0.25f / T;
+
+ updateX = cos_theta * inv_sin_theta;
+
+ // get t
+ t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector);
+ if (switch_t) t = -t;
+
+ // calculate left strip extremes (volume coordinates)
+ PL = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0) + DW*0.5f) * inv_sin_theta;
+ PLimitL = PL + 0.5f * fabs_cos_theta * fabs_inv_sin_theta * PW;
+ PLimitR = PLimitL - DW * inv_sin_theta - PH * fabs_cos_theta * fabs_inv_sin_theta;
+
+ // calculate strip extremes (pixel coordinates)
+ XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH;
+ XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH;
+ xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH;
+ xR = xL + (DW * fabs_inv_sin_theta) * inv_PH;
+
+ // for each col
+ for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
+
+ // get strip extremes in column indices
+ x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
+ x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
+
+ // get coords w.r.t leftmost column hit by strip
+ x2L = xL - x1L;
+ x2R = xR - x1L;
+
+ // update strip extremes for the next row
+ XLimitL += updateX;
+ XLimitR += updateX;
+ xL += updateX;
+ xR += updateX;
+
+ // for each affected col
+ for (row = x1L; row <= x1R; ++row) {
+
+ if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
+
+ // POLICY: PIXEL PRIOR
+ if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // right
+ if (x2R >= V) res = 1.0f;
+ else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T;
+ else if (x2R >= T) res = x2R;
+ else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // left
+ if (x2L <= S) {} // - 0.0f
+ else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T;
+ else if (x2L <= U) res -= x2L;
+ else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T;
+ else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+
+ x2L -= 1.0f;
+ x2R -= 1.0f;
+
+ } // end row loop
+
+ } // end col loop
+
+ } // end theta switch
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+}
diff --git a/include/astra/ParallelProjectionGeometry2D.h b/include/astra/ParallelProjectionGeometry2D.h
new file mode 100644
index 0000000..c91fb4d
--- /dev/null
+++ b/include/astra/ParallelProjectionGeometry2D.h
@@ -0,0 +1,153 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PARALLELPROJECTIONGEOMETRY2D
+#define _INC_ASTRA_PARALLELPROJECTIONGEOMETRY2D
+
+#include "ProjectionGeometry2D.h"
+
+namespace astra
+{
+
+/**
+ * This class defines a 2D parallel beam projection geometry.
+ *
+ * <img src="../images/par_proj_geom.svg" width="600"/>
+ * This geometry is defined by a number of parameters:
+ * - The number of detectors (DetCount).
+ * The distance between the first detector and the projection of the origin \f$O\f$ is equal to
+ * the distance between the last detector and the projection of \f$O\f$.
+ * - The width of each detector (detector width). All detectors are equidistant.
+ * - A list of projection angles (\f$\theta\f$), measured w.r.t. the y-axis of the volume. In Radians. Should lie in the interval \f$[-\frac{\pi}{4},\frac{7\pi}{4}]\f$.
+ *
+ * This class provides functionality to convert between detector index and detector offset \f$t\f$.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{DetectorCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorWidth, float, Width of each detector.}
+ * \astra_xml_item{ProjectionAngles, vector of float, projection angles w.r.t. the y-axis of the volume in radians.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * proj_geom = astra_struct('parallel');\n
+ * proj_geom.DetectorCount = 512;\n
+ * proj_geom.DetectorWidth = 1.0;\n
+ * proj_geom.ProjectionAngles = linspace(0\,pi\,100);\n
+ * }
+ */
+class _AstraExport CParallelProjectionGeometry2D : public CProjectionGeometry2D
+{
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ *
+ */
+ CParallelProjectionGeometry2D();
+
+ /** Constructor. Create an instance of the CParallelProjectionGeometry2D class.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ CParallelProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsets = 0);
+
+ /** Copy constructor.
+ */
+ CParallelProjectionGeometry2D(const CParallelProjectionGeometry2D& _projGeom);
+
+ /** Destructor.
+ */
+ ~CParallelProjectionGeometry2D();
+
+ /** Assignment operator.
+ */
+ CParallelProjectionGeometry2D& operator=(const CParallelProjectionGeometry2D& _other);
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialization. Initializes an instance of the CProjectionGeometry2D class. If the object has been
+ * initialized before, the object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ bool initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsets = 0);
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry2D* clone();
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(CProjectionGeometry2D*) const;
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if _sType == "parallel".
+ */
+ virtual bool isOfType(const std::string& _sType);
+
+ /**
+ * Returns a vector describing the direction of a ray belonging to a certain detector,
+ * the direction is the same for all detectors in one projection
+ *
+ * @param _iProjectionIndex index of projection
+ * @param _iProjectionIndex index of detector
+ *
+ * @return a unit vector describing the direction
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex = 0);
+};
+
+} // namespace astra
+
+#endif /* _INC_ASTRA_PARALLELPROJECTIONGEOMETRY2D */
diff --git a/include/astra/ParallelProjectionGeometry3D.h b/include/astra/ParallelProjectionGeometry3D.h
new file mode 100644
index 0000000..85d0687
--- /dev/null
+++ b/include/astra/ParallelProjectionGeometry3D.h
@@ -0,0 +1,165 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PARALLELPROJECTIONGEOMETRY3D
+#define _INC_ASTRA_PARALLELPROJECTIONGEOMETRY3D
+
+#include "ProjectionGeometry3D.h"
+#include "ParallelProjectionGeometry2D.h"
+
+namespace astra
+{
+
+/**
+ * This class defines a 3D parallel beam projection geometry.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorWidth, float, Width of each detector.}
+ * \astra_xml_item{DetectorHeight, float, Width of each detector.}
+ * \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * proj_geom = astra_struct('parallel');\n
+ * proj_geom.DetectorRowCount = 512;\n
+ * proj_geom.DetectorColCount = 512;\n
+ * proj_geom.DetectorWidth = 1.0;\n
+ * proj_geom.DetectorHeight = 1.0;\n
+ * proj_geom.ProjectionAngles = linspace(0,pi,100);\n
+ * }
+ */
+class _AstraExport CParallelProjectionGeometry3D : public CProjectionGeometry3D
+{
+protected:
+
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the initialize() methods before the object can be used. Any use before calling initialize()
+ * is not allowed, except calling the member function isInitialized().
+ */
+ CParallelProjectionGeometry3D();
+
+ /** Constructor. Create an instance of the CParallelProjectionGeometry3D class.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _fDetectorHeight Height of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles
+ * are represented in radians and lie in the [0,2pi[ interval.
+ */
+ CParallelProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorWidth,
+ float32 _fDetectorHeight,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsetsX = NULL,
+ const float32* _pfExtraDetectorOffsetsY = NULL);
+
+ /** Copy constructor.
+ */
+ CParallelProjectionGeometry3D(const CParallelProjectionGeometry3D& _projGeom);
+
+ /** Destructor.
+ */
+ ~CParallelProjectionGeometry3D();
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the geometry. If the object has been initialized before, the object is reinitialized
+ * and memory is freed and reallocated if necessary.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _fDetectorHeight Height of a detector cell, in unit lengths. All detector cells are assumed to have equal height.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles
+ * are represented in radians and lie in the [0,2pi[ interval.
+ */
+ bool initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorWidth,
+ float32 _fDetectorHeight,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsetsX = NULL,
+ const float32* _pfExtraDetectorOffsetsY = NULL);
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry3D* clone() const;
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(const CProjectionGeometry3D*) const;
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if _sType == "parallel".
+ */
+ virtual bool isOfType(const std::string& _sType) const;
+
+ /** Turn this object into an XML object.
+ *
+ * @param _sNode The XML object to fill.
+ */
+ virtual void toXML(XMLNode* _sNode) const;
+
+ /**
+ * Returns a vector giving the projection direction for a projection and detector index
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const;
+
+ /**
+ * Creates (= allocates) a 2D projection geometry used when projecting one slice using a 2D projector
+ *
+ * @return the 2D geometry, this pointer needs to be delete-ed after use.
+ */
+ CParallelProjectionGeometry2D * createProjectionGeometry2D() const;
+
+};
+
+} // namespace astra
+
+#endif /* _INC_ASTRA_PARALLELPROJECTIONGEOMETRY3D */
diff --git a/include/astra/ParallelVecProjectionGeometry3D.h b/include/astra/ParallelVecProjectionGeometry3D.h
new file mode 100644
index 0000000..0b4a766
--- /dev/null
+++ b/include/astra/ParallelVecProjectionGeometry3D.h
@@ -0,0 +1,157 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PARALLELVECPROJECTIONGEOMETRY3D
+#define _INC_ASTRA_PARALLELVECPROJECTIONGEOMETRY3D
+
+#include "ProjectionGeometry3D.h"
+#include "../cuda/3d/dims3d.h"
+
+namespace astra
+{
+
+/**
+ * This class defines a 3D parallel beam projection geometry.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * proj_geom = astra_struct('parallel3d_vec');\n
+ * proj_geom.DetectorRowCount = 512;\n
+ * proj_geom.DetectorColCount = 512;\n
+ * proj_geom.Vectors = V;\n
+ * }
+ *
+ * \par Vectors
+ * Vectors is a matrix containing the actual geometry. Each row corresponds
+ * to a single projection, and consists of:
+ * ( rayX, rayY, rayZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ )
+ * ray: the ray direction
+ * d : the corner of the detector
+ * u : the vector from detector pixel (0,0) to (0,1)
+ * v : the vector from detector pixel (0,0) to (1,0)
+ */
+class _AstraExport CParallelVecProjectionGeometry3D : public CProjectionGeometry3D
+{
+protected:
+
+ SPar3DProjection *m_pProjectionAngles;
+
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the initialize() methods before the object can be used. Any use before calling initialize()
+ * is not allowed, except calling the member function isInitialized().
+ */
+ CParallelVecProjectionGeometry3D();
+
+ /** Constructor. Create an instance of the CParallelProjectionGeometry3D class.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _pProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ CParallelVecProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ const SPar3DProjection* _pProjectionAngles);
+
+ /** Copy constructor.
+ */
+ CParallelVecProjectionGeometry3D(const CParallelVecProjectionGeometry3D& _projGeom);
+
+ /** Destructor.
+ */
+ ~CParallelVecProjectionGeometry3D();
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the geometry. If the object has been initialized before, the object is reinitialized
+ * and memory is freed and reallocated if necessary.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _pProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ bool initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ const SPar3DProjection* _pProjectionAngles);
+
+
+ virtual bool _check();
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry3D* clone() const;
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(const CProjectionGeometry3D*) const;
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if _sType == "parallel3d_vec".
+ */
+ virtual bool isOfType(const std::string& _sType) const;
+
+ /** Turn this object into an XML object.
+ *
+ * @param _sNode The XML object to fill.
+ */
+ virtual void toXML(XMLNode* _sNode) const;
+
+ /**
+ * Returns a vector giving the projection direction for a projection and detector index
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const;
+
+
+ const SPar3DProjection* getProjectionVectors() const { return m_pProjectionAngles; }
+
+
+};
+
+} // namespace astra
+
+#endif /* _INC_ASTRA_PARALLELVECPROJECTIONGEOMETRY3D */
diff --git a/include/astra/PlatformDepSystemCode.h b/include/astra/PlatformDepSystemCode.h
new file mode 100644
index 0000000..1e254b4
--- /dev/null
+++ b/include/astra/PlatformDepSystemCode.h
@@ -0,0 +1,83 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef PLATFORMDEPSYSTEMCODE_H
+#define PLATFORMDEPSYSTEMCODE_H
+
+#include <cstdio>
+
+#ifndef _WIN32
+#include <stdint.h>
+#endif
+
+namespace astra
+{
+
+#ifdef _WIN32
+ typedef __int64 int64;
+#else
+ typedef int64_t int64;
+#endif
+
+class CPlatformDepSystemCode
+{
+public:
+
+ /**
+ * Clock with resolution of 1 ms. Windows implementation will return number of ms since system start,
+ * but this is not a requirement for the implementation. Just as long as the subtraction of two acquired
+ * values will result in a time interval in ms.
+ *
+ * @return a value that increases with 1 every ms
+ */
+ static unsigned long getMSCount();
+
+ /**
+ * fseek variant that works with 64 bit ints.
+ *
+ * @param _pStream file handler of file in which needs to be seek-ed
+ * @param _iOffset 64 bit int telling the new offset in the file
+ * @param _iOrigin typical fseek directive telling how _iOffset needs to be interpreted (SEEK_SET, ...)
+ *
+ * @return 0 if successful
+ */
+ static int fseek64(FILE * _pStream, astra::int64 _iOffset, int _iOrigin);
+
+ /**
+ * 64-bit ftell variant
+ *
+ * @param _pStream file handle
+ *
+ * @return the position in the file
+ */
+ static astra::int64 ftell64(FILE * _pStream);
+};
+
+}
+
+#endif /* PLATFORMDEPSYSTEMCODE_H */
diff --git a/include/astra/ProjectionGeometry2D.h b/include/astra/ProjectionGeometry2D.h
new file mode 100644
index 0000000..bcaee7a
--- /dev/null
+++ b/include/astra/ProjectionGeometry2D.h
@@ -0,0 +1,373 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PROJECTIONGEOMETRY2D
+#define _INC_ASTRA_PROJECTIONGEOMETRY2D
+
+#include "Globals.h"
+#include "Config.h"
+#include "Vector3D.h"
+
+#include <string>
+#include <cmath>
+#include <vector>
+
+namespace astra
+{
+
+/**
+ * This abstract base class defines the projection geometry.
+ * It has a number of data fields, such as width of detector
+ * pixels, projection angles, number of detector pixels and object offsets
+ * for every projection angle.
+ */
+class _AstraExport CProjectionGeometry2D
+{
+
+protected:
+
+ bool m_bInitialized; ///< Has the object been intialized?
+
+ /** Number of projection angles
+ */
+ int m_iProjectionAngleCount;
+
+ /** Number of detectors, i.e., the number of detector measurements for each projection angle.
+ */
+ int m_iDetectorCount;
+
+ /** Width of a detector pixel, i.e., the distance between projected rays (or width of projected strips).
+ */
+ float32 m_fDetectorWidth;
+
+ /** An array of m_iProjectionAngleCount elements containing an extra detector offset for each projection.
+ */
+ float32* m_pfExtraDetectorOffset;
+
+ /** Dynamically allocated array of projection angles. All angles are represented in radians and lie in
+ * the [0,2pi[ interval.
+ */
+ float32* m_pfProjectionAngles;
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not
+ * allowed, except calling the member function isInitialized().
+ *
+ */
+ CProjectionGeometry2D();
+
+ /** Constructor. Create an instance of the CProjectionGeometry2D class.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ * All angles are represented in radians.
+ */
+ CProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsets = 0);
+
+ /** Copy constructor.
+ */
+ CProjectionGeometry2D(const CProjectionGeometry2D& _projGeom);
+
+ /** Check variable values.
+ */
+ bool _check();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ * Should only be used by constructors. Otherwise use the clear() function.
+ */
+ void _clear();
+
+ /** Initialization. Initializes an instance of the CProjectionGeometry2D class. If the object has been
+ * initialized before, the object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _fDetectorWidth Width of a detector cell, in unit lengths. All detector cells are assumed to have equal width.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array.
+ */
+ bool _initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsets = 0);
+
+public:
+
+ /** Destructor
+ */
+ virtual ~CProjectionGeometry2D();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ */
+ virtual void clear();
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry2D* clone() = 0;
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Get the initialization state of the object.
+ *
+ * @return true iff the object has been initialized
+ */
+ bool isInitialized() const;
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(CProjectionGeometry2D*) const = 0;
+
+ /** Get the number of projection angles.
+ *
+ * @return Number of projection angles
+ */
+ int getProjectionAngleCount() const;
+
+ /** Get the number of detectors.
+ *
+ * @return Number of detectors, i.e., the number of detector measurements for each projection angle.
+ */
+ int getDetectorCount() const;
+
+ /** Get the width of a detector.
+ *
+ * @return Width of a detector, in unit lengths
+ */
+ float32 getDetectorWidth() const;
+
+ /** Get a projection angle, given by its index. The angle is represented in Radians.
+ *
+ * @return Projection angle with index _iProjectionIndex
+ */
+ float32 getProjectionAngle(int _iProjectionIndex) const;
+
+ /** Returns a buffer containing all projection angles. The element count of the buffer is equal
+ * to the number given by getProjectionAngleCount.
+ *
+ * The angles are in radians.
+ *
+ * @return Pointer to buffer containing the angles.
+ */
+ const float32* getProjectionAngles() const;
+
+ /** Get a projection angle, given by its index. The angle is represented in degrees.
+ *
+ * @return Projection angle with index _iProjectionIndex
+ */
+ float32 getProjectionAngleDegrees(int _iProjectionIndex) const;
+
+ float32 getExtraDetectorOffset(int iAngle) const;
+ const float32* getExtraDetectorOffset() const { return m_pfExtraDetectorOffset; }
+
+ /** Get the index coordinate of a point on a detector array.
+ *
+ * @param _fOffset distance between the center of the detector array and a certain point
+ * @return the location of the point in index coordinates (still float, not rounded)
+ */
+ virtual float32 detectorOffsetToIndexFloat(float32 _fOffset) const;
+
+ /** Get the index coordinate of a point on a detector array.
+ *
+ * @param _fOffset distance between the center of the detector array and a certain point
+ * @return the index of the detector that is hit, -1 if detector array isn't hit.
+ */
+ virtual int detectorOffsetToIndex(float32 _fOffset) const;
+
+ /** Get the offset of a detector based on its index coordinate.
+ *
+ * @param _iIndex the index of the detector.
+ * @return the offset from the center of the detector array.
+ */
+ virtual float32 indexToDetectorOffset(int _iIndex) const;
+
+ /** Get the angle and detector index of a sinogram pixel
+ *
+ * @param _iIndex the index of the detector pixel in the sinogram.
+ * @param _iAngleIndex output: index of angle
+ * @param _iDetectorIndex output: index of detector
+ */
+ virtual void indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const;
+
+ /** Get the value for t and theta, based upon the row and column index.
+ *
+ * @param _iRow row index
+ * @param _iColumn column index
+ * @param _fT output: value of t
+ * @param _fTheta output: value of theta, always lies within the [0,pi[ interval.
+ */
+ virtual void getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const;
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if the type of geometry defined in this class is the one specified in _sType.
+ */
+ virtual bool isOfType(const std::string& _sType) = 0;
+
+ /**
+ * Returns a vector describing the direction of a ray belonging to a certain detector
+ *
+ * @param _iProjectionIndex index of projection
+ * @param _iProjectionIndex index of detector
+ *
+ * @return a unit vector describing the direction
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) = 0;
+
+
+ //< For Config unused argument checking
+ ConfigCheckData* configCheckData;
+ friend class ConfigStackCheck<CProjectionGeometry2D>;
+};
+
+
+
+//----------------------------------------------------------------------------------------
+// Inline member functions
+//----------------------------------------------------------------------------------------
+
+
+inline float32 CProjectionGeometry2D::getExtraDetectorOffset(int _iAngle) const
+{
+ return m_pfExtraDetectorOffset ? m_pfExtraDetectorOffset[_iAngle] : 0.0f;
+}
+
+
+// Get the initialization state.
+inline bool CProjectionGeometry2D::isInitialized() const
+{
+ return m_bInitialized;
+}
+
+
+// Get the number of detectors.
+inline int CProjectionGeometry2D::getDetectorCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iDetectorCount;
+}
+
+// Get the width of a single detector (in unit lengths).
+inline float32 CProjectionGeometry2D::getDetectorWidth() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fDetectorWidth;
+}
+
+// Get the number of projection angles.
+inline int CProjectionGeometry2D::getProjectionAngleCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iProjectionAngleCount;
+}
+
+// Get pointer to buffer used to store projection angles.
+inline const float32* CProjectionGeometry2D::getProjectionAngles() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_pfProjectionAngles;
+}
+
+// Get a projection angle, represented in Radians.
+inline float32 CProjectionGeometry2D::getProjectionAngle(int _iProjectionIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iProjectionIndex >= 0);
+ ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount);
+
+ return m_pfProjectionAngles[_iProjectionIndex];
+}
+
+// Get a projection angle, represented in degrees.
+inline float32 CProjectionGeometry2D::getProjectionAngleDegrees(int _iProjectionIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iProjectionIndex >= 0);
+ ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount);
+
+ return (m_pfProjectionAngles[_iProjectionIndex] * 180.0f / PI32);
+}
+
+// Get T and Theta
+inline void CProjectionGeometry2D::getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ _fT = indexToDetectorOffset(_iColumn);
+ _fTheta = getProjectionAngle(_iRow);
+ if (PI <= _fTheta) {
+ _fTheta -= PI;
+ _fT = -_fT;
+ }
+}
+
+// detector offset -> detector index
+inline int CProjectionGeometry2D::detectorOffsetToIndex(float32 _fOffset) const
+{
+ int res = (int)(detectorOffsetToIndexFloat(_fOffset) + 0.5f);
+ return (res > 0 && res <= m_iDetectorCount) ? res : -1;
+}
+
+// detector offset -> detector index (float)
+inline float32 CProjectionGeometry2D::detectorOffsetToIndexFloat(float32 _fOffset) const
+{
+ return (_fOffset / m_fDetectorWidth) + ((m_iDetectorCount-1.0f) * 0.5f);
+}
+
+// detector index -> detector offset
+inline float32 CProjectionGeometry2D::indexToDetectorOffset(int _iIndex) const
+{
+ return (_iIndex - (m_iDetectorCount-1.0f) * 0.5f) * m_fDetectorWidth;
+}
+
+// sinogram index -> angle and detecor index
+inline void CProjectionGeometry2D::indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const
+{
+ _iAngleIndex = _iIndex / m_iDetectorCount;
+ _iDetectorIndex = _iIndex % m_iDetectorCount;
+}
+
+} // end namespace astra
+
+#endif /* _INC_ASTRA_PROJECTIONGEOMETRY2D */
diff --git a/include/astra/ProjectionGeometry3D.h b/include/astra/ProjectionGeometry3D.h
new file mode 100644
index 0000000..0deffa6
--- /dev/null
+++ b/include/astra/ProjectionGeometry3D.h
@@ -0,0 +1,589 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PROJECTIONGEOMETRY3D
+#define _INC_ASTRA_PROJECTIONGEOMETRY3D
+
+#include "Globals.h"
+#include "Config.h"
+#include "Vector3D.h"
+
+#include <string>
+#include <cmath>
+#include <vector>
+
+namespace astra
+{
+
+class XMLNode;
+
+/**
+ * This class defines the interface for each 3D projection geometry.
+ * It has a number of data fields, such as width and height of detector
+ * pixels, projection angles and number of rows and columns of detector pixels.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{DetectorRowCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorColCount, int, Number of detectors for each projection.}
+ * \astra_xml_item{DetectorWidth, float, Width of each detector.}
+ * \astra_xml_item{DetectorHeight, float, Width of each detector.}
+ * \astra_xml_item{ProjectionAngles, vector of float, projection angles in radians.}
+ */
+class _AstraExport CProjectionGeometry3D
+{
+
+protected:
+
+ /** Has the object been intialized with acceptable values?
+ */
+ bool m_bInitialized;
+
+ /** Number of projection angles.
+ */
+ int m_iProjectionAngleCount;
+
+ /** Number of rows of detectors.
+ */
+ int m_iDetectorRowCount;
+
+ /** Number of columns of detectors.
+ */
+ int m_iDetectorColCount;
+
+ /** Total number of detectors.
+ */
+ int m_iDetectorTotCount;
+
+ /** The x-distance between projected rays on the detector plate (or width of projected strips).
+ */
+ float32 m_fDetectorSpacingX;
+
+ /** The y-distance between projected rays on the detector plate (or height of projected strips).
+ */
+ float32 m_fDetectorSpacingY;
+
+ /** Dynamically allocated array of projection angles. All angles are represented in radians and lie in
+ * the [0,2pi[ interval.
+ */
+ float32* m_pfProjectionAngles;
+
+ /** Dynamically allocated array of vectors that represents the amount by which an image has been shifted after
+ * projection. Each projection image has a 2 shifts associated with it, one x-translation and y-translation
+ */
+ float32* m_pfExtraDetectorOffsetsX;
+ float32* m_pfExtraDetectorOffsetsY;
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the initialize() methods before the object can be used. Any use before calling initialize()
+ * is not allowed, except calling the member function isInitialized().
+ *
+ */
+ CProjectionGeometry3D();
+
+ /** Constructor. Create an instance of the CProjectionGeometry3D class.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _fDetectorSpacingX Spacing between the detector points on the X-axis, in unit lengths. Assumed to be constant throughout the entire detector plate.
+ * @param _fDetectorSpacingY Spacing between the detector points on the Y-axis, in unit lengths. Assumed to be constant throughout the entire detector plate.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles
+ * are represented in radians and lie in the [0,2pi[ interval.
+ */
+ CProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorSpacingX,
+ float32 _fDetectorSpacingY,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsetsX = NULL,
+ const float32* _pfExtraDetectorOffsetsY = NULL);
+
+ /** Copy constructor.
+ */
+ CProjectionGeometry3D(const CProjectionGeometry3D& _projGeom);
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - number of rows and columns is larger than zero
+ * - detector spacing is larger than zero
+ * - number of angles is larger than zero
+ * - (autofix) each angle lies in [0,2pi[
+ */
+ bool _check();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ * Should only be used by constructors. Otherwise use the clear() function.
+ */
+ void _clear();
+
+ /** Initialize the geometry. If the object has been initialized before, the object is reinitialized
+ * and memory is freed and reallocated if necessary.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorRowCount Number of rows of detectors.
+ * @param _iDetectorColCount Number of columns detectors.
+ * @param _fDetectorSpacingX Spacing between the detector points on the X-axis, in unit lengths. Assumed to be constant throughout the entire detector plate.
+ * @param _fDetectorSpacingY Spacing between the detector points on the Y-axis, in unit lengths. Assumed to be constant throughout the entire detector plate.
+ * @param _pfProjectionAngles Pointer to an array of projection angles. The angles will be copied from this array. All angles
+ * are represented in radians and lie in the [0,2pi[ interval.
+ */
+ bool _initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorSpacingX,
+ float32 _fDetectorSpacingY,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsetsX = NULL,
+ const float32* _pfExtraDetectorOffsetsY = NULL);
+
+public:
+
+ /** Destructor
+ */
+ virtual ~CProjectionGeometry3D();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ */
+ virtual void clear();
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry3D* clone() const = 0;
+
+ /** Initialize the geometry with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Get the initialization state of the object.
+ *
+ * @return true iff the object has been initialized
+ */
+ bool isInitialized() const;
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(const CProjectionGeometry3D *) const = 0;
+
+ /** Get the number of projections.
+ *
+ * @return Number of projections
+ */
+ int getProjectionCount() const;
+
+ /** Get the number of rows of detectors.
+ *
+ * @return Number of rows of detectors.
+ */
+ int getDetectorRowCount() const;
+
+ /** Get the number of columns of detectors.
+ *
+ * @return Number of columns of detectors.
+ */
+ int getDetectorColCount() const;
+
+ /** Get the total number of detectors.
+ *
+ * @return Total number of detectors.
+ */
+ int getDetectorTotCount() const;
+
+ /** Get the width of a detector.
+ *
+ * @return Width of a detector, in unit lengths
+ */
+ float32 getDetectorSpacingX() const;
+
+ /** Get the height of a detector.
+ *
+ * @return Height of a detector, in unit lengths
+ */
+ float32 getDetectorSpacingY() const;
+
+ /** Get a projection angle, given by its index. The angle is represented in Radians.
+ *
+ * @return Projection angle with index _iProjectionIndex
+ */
+ float32 getProjectionAngle(int _iProjectionIndex) const;
+
+ /** Get a projection angle, given by its index. The angle is represented in degrees.
+ *
+ * @return Projection angle with index _iProjectionIndex
+ */
+// float32 getProjectionAngleDegrees(int _iProjectionIndex) const;
+
+ /** Returns a buffer containing all projection angles. The element count of the buffer is equal
+ * to the number given by getProjectionAngleCount.
+ *
+ * The angles are in radians.
+ *
+ * @return Pointer to buffer containing the angles.
+ */
+ const float32* getProjectionAngles() const;
+
+ const float32* getExtraDetectorOffsetsX() const;
+
+ const float32* getExtraDetectorOffsetsY() const;
+
+ float32 getExtraDetectorOffsetX(int _iProjectionIndex) const;
+
+ float32 getExtraDetectorOffsetY(int _iProjectionIndex) const;
+
+ AstraError setExtraDetectorOffsetsX(float32* _pfExtraDetectorOffsetsX);
+
+ AstraError setExtraDetectorOffsetsY(float32* _pfExtraDetectorOffsetsY);
+
+ /** Get the column index coordinate of a point on a detector array.
+ *
+ * @param _fOffsetX Distance between the center of the detector array and a certain point (both on the X-axis).
+ * @return The location of the point in index X-coordinates (still float, not rounded)
+ */
+ virtual float32 detectorOffsetXToColIndexFloat(float32 _fOffsetX) const;
+
+ /** Get the row index coordinate of a point on a detector array.
+ *
+ * @param _fOffsetY Distance between the center of the detector array and a certain point (both on the Y-axis).
+ * @return The location of the point in index Y-coordinates (still float, not rounded)
+ */
+ virtual float32 detectorOffsetYToRowIndexFloat(float32 _fOffsetY) const;
+
+ /** Get the offset of a detector on the X-axis based on its index coordinate.
+ *
+ * @param _iIndex the index of the detector.
+ * @return the offset from the center of the detector array on the X-axis.
+ */
+ virtual float32 indexToDetectorOffsetX(int _iIndex) const;
+
+ /** Get the offset of a detector on the Y-axis based on its index coordinate.
+ *
+ * @param _iIndex the index of the detector.
+ * @return the offset from the center of the detector array on the Y-axis.
+ */
+ virtual float32 indexToDetectorOffsetY(int _iIndex) const;
+
+ /** Get the offset of a detector on the X-axis based on its column index coordinate.
+ *
+ * @param _iIndex the index of the detector.
+ * @return the offset from the center of the detector array on the X-axis.
+ */
+ virtual float32 colIndexToDetectorOffsetX(int _iIndex) const;
+
+ /** Get the offset of a detector on the Y-axis based on its row index coordinate.
+ *
+ * @param _iIndex the index of the detector.
+ * @return the offset from the center of the detector array on the Y-axis.
+ */
+ virtual float32 rowIndexToDetectorOffsetY(int _iIndex) const;
+
+ /** Get the row and column index of a detector based on its index.
+ *
+ * @param _iDetectorIndex in: the index of the detector.
+ * @param _iDetectorRow out: the row index of the detector.
+ * @param _iDetectorCol out: the column index of the detector.
+ */
+ virtual void detectorIndexToRowCol(int _iDetectorIndex, int& _iDetectorRow, int& _iDetectorCol) const;
+
+ /** Get the angle and detector index of a detector
+ *
+ * @param _iIndex the index of the detector.
+ * @param _iAngleIndex output: index of angle
+ * @param _iDetectorIndex output: index of dectecor
+ */
+ virtual void indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const;
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if the type of geometry defined in this class is the one specified in _sType.
+ */
+ virtual bool isOfType(const std::string& _sType) const = 0;
+
+ /** Turn this object into an XML object.
+ *
+ * @param _sNode The XML object to fill.
+ */
+ virtual void toXML(XMLNode* _sNode) const = 0;
+
+ /**
+ * Returns a vector giving the projection direction for a projection and detector index
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const = 0;
+
+
+ //< For Config unused argument checking
+ ConfigCheckData* configCheckData;
+ friend class ConfigStackCheck<CProjectionGeometry3D>;
+};
+
+
+
+//----------------------------------------------------------------------------------------
+// Inline member functions
+//----------------------------------------------------------------------------------------
+// Get the initialization state.
+inline bool CProjectionGeometry3D::isInitialized() const
+{
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of detectors.
+inline int CProjectionGeometry3D::getDetectorRowCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iDetectorRowCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of detectors.
+inline int CProjectionGeometry3D::getDetectorColCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iDetectorColCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of detectors.
+inline int CProjectionGeometry3D::getDetectorTotCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iDetectorTotCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the width of a single detector (in unit lengths).
+inline float32 CProjectionGeometry3D::getDetectorSpacingX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fDetectorSpacingX;
+}
+//----------------------------------------------------------------------------------------
+// Get the width of a single detector (in unit lengths).
+inline float32 CProjectionGeometry3D::getDetectorSpacingY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fDetectorSpacingY;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of projection angles.
+inline int CProjectionGeometry3D::getProjectionCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iProjectionAngleCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Get a projection angle, represented in Radians.
+inline float32 CProjectionGeometry3D::getProjectionAngle(int _iProjectionIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iProjectionIndex >= 0);
+ ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount);
+
+ return m_pfProjectionAngles[_iProjectionIndex];
+}
+
+/*
+//----------------------------------------------------------------------------------------
+// Get a projection angle, represented in degrees.
+inline float32 CProjectionGeometry3D::getProjectionAngleDegrees(int _iProjectionIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iProjectionIndex >= 0);
+ ASTRA_ASSERT(_iProjectionIndex < m_iProjectionAngleCount);
+
+ return (m_pfProjectionAngles[_iProjectionIndex] * 180.0f / PI32);
+}
+*/
+
+
+//----------------------------------------------------------------------------------------
+// Get pointer to buffer used to store projection angles.
+inline const float32* CProjectionGeometry3D::getProjectionAngles() const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+
+ return m_pfProjectionAngles;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Get pointer to buffer used to store x-translations of the projection images.
+inline const float32* CProjectionGeometry3D::getExtraDetectorOffsetsX() const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+
+ return m_pfExtraDetectorOffsetsX;
+}
+
+//----------------------------------------------------------------------------------------
+// Get pointer to buffer used to store y-translations of the projection images.
+inline const float32* CProjectionGeometry3D::getExtraDetectorOffsetsY() const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+
+ return m_pfExtraDetectorOffsetsY;
+}
+//----------------------------------------------------------------------------------------
+// Get the x-translation of a specific projection image.
+inline float32 CProjectionGeometry3D::getExtraDetectorOffsetX(int _iProjectionIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+
+ return m_pfExtraDetectorOffsetsX[_iProjectionIndex];
+}
+
+//----------------------------------------------------------------------------------------
+// Get the y-translation of a specific projection image.
+inline float32 CProjectionGeometry3D::getExtraDetectorOffsetY(int _iProjectionIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+
+ return m_pfExtraDetectorOffsetsX[_iProjectionIndex];
+}
+//----------------------------------------------------------------------------------------
+// detector offset X -> detector column index (float)
+inline float32 CProjectionGeometry3D::detectorOffsetXToColIndexFloat(float32 _fOffsetX) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+
+ return (_fOffsetX / m_fDetectorSpacingX) + ((m_iDetectorColCount-1.0f) / 2.0f);
+}
+
+//----------------------------------------------------------------------------------------
+// detector offset Y -> detector row index (float)
+inline float32 CProjectionGeometry3D::detectorOffsetYToRowIndexFloat(float32 _fOffsetY) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+
+ return (_fOffsetY / m_fDetectorSpacingY) + ((m_iDetectorRowCount-1.0f) / 2.0f);
+}
+
+//----------------------------------------------------------------------------------------
+// detector index -> detector offset X
+inline float32 CProjectionGeometry3D::indexToDetectorOffsetX(int _iIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iIndex >= 0);
+ ASTRA_ASSERT(_iIndex < m_iDetectorTotCount);
+
+ _iIndex = _iIndex % m_iDetectorColCount;
+ return (_iIndex - (m_iDetectorColCount-1.0f) / 2.0f) * m_fDetectorSpacingX;
+}
+
+//----------------------------------------------------------------------------------------
+// detector index -> detector offset Y
+inline float32 CProjectionGeometry3D::indexToDetectorOffsetY(int _iIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iIndex >= 0);
+ ASTRA_ASSERT(_iIndex < m_iDetectorTotCount);
+
+ _iIndex = _iIndex / m_iDetectorColCount;
+ return -(_iIndex - (m_iDetectorRowCount-1.0f) / 2.0f) * m_fDetectorSpacingY;
+}
+
+//----------------------------------------------------------------------------------------
+// detector index -> detector offset X
+inline float32 CProjectionGeometry3D::colIndexToDetectorOffsetX(int _iIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iIndex >= 0);
+ ASTRA_ASSERT(_iIndex < m_iDetectorColCount);
+
+ return (_iIndex - (m_iDetectorColCount-1.0f) / 2.0f) * m_fDetectorSpacingX;
+}
+
+//----------------------------------------------------------------------------------------
+// detector index -> detector offset Y
+inline float32 CProjectionGeometry3D::rowIndexToDetectorOffsetY(int _iIndex) const
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iIndex >= 0);
+ ASTRA_ASSERT(_iIndex < m_iDetectorRowCount);
+
+ return (_iIndex - (m_iDetectorRowCount-1.0f) / 2.0f) * m_fDetectorSpacingY;
+}
+
+//----------------------------------------------------------------------------------------
+// detector index -> row index & column index
+inline void CProjectionGeometry3D::detectorIndexToRowCol(int _iDetectorIndex, int& _iDetectorRow, int& _iDetectorCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iDetectorIndex >= 0);
+ ASTRA_ASSERT(_iDetectorIndex < m_iDetectorTotCount);
+
+ _iDetectorRow = _iDetectorIndex / m_iDetectorColCount;
+ _iDetectorCol = _iDetectorIndex % m_iDetectorColCount;
+}
+
+//----------------------------------------------------------------------------------------
+inline void CProjectionGeometry3D::indexToAngleDetectorIndex(int _iIndex, int& _iAngleIndex, int& _iDetectorIndex) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iIndex >= 0);
+ ASTRA_ASSERT(_iIndex < m_iDetectorTotCount * m_iProjectionAngleCount);
+
+// int det_row = _iIndex / (m_iDetectorColCount*m_iProjectionAngleCount);
+// int det_col = _iIndex % m_iDetectorColCount;
+//
+// _iAngleIndex = _iIndex % (m_iDetectorColCount*m_iProjectionAngleCount) / m_iDetectorColCount;
+// _iDetectorIndex = det_row * m_iDetectorColCount + det_col;
+
+ _iAngleIndex = (_iIndex % (m_iDetectorColCount*m_iProjectionAngleCount)) / m_iDetectorColCount;
+ _iDetectorIndex = _iIndex / m_iProjectionAngleCount + (_iIndex % m_iDetectorColCount);
+
+}
+
+//----------------------------------------------------------------------------------------
+
+} // end namespace astra
+
+#endif /* _INC_ASTRA_PROJECTIONGEOMETRY2D */
diff --git a/include/astra/Projector2D.h b/include/astra/Projector2D.h
new file mode 100644
index 0000000..a359aba
--- /dev/null
+++ b/include/astra/Projector2D.h
@@ -0,0 +1,204 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef INC_ASTRA_PROJECTOR2D
+#define INC_ASTRA_PROJECTOR2D
+
+#include <cmath>
+#include <vector>
+
+#include "Globals.h"
+#include "Config.h"
+#include "Float32Data2D.h"
+#include "ParallelProjectionGeometry2D.h"
+#include "ProjectionGeometry2D.h"
+#include "VolumeGeometry2D.h"
+
+namespace astra
+{
+
+class CSparseMatrix;
+
+
+/** This is a base interface class for a two-dimensional projector. Each subclass should at least
+ * implement the core projection functions computeProjectionRayWeights and projectPoint. For
+ * extra efficiency one might also like to overwrite other functions such as computeProjectionRayWeights,
+ * computeRayForwardProj_ART, ...
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ */
+class _AstraExport CProjector2D
+{
+
+protected:
+ CProjectionGeometry2D* m_pProjectionGeometry; ///< Used projection geometry
+ CVolumeGeometry2D* m_pVolumeGeometry; ///< Used volume geometry
+ bool m_bIsInitialized; ///< Has this class been initialized?
+
+ /** Default Constructor.
+ */
+ CProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pVolumeGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ */
+ CProjector2D(CProjectionGeometry2D* _pProjectionGeometry, CVolumeGeometry2D* _pVolumeGeometry);
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ */
+ virtual bool _check();
+
+public:
+
+ /** Destructor.
+ */
+ virtual ~CProjector2D();
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Initialize the projector with a config object.
+ * This function does not set m_bInitialized to true.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Fetch the Projection Geometry of this projector.
+ *
+ * @return Projection Geometry class.
+ */
+ CProjectionGeometry2D* getProjectionGeometry();
+
+ /** Fetch the Volume Geometry of this projector.
+ *
+ * @return Volume Geometry class.
+ */
+ CVolumeGeometry2D* getVolumeGeometry();
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection
+ * @param _iDetectorIndex Index of the detector pixel
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight *_pWeightedPixels,
+ int _iMaxPixelCount,
+ int &_iStoredPixelCount) = 0;
+
+ /** Compute the pixel weights for all rays in a single projection, from the source to a each of the
+ * detector pixels. All pixels and their weights are stored consecutively in the array _pWeightedPixels.
+ * The array starts with all pixels on the first ray, followed by all pixels on the second ray, the third
+ * ray, etc. Note that a pixel may occur in the list more than once, as it can be on several rays.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @param _pfWeightedPixels Pointer to a pre-allocated array, consisting of getProjectionWeightsCount()
+ * elements of type SPixelWeight. On return, this array contains a list of
+ * the index and weight for all pixels on each of the rays. The elements for
+ * every ray start at equal offsets (ray_index * _pWeightedPixels / ray_count).
+ * @param _piRayStoredPixelCount Pointer to a pre-allocated array, containing a single integer for each
+ * ray in the projection. On return, this array contains the number of
+ * pixels on the ray, for each ray in the given projection.
+ */
+ virtual void computeProjectionRayWeights(int _iProjectionIndex,
+ SPixelWeight* _pfWeightedPixels,
+ int* _piRayStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol) = 0;
+
+ /** Returns the number of weights required for storage of all weights of one projection ray.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex) = 0;
+
+ /** Returns the projection as an explicit sparse matrix.
+ * @return a newly allocated CSparseMatrix. Delete afterwards.
+ */
+ CSparseMatrix* getMatrix();
+
+ /** Has the projector been initialized?
+ *
+ * @return initialized successfully
+ */
+ bool isInitialized();
+
+ /** get a description of the class
+ *
+ * @return description string
+ */
+ virtual std::string description() const {return " ";};
+
+ virtual std::string getType() { return " "; }
+
+private:
+ //< For Config unused argument checking
+ ConfigCheckData* configCheckData;
+ friend class ConfigStackCheck<CProjector2D>;
+};
+
+// inline functions
+inline bool CProjector2D::isInitialized() { return m_bIsInitialized; }
+inline CProjectionGeometry2D* CProjector2D::getProjectionGeometry() { return m_pProjectionGeometry; }
+inline CVolumeGeometry2D* CProjector2D::getVolumeGeometry() { return m_pVolumeGeometry; }
+
+
+
+
+
+} // namespace astra
+
+#endif /* INC_ASTRA_PROJECTOR2D */
diff --git a/include/astra/Projector2DImpl.inl b/include/astra/Projector2DImpl.inl
new file mode 100644
index 0000000..97341c8
--- /dev/null
+++ b/include/astra/Projector2DImpl.inl
@@ -0,0 +1,37 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#include "ParallelBeamLinearKernelProjector2D.inl"
+#include "ParallelBeamLineKernelProjector2D.inl"
+#include "ParallelBeamStripKernelProjector2D.inl"
+#include "ParallelBeamBlobKernelProjector2D.inl"
+#include "FanFlatBeamStripKernelProjector2D.inl"
+#include "FanFlatBeamLineKernelProjector2D.inl"
+#include "SparseMatrixProjector2D.inl"
+
diff --git a/include/astra/Projector3D.h b/include/astra/Projector3D.h
new file mode 100644
index 0000000..ec81bc8
--- /dev/null
+++ b/include/astra/Projector3D.h
@@ -0,0 +1,185 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef INC_ASTRA_PROJECTOR3D
+#define INC_ASTRA_PROJECTOR3D
+
+#include <cmath>
+#include <vector>
+
+#include "Globals.h"
+#include "Config.h"
+#include "ProjectionGeometry3D.h"
+#include "VolumeGeometry3D.h"
+
+namespace astra
+{
+
+class CSparseMatrix;
+
+
+/** This is a base interface class for a three-dimensional projector. Each subclass should at least
+ * implement the core projection functions computeProjectionRayWeights and projectPoint.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ */
+class _AstraExport CProjector3D
+{
+
+protected:
+
+ CProjectionGeometry3D* m_pProjectionGeometry; ///< Used projection geometry
+ CVolumeGeometry3D* m_pVolumeGeometry; ///< Used volume geometry
+ bool m_bIsInitialized; ///< Has this class been initialized?
+
+ /** Check variable values.
+ */
+ bool _check();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ * Should only be used by constructors. Otherwise use the clear() function.
+ */
+ void _clear();
+
+public:
+
+ /**
+ * Default Constructor.
+ */
+ CProjector3D();
+
+ /** Destructor, is virtual to show that we are aware subclass destructor is called.
+ */
+ virtual ~CProjector3D();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ */
+ void clear();
+
+ /** Initialize the projector with a config object.
+ * This function does not set m_bInitialized to true.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Fetch the Projection Geometry of this projector.
+ *
+ * @return Projection Geometry class.
+ */
+ CProjectionGeometry3D* getProjectionGeometry();
+
+ /** Fetch the Volume Geometry of this projector.
+ *
+ * @return Volume Geometry class.
+ */
+ CVolumeGeometry3D* getVolumeGeometry();
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection.
+ * @param _iSliceIndex Index of the detector pixel (1-d index).
+ * @param _iDetectorIndex Index of the detector pixel (1-d index).
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex, int _iSliceIndex, int _iDetectorIndex, SPixelWeight* _pWeightedPixels, int _iMaxPixelCount, int& _iStoredPixelCount) = 0;
+
+ /** Compute the pixel weights for all rays in a single projection, from the source to a each of the
+ * detector pixels. All pixels and their weights are stored consecutively in the array _pWeightedPixels.
+ * The array starts with all pixels on the first ray, followed by all pixels on the second ray, the third
+ * ray, etc. Note that a pixel may occur in the list more than once, as it can be on several rays.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @param _pfWeightedPixels Pointer to a pre-allocated array, consisting of getProjectionWeightsCount()
+ * elements of type SPixelWeight. On return, this array contains a list of
+ * the index and weight for all pixels on each of the rays. The elements for
+ * every ray start at equal offsets (ray_index * _pWeightedPixels / ray_count).
+ * @param _piRayStoredPixelCount Pointer to a pre-allocated array, containing a single integer for each
+ * ray in the projection. On return, this array contains the number of
+ * pixels on the ray, for each ray in the given projection.
+ */
+ virtual void computeProjectionRayWeights(int _iProjectionIndex, SPixelWeight* _pfWeightedPixels, int* _piRayStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ //virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol) = 0;
+
+ /** Returns the number of weights required for storage of all weights of one projection.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SWeightedPixel3D elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex) = 0;
+
+ /** Has the projector been initialized?
+ *
+ * @return initialized successfully
+ */
+ bool isInitialized();
+
+ /** get a description of the class
+ *
+ * @return description string
+ */
+ virtual std::string description() const = 0;
+
+ /**
+ * Returns a string describing the projector type
+ */
+ virtual std::string getType() = 0;
+
+private:
+ //< For Config unused argument checking
+ ConfigCheckData* configCheckData;
+ friend class ConfigStackCheck<CProjector3D>;
+
+};
+
+// inline functions
+inline bool CProjector3D::isInitialized() { return m_bIsInitialized; }
+inline CProjectionGeometry3D* CProjector3D::getProjectionGeometry() { return m_pProjectionGeometry; }
+inline CVolumeGeometry3D* CProjector3D::getVolumeGeometry() { return m_pVolumeGeometry; }
+
+
+
+} // namespace astra
+
+#endif /* INC_ASTRA_PROJECTOR3D */
diff --git a/include/astra/ProjectorTypelist.h b/include/astra/ProjectorTypelist.h
new file mode 100644
index 0000000..ddc345a
--- /dev/null
+++ b/include/astra/ProjectorTypelist.h
@@ -0,0 +1,104 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_PROJECTORTYPELIST
+#define _INC_ASTRA_PROJECTORTYPELIST
+
+#include "Projector2D.h"
+#include "TypeList.h"
+
+using namespace astra;
+using namespace astra::typelist;
+
+// Projector2D
+#include "Projector2D.h"
+#include "ParallelBeamLineKernelProjector2D.h"
+#include "ParallelBeamLinearKernelProjector2D.h"
+#include "ParallelBeamBlobKernelProjector2D.h"
+#include "ParallelBeamStripKernelProjector2D.h"
+#include "SparseMatrixProjector2D.h"
+#include "FanFlatBeamLineKernelProjector2D.h"
+#include "FanFlatBeamStripKernelProjector2D.h"
+
+#ifdef ASTRA_CUDA
+#include "CudaProjector2D.h"
+namespace astra{
+
+ typedef TYPELIST_8(
+ CFanFlatBeamLineKernelProjector2D,
+ CFanFlatBeamStripKernelProjector2D,
+ CParallelBeamLinearKernelProjector2D,
+ CParallelBeamLineKernelProjector2D,
+ CParallelBeamBlobKernelProjector2D,
+ CParallelBeamStripKernelProjector2D,
+ CSparseMatrixProjector2D,
+ CCudaProjector2D)
+ Projector2DTypeList;
+}
+
+
+
+#else
+
+namespace astra{
+ typedef TYPELIST_7(
+ CFanFlatBeamLineKernelProjector2D,
+ CFanFlatBeamStripKernelProjector2D,
+ CParallelBeamLinearKernelProjector2D,
+ CParallelBeamLineKernelProjector2D,
+ CParallelBeamBlobKernelProjector2D,
+ CParallelBeamStripKernelProjector2D,
+ CSparseMatrixProjector2D)
+ Projector2DTypeList;
+}
+
+#endif
+
+// Projector3D
+#include "Projector3D.h"
+
+#ifdef ASTRA_CUDA
+
+#include "CudaProjector3D.h"
+namespace astra {
+ typedef TYPELIST_1(
+ CCudaProjector3D
+ )
+ Projector3DTypeList;
+}
+
+#else
+
+namespace astra {
+ typedef TYPELIST_0 Projector3DTypeList;
+}
+
+#endif
+
+
+#endif
diff --git a/include/astra/ReconstructionAlgorithm2D.h b/include/astra/ReconstructionAlgorithm2D.h
new file mode 100644
index 0000000..25a6c0a
--- /dev/null
+++ b/include/astra/ReconstructionAlgorithm2D.h
@@ -0,0 +1,222 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_RECONSTRUCTIONALGORITHM2D
+#define _INC_ASTRA_RECONSTRUCTIONALGORITHM2D
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+
+namespace astra {
+
+/**
+ * This is a base class for the different implementations of 2D reconstruction algorithms.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.}
+ * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.}
+ * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.}
+ * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.}
+ * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.}
+ * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.}
+ */
+class _AstraExport CReconstructionAlgorithm2D : public CAlgorithm {
+
+public:
+
+ /** Default constructor, containing no code.
+ */
+ CReconstructionAlgorithm2D();
+
+ /** Destructor.
+ */
+ virtual ~CReconstructionAlgorithm2D();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Add a min/max constraint to the reconstruction process
+ *
+ * @param _bUseMin True if the algorithm should use a min constraint.
+ * @param _fMinValue Lower value to clip pixel values to.
+ * @param _bUseMax True if the algorithm should use a max constraint.
+ * @param _fMaxValue Upper value to clip pixel values to.
+ */
+ void setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue);
+
+ /** Set a fixed reconstruction mask. A pixel will only be used in the reconstruction if the
+ * corresponding value in the mask is 1.
+ *
+ * @param _pMask Volume Data object containing fixed reconstruction mask
+ * @param _bEnable enable the use of this mask
+ */
+ void setReconstructionMask(CFloat32VolumeData2D* _pMask, bool _bEnable = true);
+
+ /** Set a fixed sinogram mask. A detector value will only be used in the reconstruction if the
+ * corresponding value in the mask is 1.
+ *
+ * @param _pMask Projection Data object containing fixed sinogram mask
+ * @param _bEnable enable the use of this mask
+ */
+ void setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable = true);
+
+ /** Get all information parameters.
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information.
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get projector object
+ *
+ * @return projector
+ */
+ CProjector2D* getProjector() const;
+
+ /** Get sinogram data object
+ *
+ * @return sinogram data object
+ */
+ CFloat32ProjectionData2D* getSinogram() const;
+
+ /** Get Reconstructed Data
+ *
+ * @return reconstruction
+ */
+ CFloat32VolumeData2D* getReconstruction() const;
+
+ /** Get Fixed Reconstruction Mask
+ *
+ * @return fixed reconstruction mask
+ */
+ CFloat32VolumeData2D* getReconstructionMask() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0) = 0;
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Get the norm of the residual image.
+ * Only a few algorithms support this method.
+ *
+ * @param _fNorm if supported, the norm is returned here
+ * @return true if this operation is supported
+ */
+ virtual bool getResidualNorm(float32& _fNorm) { return false; }
+
+protected:
+
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ void _clear();
+
+ //< Projector object.
+ CProjector2D* m_pProjector;
+ //< ProjectionData2D object containing the sinogram.
+ CFloat32ProjectionData2D* m_pSinogram;
+ //< VolumeData2D object for storing the reconstruction volume.
+ CFloat32VolumeData2D* m_pReconstruction;
+
+ //< Use minimum value constraint?
+ bool m_bUseMinConstraint;
+ //< Minimum value constraint.
+ float32 m_fMinValue;
+ //< Use maximum value constraint?
+ bool m_bUseMaxConstraint;
+ //< Maximum value constraint.
+ float32 m_fMaxValue;
+
+ //< Dataobject containing fixed reconstruction mask (0 = don't reconstruct)
+ CFloat32VolumeData2D* m_pReconstructionMask;
+ //< Use the fixed reconstruction mask?
+ bool m_bUseReconstructionMask;
+
+ //< Dataobject containing fixed reconstruction mask (0 = don't reconstruct)
+ CFloat32ProjectionData2D* m_pSinogramMask;
+ //< Use the fixed reconstruction mask?
+ bool m_bUseSinogramMask;
+
+};
+
+// inline functions
+inline std::string CReconstructionAlgorithm2D::description() const { return "3D Reconstruction Algorithm"; };
+inline CProjector2D* CReconstructionAlgorithm2D::getProjector() const { return m_pProjector; }
+inline CFloat32ProjectionData2D* CReconstructionAlgorithm2D::getSinogram() const { return m_pSinogram; }
+inline CFloat32VolumeData2D* CReconstructionAlgorithm2D::getReconstruction() const { return m_pReconstruction; }
+inline CFloat32VolumeData2D* CReconstructionAlgorithm2D::getReconstructionMask() const { return m_pReconstructionMask; }
+
+} // end namespace
+
+#endif
diff --git a/include/astra/ReconstructionAlgorithm3D.h b/include/astra/ReconstructionAlgorithm3D.h
new file mode 100644
index 0000000..063ff6e
--- /dev/null
+++ b/include/astra/ReconstructionAlgorithm3D.h
@@ -0,0 +1,223 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_RECONSTRUCTIONALGORITHM3D
+#define _INC_ASTRA_RECONSTRUCTIONALGORITHM3D
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+
+#include "Float32ProjectionData3D.h"
+#include "Float32VolumeData3D.h"
+
+
+namespace astra {
+
+class CProjector3D;
+
+/**
+ * This is a base class for the different implementations of 3D reconstruction algorithms.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.}
+ * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.}
+ * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.}
+ * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.}
+ * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.}
+ * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.}
+ */
+class _AstraExport CReconstructionAlgorithm3D : public CAlgorithm {
+
+public:
+
+ /** Default constructor, containing no code.
+ */
+ CReconstructionAlgorithm3D();
+
+ /** Destructor.
+ */
+ virtual ~CReconstructionAlgorithm3D();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData3D object containing the sinogram data.
+ * @param _pReconstruction VolumeData3D object for storing the reconstructed volume.
+ */
+ bool initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3D* _pSinogram,
+ CFloat32VolumeData3D* _pReconstruction);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Add a min/max constraint to the reconstruction process
+ *
+ * @param _bUseMin True if the algorithm should use a min constraint.
+ * @param _fMinValue Lower value to clip pixel values to.
+ * @param _bUseMax True if the algorithm should use a max constraint.
+ * @param _fMaxValue Upper value to clip pixel values to.
+ */
+ void setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue);
+
+ /** Set a fixed reconstruction mask. A pixel will only be used in the reconstruction if the
+ * corresponding value in the mask is 1.
+ *
+ * @param _pMask Volume Data object containing fixed reconstruction mask
+ * @param _bEnable enable the use of this mask
+ */
+ void setReconstructionMask(CFloat32VolumeData3D* _pMask, bool _bEnable = true);
+
+ /** Set a fixed sinogram mask. A detector value will only be used in the reconstruction if the
+ * corresponding value in the mask is 1.
+ *
+ * @param _pMask Projection Data object containing fixed sinogram mask
+ * @param _bEnable enable the use of this mask
+ */
+ void setSinogramMask(CFloat32ProjectionData3D* _pMask, bool _bEnable = true);
+
+ /** Get all information parameters.
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information.
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Get projector object
+ *
+ * @return projector
+ */
+ CProjector3D* getProjector() const;
+
+ /** Get sinogram data object
+ *
+ * @return sinogram data object
+ */
+ CFloat32ProjectionData3D* getSinogram() const;
+
+ /** Get Reconstructed Data
+ *
+ * @return reconstruction
+ */
+ CFloat32VolumeData3D* getReconstruction() const;
+
+ /** Get Fixed Reconstruction Mask
+ *
+ * @return fixed reconstruction mask
+ */
+ CFloat32VolumeData3D* getReconstructionMask() const;
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0) = 0;
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+ /** Get the norm of the residual image.
+ * Only a few algorithms support this method.
+ *
+ * @param _fNorm if supported, the norm is returned here
+ * @return true if this operation is supported
+ */
+ virtual bool getResidualNorm(float32& _fNorm) { return false; }
+
+protected:
+
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ //< Projector object.
+ CProjector3D* m_pProjector;
+ //< ProjectionData3D object containing the sinogram.
+ CFloat32ProjectionData3D* m_pSinogram;
+ //< VolumeData3D object for storing the reconstruction volume.
+ CFloat32VolumeData3D* m_pReconstruction;
+
+ //< Use minimum value constraint?
+ bool m_bUseMinConstraint;
+ //< Minimum value constraint.
+ float32 m_fMinValue;
+ //< Use maximum value constraint?
+ bool m_bUseMaxConstraint;
+ //< Maximum value constraint.
+ float32 m_fMaxValue;
+
+ //< Dataobject containing fixed reconstruction mask (0 = don't reconstruct)
+ CFloat32VolumeData3D* m_pReconstructionMask;
+ //< Use the fixed reconstruction mask?
+ bool m_bUseReconstructionMask;
+
+ //< Dataobject containing fixed reconstruction mask (0 = don't reconstruct)
+ CFloat32ProjectionData3D* m_pSinogramMask;
+ //< Use the fixed reconstruction mask?
+ bool m_bUseSinogramMask;
+
+};
+
+// inline functions
+inline std::string CReconstructionAlgorithm3D::description() const { return "3D Reconstruction Algorithm"; };
+inline CProjector3D* CReconstructionAlgorithm3D::getProjector() const { return m_pProjector; }
+inline CFloat32ProjectionData3D* CReconstructionAlgorithm3D::getSinogram() const { return m_pSinogram; }
+inline CFloat32VolumeData3D* CReconstructionAlgorithm3D::getReconstruction() const { return m_pReconstruction; }
+inline CFloat32VolumeData3D* CReconstructionAlgorithm3D::getReconstructionMask() const { return m_pReconstructionMask; }
+
+} // end namespace
+
+#endif
diff --git a/include/astra/SartAlgorithm.h b/include/astra/SartAlgorithm.h
new file mode 100644
index 0000000..1a79a60
--- /dev/null
+++ b/include/astra/SartAlgorithm.h
@@ -0,0 +1,226 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_SARTALGORITHM
+#define _INC_ASTRA_SARTALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+#include "ReconstructionAlgorithm2D.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+#include "DataProjector.h"
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains the implementation of the SART (Simultaneous Algebraic Reconstruction Technique) algorithm.
+ *
+ * The update step of pixel \f$v_j\f$ for projection \f$phi\f$ and iteration \f$k\f$ is given by:
+ * \f[
+ * v_j^{(k+1)} = v_j^{(k)} + \frac{\sum_{p_i \in P_\phi} \left( \lambda \frac{p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}} {\sum_{r=1}^{N}w_{ir} } \right)} {\sum_{p_i \in P_\phi}w_{ij}}
+ * \f]
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.}
+ * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.}
+ * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.}
+ * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.}
+ * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.}
+ * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.}
+ * \astra_xml_item_option{ProjectionOrder, string, "sequential", the order in which the projections are updated. 'sequential', 'random' or 'custom'}
+ * \astra_xml_item_option{ProjectionOrderList, vector of float, not used, if ProjectionOrder='custom': use this order.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('SART');\n
+ * cfg.ProjectorId = proj_id;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * cfg.ReconstructionDataId = recon_id;\n
+ * cfg.option.MaskId = mask_id;\n
+ * cfg.option.UseMinConstraint = 'yes';\n
+ * cfg.option.UseMaxConstraint = 'yes';\n
+ * cfg.option.MaxConstraintValue = 1024;\n
+ * cfg.option.ProjectionOrder = 'custom';\n
+* cfg.option.ProjectionOrderList = randperm(100);\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('iterate'\, alg_id\, 10);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ */
+class _AstraExport CSartAlgorithm : public CReconstructionAlgorithm2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - valid projector
+ * - valid data objects
+ * - projection order all within range
+ */
+ virtual bool _check();
+
+ // temporary data objects
+ CFloat32ProjectionData2D* m_pTotalRayLength;
+ CFloat32VolumeData2D* m_pTotalPixelWeight;
+ CFloat32ProjectionData2D* m_pDiffSinogram;
+
+ int m_iIterationCount;
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CSartAlgorithm();
+
+ /** Constructor.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ */
+ CSartAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Constructor.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @param _piProjectionOrder array containing a projection order.
+ * @param _iProjectionCount number of elements in _piProjectionOrder.
+ */
+ CSartAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int* _piProjectionOrder,
+ int _iProjectionCount);
+
+ /** Destructor.
+ */
+ virtual ~CSartAlgorithm();
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class, no optionals, use sequential order.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @return initialization successful?
+ */
+ virtual bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Initialize class, use custom order.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @param _piProjectionOrder array containing a projection order.
+ * @param _iProjectionCount number of elements in _piProjectionOrder.
+ * @return initialization successful?
+ */
+ virtual bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int* _piProjectionOrder,
+ int _iProjectionCount);
+
+ /** Get all information parameters
+ *
+ * @return map with all boost::any object
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier identifier string to specify which piece of information you want
+ * @return boost::any object
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations. Each iteration is a forward and backprojection of
+ * a single projection index.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 1);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+protected:
+
+
+ //< Order of the projections.
+ int* m_piProjectionOrder;
+ //< Number of projections specified in m_piProjectionOrder.
+ int m_iProjectionCount;
+ //< Current index in the projection order array.
+ int m_iCurrentProjection;
+
+};
+
+// inline functions
+inline std::string CSartAlgorithm::description() const { return CSartAlgorithm::type; };
+
+
+} // end namespace
+
+#endif
diff --git a/include/astra/Singleton.h b/include/astra/Singleton.h
new file mode 100644
index 0000000..5a494e4
--- /dev/null
+++ b/include/astra/Singleton.h
@@ -0,0 +1,87 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_SINGLETON
+#define _INC_ASTRA_SINGLETON
+
+#include <cassert>
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+
+namespace astra {
+ /**
+ * This singleton interface class ensures that any of its children can be instatiated only once. This is used by the ObjectFactories.
+ **/
+template<typename T>
+class Singleton {
+
+ public:
+
+ // constructor
+ Singleton() {
+ assert(!m_singleton);
+ int offset = (uintptr_t)(T*)1 - (uintptr_t)(Singleton<T>*)(T*)1;
+ m_singleton = (T*)((uintptr_t)this + offset);
+ };
+
+ // destructor
+ virtual ~Singleton() {
+ assert(m_singleton);
+ m_singleton = 0;
+ }
+
+ // get singleton
+ static T& getSingleton() {
+ if (!m_singleton)
+ m_singleton = new T();
+ return *m_singleton;
+ }
+ static T* getSingletonPtr() {
+ if (!m_singleton)
+ m_singleton = new T();
+ return m_singleton;
+ }
+
+ private:
+
+ // the singleton
+ static T* m_singleton;
+
+};
+
+#define DEFINE_SINGLETON(T) template<> T* Singleton<T >::m_singleton = 0
+
+// This is a hack to support statements like
+// DEFINE_SINGLETON2(CTemplatedClass<C1, C2>);
+#define DEFINE_SINGLETON2(A,B) template<> A,B* Singleton<A,B >::m_singleton = 0
+
+} // end namespace
+
+#endif
diff --git a/include/astra/SirtAlgorithm.h b/include/astra/SirtAlgorithm.h
new file mode 100644
index 0000000..5cbc4d4
--- /dev/null
+++ b/include/astra/SirtAlgorithm.h
@@ -0,0 +1,217 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_SIRTALGORITHM
+#define _INC_ASTRA_SIRTALGORITHM
+
+#include "Globals.h"
+#include "Config.h"
+
+#include "Algorithm.h"
+#include "ReconstructionAlgorithm2D.h"
+
+#include "Projector2D.h"
+#include "Float32ProjectionData2D.h"
+#include "Float32VolumeData2D.h"
+
+#include "DataProjector.h"
+
+namespace astra {
+
+/**
+ * \brief
+ * This class contains the implementation of the SIRT (Simultaneous Iterative Reconstruction Technique) algorithm.
+ *
+ * The update step of pixel \f$v_j\f$ for iteration \f$k\f$ is given by:
+ * \f[
+ * v_j^{(k+1)} = v_j^{(k)} + \alpha \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}}
+ * \f]
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectorId, integer, Identifier of a projector as it is stored in the ProjectorManager.}
+ * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.}
+ * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.}
+ * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 1 = reconstruct on this pixel. 0 = don't reconstruct on this pixel.}
+ * \astra_xml_item_option{SinogramMaskId, integer, not used, Identifier of a projection data object that acts as a projection mask. 1 = reconstruct using this ray. 0 = don't use this ray while reconstructing.}
+ * \astra_xml_item_option{UseMinConstraint, bool, false, Use minimum value constraint.}
+ * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.}
+ * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.}
+ * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.}
+ *
+ * \par XML Example
+ * \astra_code{
+ * &lt;Algorithm type="SIRT"&gt;\n
+ * &lt;ProjectorID&gt;proj_id&lt;/ProjectorID&gt;\n
+ * &lt;ProjectionDataId&gt;sino_id&lt;/ProjectionDataId&gt;\n
+ * &lt;ReconstructionDataId&gt;recon_id&lt;/ReconstructionDataId&gt;\n
+ * &lt;Option key="ReconstructionMaskId" value="3"/&gt;\n
+ * &lt;Option key="SinogramMaskId" value="4"/&gt;\n
+ * &lt;Option key="UseMinConstraint" value="yes"/&gt;\n
+ * &lt;Option key="UseMaxConstraint" value="yes"/&gt;\n
+ * &lt;Option key="MaxConstraintValue" value="1024"/&gt;\n
+ * &lt;/Algorithm&gt;
+ * }
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('SIRT');\n
+ * cfg.ProjectorId = proj_id;\n
+ * cfg.ProjectionDataId = sino_id;\n
+ * cfg.ReconstructionDataId = recon_id;\n
+ * cfg.option.SinogramMaskId = smask_id;\n
+ * cfg.option.ReconstructionMaskId = mask_id;\n
+ * cfg.option.UseMinConstraint = 'yes';\n
+ * cfg.option.UseMaxConstraint = 'yes';\n
+ * cfg.option.MaxConstraintValue = 1024;\n
+ * alg_id = astra_mex_algorithm('create'\, cfg);\n
+ * astra_mex_algorithm('iterate'\, alg_id\, 10);\n
+ * astra_mex_algorithm('delete'\, alg_id);\n
+ * }
+ *
+ * \par References
+ * [1] "Computational Analysis and Improvement of SIRT", J. Gregor, T. Benson, IEEE Transactions on Medical Imaging, Vol. 22, No. 7, July 2008.
+ */
+class _AstraExport CSirtAlgorithm : public CReconstructionAlgorithm2D {
+
+protected:
+
+ /** Init stuff
+ */
+ virtual void _init();
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - valid projector
+ * - valid data objects
+ */
+ virtual bool _check();
+
+ /** Temporary data object for storing the total ray lengths
+ */
+ CFloat32ProjectionData2D* m_pTotalRayLength;
+
+ /** Temporary data object for storing the total pixel weigths
+ */
+ CFloat32VolumeData2D* m_pTotalPixelWeight;
+
+ /** Temporary data object for storing the difference between the forward projected
+ * reconstruction, and the measured projection data
+ */
+ CFloat32ProjectionData2D* m_pDiffSinogram;
+
+ /** Temporary data object for storing volume data
+ */
+ CFloat32VolumeData2D* m_pTmpVolume;
+
+ /** The number of performed iterations
+ */
+ int m_iIterationCount;
+
+public:
+
+ // type of the algorithm, needed to register with CAlgorithmFactory
+ static std::string type;
+
+ /** Default constructor, containing no code.
+ */
+ CSirtAlgorithm();
+
+ /** Default constructor
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ */
+ CSirtAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Destructor.
+ */
+ virtual ~CSirtAlgorithm();
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Initialize the algorithm with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return Initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize class.
+ *
+ * @param _pProjector Projector Object.
+ * @param _pSinogram ProjectionData2D object containing the sinogram data.
+ * @param _pReconstruction VolumeData2D object for storing the reconstructed volume.
+ * @return Initialization successful?
+ */
+ bool initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction);
+
+ /** Get all information parameters.
+ *
+ * @return Map with all available identifier strings and their values.
+ */
+ virtual map<string,boost::any> getInformation();
+
+ /** Get a single piece of information represented as a boost::any
+ *
+ * @param _sIdentifier Identifier string to specify which piece of information you want.
+ * @return One piece of information.
+ */
+ virtual boost::any getInformation(std::string _sIdentifier);
+
+ /** Perform a number of iterations.
+ *
+ * @param _iNrIterations amount of iterations to perform.
+ */
+ virtual void run(int _iNrIterations = 0);
+
+ /** Get a description of the class.
+ *
+ * @return description string
+ */
+ virtual std::string description() const;
+
+};
+
+// inline functions
+inline std::string CSirtAlgorithm::description() const { return CSirtAlgorithm::type; };
+
+
+} // end namespace
+
+#endif
diff --git a/include/astra/SparseMatrix.h b/include/astra/SparseMatrix.h
new file mode 100644
index 0000000..e07be87
--- /dev/null
+++ b/include/astra/SparseMatrix.h
@@ -0,0 +1,144 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_SPARSEMATRIX
+#define _INC_ASTRA_SPARSEMATRIX
+
+namespace astra
+{
+
+
+/** This class implements a sparse matrix. It is stored as three arrays.
+ * The values are stored row-by-row.
+ * m_pfValues contains the values
+ * m_piColIndices contains the col indices of the values
+ * m_plRowStarts contains the start offsets of the rows
+ */
+
+
+class _AstraExport CSparseMatrix {
+public:
+ CSparseMatrix();
+
+ // TODO: are ints large enough for width/height?
+ CSparseMatrix(unsigned int _iHeight, unsigned int _iWidth,
+ unsigned long _lSize);
+
+ /** Initialize the matrix structure.
+ * It does not initialize any values.
+ *
+ * @param _iHeight number of rows
+ * @param _iWidth number of columns
+ * @param _lSize maximum number of non-zero entries
+ * @return initialization successful?
+ */
+
+ bool initialize(unsigned int _iHeight, unsigned int _iWidth,
+ unsigned long _lSize);
+
+ /** Destructor.
+ */
+ ~CSparseMatrix();
+
+ /** Has the matrix structure been initialized?
+ *
+ * @return initialized successfully
+ */
+ bool isInitialized() const { return m_bInitialized; }
+
+ /** get a description of the class
+ *
+ * @return description string
+ */
+ std::string description() const;
+
+ /** get the data for a single row. Entries are stored from left to right.
+ *
+ * @param _iRow the row
+ * @param _iSize the returned number of elements in the row
+ * @param _pfValues the values of the non-zero entries in the row
+ * @param _piColIndices the column indices of the non-zero entries
+ */
+ void getRowData(unsigned int _iRow, unsigned int& _iSize,
+ const float32*& _pfValues, const unsigned int*& _piColIndices) const
+ {
+ assert(_iRow < m_iHeight);
+ unsigned long lStart = m_plRowStarts[_iRow];
+ _iSize = m_plRowStarts[_iRow+1] - lStart;
+ _pfValues = &m_pfValues[lStart];
+ _piColIndices = &m_piColIndices[lStart];
+ }
+
+ /** get the number of elements in a row
+ *
+ * @param _iRow the row
+ * @return number of stored entries in the row
+ */
+ unsigned int getRowSize(unsigned int _iRow) const
+ {
+ assert(_iRow < m_iHeight);
+ return m_plRowStarts[_iRow+1] - m_plRowStarts[_iRow];
+ }
+
+
+ /** Matrix width
+ */
+ unsigned int m_iHeight;
+
+ /** Matrix height
+ */
+ unsigned int m_iWidth;
+
+ /** Maximum number of non-zero entries
+ */
+ unsigned long m_lSize;
+
+ /** Contains the numeric values of all non-zero elements
+ */
+ float32* m_pfValues;
+
+ /** Contains the colon index of all non-zero elements
+ */
+ unsigned int* m_piColIndices;
+
+ /** The indices in this array point to the first element of each row in the m_pfValues array
+ */
+ unsigned long* m_plRowStarts;
+
+protected:
+
+ /** Is the class initialized?
+ */
+ bool m_bInitialized;
+};
+
+
+}
+
+
+#endif
diff --git a/include/astra/SparseMatrixProjectionGeometry2D.h b/include/astra/SparseMatrixProjectionGeometry2D.h
new file mode 100644
index 0000000..e334dd1
--- /dev/null
+++ b/include/astra/SparseMatrixProjectionGeometry2D.h
@@ -0,0 +1,154 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_SPARSEMATRIXPROJECTIONGEOMETRY2D
+#define _INC_ASTRA_SPARSEMATRIXPROJECTIONGEOMETRY2D
+
+#include "ProjectionGeometry2D.h"
+
+namespace astra
+{
+
+class CSparseMatrix;
+
+/**
+ * This class defines a projection geometry determined by an arbitrary
+ * sparse matrix.
+ *
+ * The projection data is assumed to be grouped by 'angle' and 'detector pixel'.
+ * This does not have any effect on the algorithms, but only on the
+ * way the projection data is stored and accessed.
+ */
+class _AstraExport CSparseMatrixProjectionGeometry2D : public CProjectionGeometry2D
+{
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ *
+ */
+ CSparseMatrixProjectionGeometry2D();
+
+ /** Constructor. Create an instance of the CSparseMatrixProjectionGeometry2D class.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _pMatrix Pointer to a CSparseMatrix. The caller is responsible for keeping this matrix valid until it is no longer required.
+ */
+ CSparseMatrixProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ const CSparseMatrix* _pMatrix);
+
+ /** Copy constructor.
+ */
+ CSparseMatrixProjectionGeometry2D(const CSparseMatrixProjectionGeometry2D& _projGeom);
+
+ /** Destructor.
+ */
+ ~CSparseMatrixProjectionGeometry2D();
+
+ /** Assignment operator.
+ */
+ CSparseMatrixProjectionGeometry2D& operator=(const CSparseMatrixProjectionGeometry2D& _other);
+
+ /** Initialize the geometry with a config object. This does not allow
+ * setting a matrix. Use the setMatrix() method for that afterwards.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialization. Initializes an instance of the CProjectionGeometry2D class. If the object has been
+ * initialized before, the object is reinitialized and memory is freed and reallocated if necessary.
+ *
+ * @param _iProjectionAngleCount Number of projection angles.
+ * @param _iDetectorCount Number of detectors, i.e., the number of detector measurements for each projection angle.
+ * @param _pMatrix Pointer to a CSparseMatrix. The caller is responsible for keeping this matrix valid until it is no longer required.
+ */
+ bool initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ const CSparseMatrix* _pMatrix);
+
+ /** Set the associated sparse matrix. The previous one is deleted.
+ *
+ * @param _pMatrix Pointer to a CSparseMatrix. The caller is responsible for keeping this matrix valid until it is no longer required.
+ * @return initialization successful?
+ */
+
+ bool setMatrix(CSparseMatrix* _pMatrix);
+
+ /** Get a pointer to the associated sparse matrix.
+ * @return the associated sparse matrix
+ */
+ const CSparseMatrix* getMatrix() const { return m_pMatrix; }
+
+ /** Create a hard copy.
+ */
+ virtual CProjectionGeometry2D* clone();
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(CProjectionGeometry2D*) const;
+
+ /** Returns true if the type of geometry defined in this class is the one specified in _sType.
+ *
+ * @param _sType geometry type to compare to.
+ * @return true if _sType == "parallel".
+ */
+ virtual bool isOfType(const std::string& _sType);
+
+ /**
+ * Returns a vector describing the direction of a ray belonging to a certain detector
+ *
+ * @param _iProjectionIndex index of projection
+ * @param _iProjectionIndex index of detector
+ *
+ * @return a unit vector describing the direction
+ */
+ virtual CVector3D getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex);
+
+protected:
+
+ /** Check this object.
+ *
+ * @return object initialized
+ */
+ bool _check();
+
+ const CSparseMatrix* m_pMatrix;
+};
+
+} // namespace astra
+
+#endif /* _INC_ASTRA_SPARSEMATRIXPROJECTIONGEOMETRY2D */
diff --git a/include/astra/SparseMatrixProjector2D.h b/include/astra/SparseMatrixProjector2D.h
new file mode 100644
index 0000000..f2554bf
--- /dev/null
+++ b/include/astra/SparseMatrixProjector2D.h
@@ -0,0 +1,210 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_SPARSEMATRIXPROJECTOR2D
+#define _INC_ASTRA_SPARSEMATRIXPROJECTOR2D
+
+#include "SparseMatrixProjectionGeometry2D.h"
+#include "SparseMatrix.h"
+#include "Float32Data2D.h"
+#include "Projector2D.h"
+
+namespace astra
+{
+
+
+/** This class implements a two-dimensional projector using a projection geometry defined by an arbitrary sparse matrix.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{ProjectionGeometry, xml node, The geometry of the projection.}
+ * \astra_xml_item{VolumeGeometry, xml node, The geometry of the volume.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * cfg = astra_struct('sparse_matrix');\n
+ * cfg.ProjectionGeometry = proj_geom;\n
+ * cfg.VolumeGeometry = vol_geom;\n
+ * proj_id = astra_mex_projector('create'\, cfg);\n
+ * }
+ */
+class _AstraExport CSparseMatrixProjector2D : public CProjector2D {
+
+protected:
+
+ /** Initial clearing. Only to be used by constructors.
+ */
+ virtual void _clear();
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - no NULL pointers
+ * - all sub-objects are initialized properly
+ * - matrix dimensions match volume geometry
+ */
+ virtual bool _check();
+
+public:
+
+ // type of the projector, needed to register with CProjectorFactory
+ static std::string type;
+
+ /** Default constructor.
+ */
+ CSparseMatrixProjector2D();
+
+ /** Constructor.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ */
+ CSparseMatrixProjector2D(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Destructor, is virtual to show that we are aware subclass destructor are called.
+ */
+ ~CSparseMatrixProjector2D();
+
+ /** Initialize the projector with a config object.
+ *
+ * @param _cfg Configuration Object
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialize the projector.
+ *
+ * @param _pProjectionGeometry Information class about the geometry of the projection. Will be HARDCOPIED.
+ * @param _pReconstructionGeometry Information class about the geometry of the reconstruction volume. Will be HARDCOPIED.
+ * @return initialization successful?
+ */
+ virtual bool initialize(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry);
+
+ /** Clear this class.
+ */
+ virtual void clear();
+
+ /** Returns the number of weights required for storage of all weights of one projection.
+ *
+ * @param _iProjectionIndex Index of the projection (zero-based).
+ * @return Size of buffer (given in SPixelWeight elements) needed to store weighted pixels.
+ */
+ virtual int getProjectionWeightsCount(int _iProjectionIndex);
+
+ /** Compute the pixel weights for a single ray, from the source to a detector pixel.
+ *
+ * @param _iProjectionIndex Index of the projection
+ * @param _iDetectorIndex Index of the detector pixel
+ * @param _pWeightedPixels Pointer to a pre-allocated array, consisting of _iMaxPixelCount elements
+ * of type SPixelWeight. On return, this array contains a list of the index
+ * and weight for all pixels on the ray.
+ * @param _iMaxPixelCount Maximum number of pixels (and corresponding weights) that can be stored in _pWeightedPixels.
+ * This number MUST be greater than the total number of pixels on the ray.
+ * @param _iStoredPixelCount On return, this variable contains the total number of pixels on the
+ * ray (that have been stored in the list _pWeightedPixels).
+ */
+ virtual void computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount);
+
+ /** Create a list of detectors that are influenced by point [_iRow, _iCol].
+ *
+ * @param _iRow row of the point
+ * @param _iCol column of the point
+ * @return list of SDetector2D structs
+ */
+ virtual std::vector<SDetector2D> projectPoint(int _iRow, int _iCol);
+
+ /** Policy-based projection of all rays. This function will calculate each non-zero projection
+ * weight and use this value for a task provided by the policy object.
+ *
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void project(Policy& _policy);
+
+ /** Policy-based projection of all rays of a single projection. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Wwhich projection should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleProjection(int _iProjection, Policy& _policy);
+
+ /** Policy-based projection of a single ray. This function will calculate each non-zero
+ * projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iProjection Which projection should be projected?
+ * @param _iDetector Which detector should be projected?
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleRay(int _iProjection, int _iDetector, Policy& _policy);
+
+ /** Policy-based voxel-projection of a single pixel. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _iRow
+ * @param _iCol
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectSingleVoxel(int _iRow, int _iCol, Policy& _policy) {}
+
+ /** Policy-based voxel-projection of all voxels. This function will calculate
+ * each non-zero projection weight and use this value for a task provided by the policy object.
+ *
+ * @param _policy Policy object. Should contain prior, addWeight and posterior function.
+ */
+ template <typename Policy>
+ void projectAllVoxels(Policy& _policy) {}
+
+protected:
+
+ /** Return the type of this projector.
+ *
+ * @return identification type of this projector
+ */
+ virtual std::string getType();
+
+};
+
+//----------------------------------------------------------------------------------------
+
+inline std::string CSparseMatrixProjector2D::getType()
+{
+ return type;
+}
+
+} // namespace astra
+
+#endif
+
diff --git a/include/astra/SparseMatrixProjector2D.inl b/include/astra/SparseMatrixProjector2D.inl
new file mode 100644
index 0000000..8256232
--- /dev/null
+++ b/include/astra/SparseMatrixProjector2D.inl
@@ -0,0 +1,90 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT ALL
+template <typename Policy>
+void CSparseMatrixProjector2D::project(Policy& p)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ for (int i = 0; i < m_pProjectionGeometry->getProjectionAngleCount(); ++i)
+ for (int j = 0; j < m_pProjectionGeometry->getDetectorCount(); ++j)
+ projectSingleRay(i, j, p);
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE PROJECTION
+template <typename Policy>
+void CSparseMatrixProjector2D::projectSingleProjection(int _iProjection, Policy& p)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ for (int j = 0; j < m_pProjectionGeometry->getDetectorCount(); ++j)
+ projectSingleRay(_iProjection, j, p);
+}
+
+
+//----------------------------------------------------------------------------------------
+// PROJECT SINGLE RAY
+template <typename Policy>
+void CSparseMatrixProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector;
+ const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix();
+
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) return;
+
+ const unsigned int* piColIndices;
+ const float32* pfValues;
+ unsigned int iSize;
+
+ pMatrix->getRowData(iRayIndex, iSize, pfValues, piColIndices);
+
+ for (unsigned int i = 0; i < iSize; ++i) {
+ unsigned int iVolumeIndex = piColIndices[i];
+
+ // POLICY: PIXEL PRIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+
+ // POLICY: ADD
+ p.addWeight(iRayIndex, iVolumeIndex, pfValues[i]);
+
+ // POLICY: PIXEL POSTERIOR
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+}
diff --git a/include/astra/TypeList.h b/include/astra/TypeList.h
new file mode 100644
index 0000000..fcf985d
--- /dev/null
+++ b/include/astra/TypeList.h
@@ -0,0 +1,236 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_TYPELIST
+#define _INC_ASTRA_TYPELIST
+
+#include "Globals.h"
+#include <cstring>
+
+namespace astra {
+namespace typelist {
+
+ //-----------------------------------------------------------------------------------------
+ // basic types
+ /**
+ * Type to serve as tail of typelist
+ **/
+ class NullType { };
+ struct FalseType { enum { value = false }; };
+ struct TrueType { enum { value = true }; };
+
+ //-----------------------------------------------------------------------------------------
+ // define typelist
+ /**
+ * Typelist definition
+ * \par References
+ * [1] Modern C++ design: generic programming and design patterns applied, Andrei Alexandrescu
+ **/
+ template <class T, class U>
+ struct TypeList
+ {
+ typedef T Head;
+ typedef U Tail;
+ };
+
+ //-----------------------------------------------------------------------------------------
+ // linearize typelist
+ #define TYPELIST_0 NullType
+ #define TYPELIST_1(T1) TypeList<T1, NullType>
+ #define TYPELIST_2(T1,T2) TypeList<T1, TYPELIST_1(T2) >
+ #define TYPELIST_3(T1,T2,T3) TypeList<T1, TYPELIST_2(T2,T3) >
+ #define TYPELIST_4(T1,T2,T3,T4) TypeList<T1, TYPELIST_3(T2,T3,T4) >
+ #define TYPELIST_5(T1,T2,T3,T4,T5) TypeList<T1, TYPELIST_4(T2,T3,T4,T5) >
+ #define TYPELIST_6(T1,T2,T3,T4,T5,T6) TypeList<T1, TYPELIST_5(T2,T3,T4,T5,T6) >
+ #define TYPELIST_7(T1,T2,T3,T4,T5,T6,T7) TypeList<T1, TYPELIST_6(T2,T3,T4,T5,T6,T7) >
+ #define TYPELIST_8(T1,T2,T3,T4,T5,T6,T7,T8) TypeList<T1, TYPELIST_7(T2,T3,T4,T5,T6,T7,T8) >
+ #define TYPELIST_9(T1,T2,T3,T4,T5,T6,T7,T8,T9) TypeList<T1, TYPELIST_8(T2,T3,T4,T5,T6,T7,T8,T9)>
+ #define TYPELIST_10(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10) \
+ TypeList<T1, TYPELIST_9(T2,T3,T4,T5,T6,T7,T8,T9,T10) >
+ #define TYPELIST_11(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11) \
+ TypeList<T1, TYPELIST_10(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11) >
+ #define TYPELIST_12(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12) \
+ TypeList<T1, TYPELIST_11(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12) >
+ #define TYPELIST_13(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13) \
+ TypeList<T1, TYPELIST_12(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13) >
+ #define TYPELIST_14(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14) \
+ TypeList<T1, TYPELIST_13(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14) >
+ #define TYPELIST_15(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15) \
+ TypeList<T1, TYPELIST_14(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15) >
+ #define TYPELIST_16(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16) \
+ TypeList<T1, TYPELIST_15(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16) >
+ #define TYPELIST_17(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17) \
+ TypeList<T1, TYPELIST_16(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17) >
+ #define TYPELIST_18(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18) \
+ TypeList<T1, TYPELIST_17(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18) >
+ #define TYPELIST_19(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19) \
+ TypeList<T1, TYPELIST_18(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19) >
+ #define TYPELIST_20(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20) \
+ TypeList<T1, TYPELIST_19(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20) >
+ #define TYPELIST_21(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21) \
+ TypeList<T1, TYPELIST_20(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21) >
+ #define TYPELIST_22(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22) \
+ TypeList<T1, TYPELIST_21(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22) >
+ #define TYPELIST_23(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23) \
+ TypeList<T1, TYPELIST_22(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23) >
+
+ #define TYPELIST_24(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24) \
+ TypeList<T1, TYPELIST_23(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24) >
+
+ #define TYPELIST_25(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25) \
+ TypeList<T1, TYPELIST_24(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25) >
+
+ #define TYPELIST_26(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26) \
+ TypeList<T1, TYPELIST_25(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26) >
+
+ #define TYPELIST_27(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27) \
+ TypeList<T1, TYPELIST_26(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27) >
+
+ #define TYPELIST_28(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28) \
+ TypeList<T1, TYPELIST_27(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28) >
+
+ #define TYPELIST_29(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29) \
+ TypeList<T1, TYPELIST_28(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29) >
+
+ #define TYPELIST_30(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30) \
+ TypeList<T1, TYPELIST_29(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30) >
+
+ #define TYPELIST_31(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31) \
+ TypeList<T1, TYPELIST_30(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31) >
+
+ #define TYPELIST_32(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32) \
+ TypeList<T1, TYPELIST_31(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32) >
+
+ #define TYPELIST_33(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33) \
+ TypeList<T1, TYPELIST_32(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33) >
+
+ #define TYPELIST_34(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34) \
+ TypeList<T1, TYPELIST_33(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34) >
+
+ #define TYPELIST_35(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35) \
+ TypeList<T1, TYPELIST_34(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35) >
+
+ #define TYPELIST_36(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36) \
+ TypeList<T1, TYPELIST_35(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36) >
+
+ #define TYPELIST_37(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37) \
+ TypeList<T1, TYPELIST_36(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37) >
+
+ #define TYPELIST_38(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38) \
+ TypeList<T1, TYPELIST_37(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38) >
+
+ #define TYPELIST_39(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38,T39) \
+ TypeList<T1, TYPELIST_38(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38,T39) >
+
+ #define TYPELIST_40(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38,T39,T40) \
+ TypeList<T1, TYPELIST_39(T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,T17,T18,T19,T20,T21,T22,T23,T24,T25,T26,T27,T28,T29,T30,T31,T32,T33,T34,T35,T36,T37,T38,T39,T40) >
+
+
+ //-----------------------------------------------------------------------------------------
+ // calculate length of a typelist
+ template <class TList> struct Length;
+ template <> struct Length<NullType>
+ {
+ enum { value = 0 };
+ };
+ template <class T, class U>
+ struct Length< TypeList<T,U> >
+ {
+ enum { value = 1 + Length<U>::value };
+ };
+
+ //-----------------------------------------------------------------------------------------
+ // indexed access
+ template <class TList, unsigned int i> struct TypeAt;
+ template <class Head, class Tail>
+ struct TypeAt<TypeList<Head,Tail> , 0>
+ {
+ typedef Head Result;
+ };
+ template <class Head, class Tail, unsigned int i>
+ struct TypeAt<TypeList<Head,Tail>, i>
+ {
+ typedef typename TypeAt<Tail, i-1>::Result Result;
+ };
+
+
+ //-----------------------------------------------------------------------------------------
+ // append to typelist
+ template <class TList, class T> struct Append;
+ template <>
+ struct Append<NullType, NullType> {
+ typedef NullType Result;
+ };
+ template <class T>
+ struct Append<NullType, T> {
+ typedef TYPELIST_1(T) Result;
+ };
+ template <class Head, class Tail>
+ struct Append<NullType, TypeList<Head,Tail> > {
+ typedef TypeList<Head,Tail> Result;
+ };
+ template <class Head, class Tail, class T>
+ struct Append<TypeList<Head,Tail>, T> {
+ typedef TypeList<Head, typename Append<Tail, T>::Result> Result;
+ };
+
+ //-----------------------------------------------------------------------------------------
+ // create a new object
+ template <class TList>
+ struct CreateObject {
+ template <class U>
+ static void find (U& functor) {
+ if (functor(TList::Head::type)) {
+ functor.res = new typename TList::Head();
+ }
+ CreateObject<typename TList::Tail>::find(functor);
+ }
+ };
+ template <>
+ struct CreateObject<NullType> {
+ template <class U>
+ static void find(U& functor) {}
+ };
+
+ template <typename Base>
+ struct functor_find {
+ functor_find() { res = NULL; }
+ bool operator() (string name) {
+ return strcmp(tofind.c_str(), name.c_str()) == 0;
+ }
+ string tofind;
+ Base* res;
+ };
+
+
+
+
+} // end namespace typelist
+} // end namespace astra
+
+#endif
diff --git a/include/astra/Utilities.h b/include/astra/Utilities.h
new file mode 100644
index 0000000..7bf0cae
--- /dev/null
+++ b/include/astra/Utilities.h
@@ -0,0 +1,131 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_UTILIES
+#define _INC_ASTRA_UTILIES
+
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <sstream>
+#include <map>
+
+#include "Globals.h"
+
+namespace astra {
+
+/**
+ * This class contains some usefull static utility functions for std strings.
+ */
+class StringUtil {
+
+public:
+ /**
+ * Removes whitespace characters such as spaces and tabs at the extremas.
+ * Optionally you can specify which extrema to trim (default=both)
+ *
+ * @param _sString The string to trim.
+ * @param _bLeft Trim the left extrema? Default = true.
+ * @param _bRight Trim the right extrema? Default = true.
+ */
+ static void trim(std::string& _sString, bool _bLeft = true, bool _bRight = true);
+
+ /**
+ * Returns a vector of strings that contains all the substrings delimited by
+ * the characters in _sDelims.
+ *
+ * @param _sString The string to split.
+ * @param _sDelims The delimiter string.
+ * @return Vector of strings.
+ */
+ static std::vector<std::string> split(const std::string& _sString, const std::string& _sDelims);
+
+ /**
+ * Cast a string to an integer.
+ *
+ * @param _sString The string to cast.
+ * @param _iValue Output integer parameter.
+ * @return success?
+ */
+ static bool toInt(const std::string& _sString, int& _iValue);
+
+ /**
+ * Cast a string to a float32.
+ *
+ * @param _sString The string to cast.
+ * @param _fValue Output float32 parameter.
+ * @return success?
+ */
+ static bool toFloat32(const std::string& _sString, float32& _fValue);
+
+ /**
+ * Convert a string to lower case.
+ *
+ * @param _sString The string to convert.
+ */
+ static void toLowerCase(std::string& _sString);
+
+ /**
+ * Convert a string to upper case.
+ *
+ * @param _sString The string to convert.
+ */
+ static void toUpperCase(std::string& _sString);
+};
+
+/**
+ * This class contains some usefull static utility functions for std strings.
+ */
+class FileSystemUtil {
+
+public:
+ /**
+ * Get the extensions of a filename. Always in lower case.
+ *
+ * @param _sFilename file to get extensions from.
+ * @return Extension (lower case). Empty string if filename is a directory or not a valid file format.
+ */
+ static std::string getExtension(std::string& _sFilename);
+
+
+};
+
+
+template<typename T, typename S>
+std::map<T,S> mergeMap(std::map<T,S> _mMap1, std::map<T,S> _mMap2)
+{
+ std::map<T,S> result = _mMap1;
+ for (typename std::map<T,S>::iterator it = _mMap2.begin(); it != _mMap2.end(); it++) {
+ result[(*it).first] = (*it).second;
+ }
+ return result;
+}
+
+} // end namespace
+
+#endif
diff --git a/include/astra/Vector3D.h b/include/astra/Vector3D.h
new file mode 100644
index 0000000..ee923c9
--- /dev/null
+++ b/include/astra/Vector3D.h
@@ -0,0 +1,131 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_VECTOR3D
+#define _INC_ASTRA_VECTOR3D
+
+#include "Globals.h"
+
+namespace astra {
+
+/**
+ * This class defines a three-dimensional vector type.
+ */
+class CVector3D
+{
+ float32 m_fX; ///< X Coordinate
+ float32 m_fY; ///< Y Coordinate
+ float32 m_fZ; ///< Z Coordinate
+
+public:
+ /**
+ * Default constructor
+ */
+ CVector3D();
+
+ /**
+ * Constructor initializing member variables
+ */
+ CVector3D(float32 _fX, float32 _fY, float32 _fZ);
+
+ /**
+ * Returns the X-coordinate stored in this vector
+ */
+ float32 getX() const;
+
+ /**
+ * Returns the Y-coordinate stored in this vector
+ */
+ float32 getY() const;
+
+ /**
+ * Returns the Z-coordinate stored in this vector
+ */
+ float32 getZ() const;
+
+ /**
+ * Sets the X-coordinate stored in this vector
+ */
+ void setX(float32 _fX);
+
+ /**
+ * Sets the X-coordinate stored in this vector
+ */
+ void setY(float32 _fY);
+
+ /**
+ * Sets the X-coordinate stored in this vector
+ */
+ void setZ(float32 _fZ);
+};
+
+inline CVector3D::CVector3D()
+{
+ m_fX = m_fY = m_fZ = 0.0f;
+}
+
+inline CVector3D::CVector3D(float32 _fX, float32 _fY, float32 _fZ)
+{
+ m_fX = _fX;
+ m_fY = _fY;
+ m_fZ = _fZ;
+}
+
+inline float32 CVector3D::getX() const
+{
+ return m_fX;
+}
+
+inline float32 CVector3D::getY() const
+{
+ return m_fY;
+}
+
+inline float32 CVector3D::getZ() const
+{
+ return m_fZ;
+}
+
+inline void CVector3D::setX(float32 _fX)
+{
+ m_fX = _fX;
+}
+
+inline void CVector3D::setY(float32 _fY)
+{
+ m_fY = _fY;
+}
+
+inline void CVector3D::setZ(float32 _fZ)
+{
+ m_fZ = _fZ;
+}
+
+}
+
+#endif /* _INC_ASTRA_VECTOR3D */
diff --git a/include/astra/VolumeGeometry2D.h b/include/astra/VolumeGeometry2D.h
new file mode 100644
index 0000000..99d480d
--- /dev/null
+++ b/include/astra/VolumeGeometry2D.h
@@ -0,0 +1,608 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_VOLUMEGEOMETRY2D
+#define _INC_ASTRA_VOLUMEGEOMETRY2D
+
+#include "Globals.h"
+#include "Config.h"
+
+namespace astra
+{
+
+/**
+ * This class represents a pixel grid that is placed in the geometry. It defines a rectangular volume window.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{GridColCount, integer, Number of columns in this geometry.}
+ * \astra_xml_item{GridRowCount, integer, Number of rows in this geometry.}
+ * \astra_xml_item_option{WindowMinX, float, Minimal X-coordinate in the volume window.}
+ * \astra_xml_item_option{WindowMaxX, float, Maximal X-coordinate in the volume window.}
+ * \astra_xml_item_option{WindowMinY, float, Minimal Y-coordinate in the volume window.}
+ * \astra_xml_item_option{WindowMaxY, float, Maximal Y-coordinate in the volume window.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * vol_geom = struct();\n
+ * vol_geom.GridColCount = 1024;\n
+ * vol_geom.GridRowCount = 768;\n
+ * vol_geom.option.WindowMinX = -512;\n
+ * vol_geom.option.WindowMaxX = -384;\n
+ * vol_geom.option.WindowMinY = 512;\n
+ * vol_geom.option.WindowMaxY = 384;\n
+ * }
+ */
+class _AstraExport CVolumeGeometry2D {
+
+protected:
+ bool m_bInitialized; ///< Has this object been initialized?
+
+ int m_iGridColCount; ///< number of columns in the volume grid.
+ int m_iGridRowCount; ///< number of rows in the volume grid.
+ int m_iGridTotCount; ///< total number of pixels in the volume grid (= m_iGridColCount * m_iGridRowCount).
+
+ /** Width of the volume window, in unit lengths.
+ *
+ * Note that this width is independent of the number of pixels in the X-direction, as the width of a pixel can
+ * be different from 1.
+ */
+ float32 m_fWindowLengthX;
+
+ /** Height of the volume window, in unit lengths.
+ *
+ * Note that this height is independent of the number of pixels in the Y-direction, as the height of a pixel can
+ * be different from 1.
+ */
+ float32 m_fWindowLengthY;
+
+ float32 m_fWindowArea; ///< Total area of the volume window, in unit lengths squared.
+
+ float32 m_fPixelLengthX; ///< Width of a single pixel, in unit lengths.
+ float32 m_fPixelLengthY; ///< Height of a single pixel, in unit lengths.
+ float32 m_fPixelArea; ///< Area of a single pixel, in unit lengths squared.
+
+ float32 m_fDivPixelLengthX; ///< 1/m_fPixelLengthX, used for fast division.
+ float32 m_fDivPixelLengthY; ///< 1/m_fPixelLengthY, used for fast division.
+
+ float32 m_fWindowMinX; ///< Minimal X-coordinate in the volume window.
+ float32 m_fWindowMinY; ///< Maximal X-coordinate in the volume window.
+ float32 m_fWindowMaxX; ///< Minimal Y-coordinate in the volume window.
+ float32 m_fWindowMaxY; ///< Maximal Y-coordinate in the volume window.
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - number of rows and columns is larger than zero
+ * - window minima is smaller than window maxima
+ * - m_iGridTotCount, m_fWindowLengthX, m_fWindowLengthY, m_fWindowArea, m_fPixelLengthX,
+ * m_fPixelLengthY, m_fPixelArea, m_fDivPixelLengthX and m_fDivPixelLengthY are initialized ok
+ */
+ bool _check();
+
+
+ /** Calculate values of all member variables from m_iGridRow/ColCount, m_fWindow*
+ */
+ void _calculateDependents();
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ */
+ CVolumeGeometry2D();
+
+ /** Constructor. Create an instance of the CVolumeGeometry2D class.
+ * The minimal and coordinates values of the geometry will be set to -/+ the number of rows/columns.
+ *
+ * @param _iGridCountX Number of columns in the volume grid.
+ * @param _iGridCountY Number of rows in the volume grid.
+ */
+ CVolumeGeometry2D(int _iGridCountX,
+ int _iGridCountY);
+
+ /** Constructor. Create an instance of the CVolumeGeometry2D class.
+ *
+ * @param _iGridCountX Number of columns in the volume grid.
+ * @param _iGridCountY Number of rows in the volume grid.
+ * @param _fWindowMinX Minimal X-coordinate in the volume window.
+ * @param _fWindowMinY Minimal Y-coordinate in the volume window.
+ * @param _fWindowMaxX Maximal X-coordinate in the volume window.
+ * @param _fWindowMaxY Maximal Y-coordinate in the volume window.
+ */
+ CVolumeGeometry2D(int _iGridCountX,
+ int _iGridCountY,
+ float32 _fWindowMinX,
+ float32 _fWindowMinY,
+ float32 _fWindowMaxX,
+ float32 _fWindowMaxY);
+
+ /** Destructor.
+ */
+ virtual ~CVolumeGeometry2D();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ */
+ void clear();
+
+ /** Create a hard copy.
+ */
+ CVolumeGeometry2D* clone();
+
+ /** Initialize the volume geometry with a config object.
+ *
+ * @param _cfg Configuration Object.
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialization. Initializes an instance of the CVolumeGeometry2D class.
+ * The minimal and maximal coordinates of the geometry will be set to -/+ half the number of rows/columns.
+ *
+ * If the object has been initialized before, the object is reinitialized and
+ * memory is freed and reallocated if necessary.
+ *
+ * @param _iGridColCount Number of columns in the volume grid.
+ * @param _iGridRowCount Number of rows in the volume grid.
+ * @return initialization successful
+ */
+ bool initialize(int _iGridColCount, int _iGridRowCount);
+
+ /** Initialization. Initializes an instance of the CVolumeGeometry2D class.
+ *
+ * If the object has been initialized before, the object is reinitialized and
+ * memory is freed and reallocated if necessary.
+ *
+ * @param _iGridColCount Number of columns in the volume grid.
+ * @param _iGridRowCount Number of rows in the volume grid.
+ * @param _fWindowMinX Minimal X-coordinate in the volume window.
+ * @param _fWindowMinY Minimal Y-coordinate in the volume window.
+ * @param _fWindowMaxX Maximal X-coordinate in the volume window.
+ * @param _fWindowMaxY Maximal Y-coordinate in the volume window.
+ * @return initialization successful
+ */
+ bool initialize(int _iGridColCount,
+ int _iGridRowCount,
+ float32 _fWindowMinX,
+ float32 _fWindowMinY,
+ float32 _fWindowMaxX,
+ float32 _fWindowMaxY);
+
+ /** Get the initialization state of the object.
+ *
+ * @return true iff the object has been initialized.
+ */
+ bool isInitialized() const;
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(CVolumeGeometry2D*) const;
+
+ /** Get the number of columns in the volume grid.
+ *
+ * @return Number of columns in the volume grid.
+ */
+ int getGridColCount() const;
+
+ /** Get the number of rows in the volume grid.
+ *
+ * @return Number of rows in the volume grid.
+ */
+ int getGridRowCount() const;
+
+ /** Get the total number of pixels in the volume grid.
+ *
+ * @return Total number of pixels.
+ */
+ int getGridTotCount() const;
+
+ /** Get the horizontal length of the volume window, in unit lengths.
+ *
+ * @return Horizontal length of the volume window.
+ */
+ float32 getWindowLengthX() const;
+
+ /** Get the vertical length of the volume window, in unit lengths.
+ *
+ * @return Vertical length of the volume window.
+ */
+ float32 getWindowLengthY() const;
+
+ /** Get the total area of the volume window, in unit lengths squared.
+ *
+ * @return Total area of the volume window.
+ */
+ float32 getWindowArea() const;
+
+ /** Get the horizontal length of a single pixel (i.e., width), in unit lengths.
+ *
+ * @return Horizontal length of a single pixel.
+ */
+ float32 getPixelLengthX() const;
+
+ /** Get the vertical length of a single pixel (i.e., height), in unit lengths.
+ *
+ * @return Vertical length of a single pixel.
+ */
+ float32 getPixelLengthY() const;
+
+ /** Get the area of a single pixel (width*height), in unit lengths squared.
+ *
+ * @return Area of a single pixel.
+ */
+ float32 getPixelArea() const;
+
+ /** Get the minimal X-coordinate in the volume window.
+ *
+ * @return Minimal X-coordinate in the volume window.
+ */
+ float32 getWindowMinX() const;
+
+ /** Get the minimal Y-coordinate in the volume window.
+ *
+ * @return Minimal Y-coordinate in the volume window.
+ */
+ float32 getWindowMinY() const;
+
+ /** Get the maximal X-coordinate in the volume window.
+ *
+ * @return Maximal X-coordinate in the volume window.
+ */
+ float32 getWindowMaxX() const;
+
+ /** Get the maximal Y-coordinate in the volume window.
+ *
+ * @return Maximal Y-coordinate in the volume window.
+ */
+ float32 getWindowMaxY() const;
+
+ /** Convert column and row index of a pixel to a single index in the interval [0..getGridTotCount()-1].
+ *
+ * @param _iPixelCol Column index of the pixel, in the interval [0..getGridColCount()-1].
+ * @param _iPixelRow Row index of the pixel, in the interval [0..getGridRowCount()-1].
+ * @return Computed index of the pixel, in the interval [0..getGridTotCount()-1].
+ */
+ int pixelRowColToIndex(int _iPixelRow, int _iPixelCol) const;
+
+ /** Convert a pixel index (from the interval [0..getGridTotCount()-1] to a column and row index.
+ *
+ * @param _iPixelIndex Index of the pixel, in the interval [0..getGridTotCount()-1].
+ * @param _iPixelRow Computed row index of the pixel, in the interval [0..getGridRowCount()-1].
+ * @param _iPixelCol Computed column index of the pixel, in the interval [0..getGridColCount()-1].
+ */
+ void pixelIndexToRowCol(int _iPixelIndex, int &_iPixelRow, int &_iPixelCol) const;
+
+ /** Convert a pixel column index to the X-coordinate of its center.
+ *
+ * @param _iPixelCol Column index of the pixel.
+ * @return X-coordinate of the pixel center.
+ */
+ float32 pixelColToCenterX(int _iPixelCol) const;
+
+ /** Convert a pixel column index to the minimum X-coordinate of points in that column.
+ *
+ * @param _iPixelCol Column index of the pixel.
+ * @return Minimum X-coordinate.
+ */
+ float32 pixelColToMinX(int _iPixelCol) const;
+
+ /** Convert a pixel column index to the maximum X-coordinate of points in that column.
+ *
+ * @param _iPixelCol Column index of the pixel.
+ * @return Maximum X-coordinate.
+ */
+ float32 pixelColToMaxX(int _iPixelCol) const;
+
+ /** Convert a pixel row index to the Y-coordinate of its center.
+ *
+ * @param _iPixelRow Row index of the pixel.
+ * @return Y-coordinate of the pixel center.
+ */
+ float32 pixelRowToCenterY(int _iPixelRow) const;
+
+ /** Convert a pixel row index to the minimum Y-coordinate of points in that row.
+ *
+ * @param _iPixelRow Row index of the pixel.
+ * @return Minimum Y-coordinate.
+ */
+ float32 pixelRowToMinY(int _iPixelRow) const;
+
+ /** Convert a pixel row index to the maximum Y-coordinate of points in that row.
+ *
+ * @param _iPixelRow Row index of the pixel.
+ * @return Maximum Y-coordinate.
+ */
+ float32 pixelRowToMaxY(int _iPixelRow) const;
+
+ /** Convert an X-coordinate to a column index in the volume grid.
+ *
+ * @param _fCoordX X-coordinate.
+ * @return If the X-coordinate falls within a column of the volume grid, the column index is returned.
+ * Otherwise, a value of -1 is returned.
+ */
+ int coordXToCol(float32 _fCoordX) const;
+
+ /** Convert a Y-coordinate to a row index in the volume grid.
+ *
+ * @param _fCoordY Y-coordinate
+ * @return If the Y-coordinate falls within a row of the volume grid, the row index is returned.
+ * Otherwise, a value of -1 is returned.
+ */
+ int coordYToRow(float32 _fCoordY) const;
+
+ /** Convert an X-coordinate to an offset in the volume grid.
+ * WindowMinX is converted to 0.
+ *
+ * @param _fCoordX X-coordinate.
+ * @return The corresponding offset in the volume grid
+ */
+ float coordXToColF(float32 _fCoordX) const;
+
+ /** Convert a Y-coordinate to an offset in the volume grid.
+ * WindowMaxY is converted to 0.
+ *
+ * @param _fCoordY Y-coordinate
+ * @return The corresponding offset in the volume grid
+ */
+ float coordYToRowF(float32 _fCoordY) const;
+
+
+ //< For Config unused argument checking
+ ConfigCheckData* configCheckData;
+ friend class ConfigStackCheck<CVolumeGeometry2D>;
+};
+
+
+
+// Get the initialization state of the object.
+inline bool CVolumeGeometry2D::isInitialized() const
+{
+ return m_bInitialized;
+}
+
+// Get the number of columns in the volume grid.
+inline int CVolumeGeometry2D::getGridColCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iGridColCount;
+}
+
+// Get the number of rows in the volume grid.
+inline int CVolumeGeometry2D::getGridRowCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iGridRowCount;
+}
+
+// Get the total number of pixels in the volume window.
+inline int CVolumeGeometry2D::getGridTotCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iGridTotCount;
+}
+
+// Get the horizontal length of the volume window, in unit lengths.
+inline float32 CVolumeGeometry2D::getWindowLengthX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowLengthX;
+}
+
+// Get the vertical length of the volume window, in unit lengths.
+inline float32 CVolumeGeometry2D::getWindowLengthY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowLengthY;
+}
+
+// Get the total area of the volume window, in unit lengths squared.
+inline float32 CVolumeGeometry2D::getWindowArea() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowArea;
+}
+
+// Get the horizontal length of a single pixel (i.e., width), in unit lengths.
+inline float32 CVolumeGeometry2D::getPixelLengthX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fPixelLengthX;
+}
+
+// Get the vertical length of a single pixel (i.e., height), in unit lengths.
+inline float32 CVolumeGeometry2D::getPixelLengthY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fPixelLengthY;
+}
+
+// Get the area of a single pixel (width*height), in unit lengths squared.
+inline float32 CVolumeGeometry2D::getPixelArea() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fPixelArea;
+}
+
+ // Get the minimal X-coordinate in the volume window.
+inline float32 CVolumeGeometry2D::getWindowMinX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMinX;
+}
+
+ // Get the minimal Y-coordinate in the volume window.
+inline float32 CVolumeGeometry2D::getWindowMinY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMinY;
+}
+
+ // Get the maximal X-coordinate in the volume window.
+inline float32 CVolumeGeometry2D::getWindowMaxX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMaxX;
+}
+
+ // Get the maximal Y-coordinate in the volume window.
+inline float32 CVolumeGeometry2D::getWindowMaxY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMaxY;
+}
+
+// Convert column and row index of a pixel to a single index in the interval [0..getGridCountTot()-1].
+inline int CVolumeGeometry2D::pixelRowColToIndex(int _iPixelRow, int _iPixelCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelCol >= 0);
+ ASTRA_ASSERT(_iPixelCol < m_iGridColCount);
+ ASTRA_ASSERT(_iPixelRow >= 0);
+ ASTRA_ASSERT(_iPixelRow < m_iGridRowCount);
+ return (_iPixelRow * m_iGridColCount + _iPixelCol);
+}
+
+
+// Convert a pixel index (from the interval [0..getGridCountTot()-1] to a column and row index.
+inline void CVolumeGeometry2D::pixelIndexToRowCol(int _iPixelIndex, int &_iPixelRow, int &_iPixelCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelIndex >= 0);
+ ASTRA_ASSERT(_iPixelIndex < m_iGridTotCount);
+
+ _iPixelCol = (_iPixelIndex % m_iGridColCount);
+ _iPixelRow = (_iPixelIndex / m_iGridColCount);
+}
+
+// Convert a pixel column index to the X-coordinate of its center
+inline float32 CVolumeGeometry2D::pixelColToCenterX(int _iPixelCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelCol >= 0);
+ ASTRA_ASSERT(_iPixelCol < m_iGridColCount);
+
+ return (m_fWindowMinX + (float32(_iPixelCol) + 0.5f) * m_fPixelLengthX);
+}
+
+// Convert a pixel column index to the minimum X-coordinate of points in that column
+inline float32 CVolumeGeometry2D::pixelColToMinX(int _iPixelCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelCol >= 0);
+ ASTRA_ASSERT(_iPixelCol < m_iGridColCount);
+
+ return (m_fWindowMinX + float32(_iPixelCol) * m_fPixelLengthX);
+}
+
+// Convert a pixel column index to the maximum X-coordinate of points in that column
+inline float32 CVolumeGeometry2D::pixelColToMaxX(int _iPixelCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelCol >= 0);
+ ASTRA_ASSERT(_iPixelCol < m_iGridColCount);
+
+ return (m_fWindowMinX + (float32(_iPixelCol) + 1.0f) * m_fPixelLengthX);
+}
+
+// Convert a pixel row index to the Y-coordinate of its center
+inline float32 CVolumeGeometry2D::pixelRowToCenterY(int _iPixelRow) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelRow >= 0);
+ ASTRA_ASSERT(_iPixelRow < m_iGridRowCount);
+
+ return (m_fWindowMaxY - (float32(_iPixelRow) + 0.5f) * m_fPixelLengthY);
+}
+
+// Convert a pixel row index to the minimum Y-coordinate of points in that row
+inline float32 CVolumeGeometry2D::pixelRowToMinY(int _iPixelRow) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelRow >= 0);
+ ASTRA_ASSERT(_iPixelRow < m_iGridRowCount);
+
+ return (m_fWindowMaxY - (float32(_iPixelRow) + 1.0f) * m_fPixelLengthY);
+}
+
+// Convert a pixel row index to the maximum Y-coordinate of points in that row
+inline float32 CVolumeGeometry2D::pixelRowToMaxY(int _iPixelRow) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelRow >= 0);
+ ASTRA_ASSERT(_iPixelRow < m_iGridRowCount);
+
+ return (m_fWindowMaxY - (float32(_iPixelRow) * m_fPixelLengthY));
+}
+
+// Convert an X-coordinate to a column index in the volume grid
+inline int CVolumeGeometry2D::coordXToCol(float32 _fCoordX) const
+{
+ if (_fCoordX < m_fWindowMinX) return -1;
+ if (_fCoordX > m_fWindowMaxX) return -1;
+
+ int iCol = int((_fCoordX - m_fWindowMinX) * m_fDivPixelLengthX);
+ ASTRA_ASSERT(iCol >= 0);
+ ASTRA_ASSERT(iCol < m_iGridColCount);
+
+ return iCol;
+}
+
+// Convert a Y-coordinate to a row index in the volume grid
+inline int CVolumeGeometry2D::coordYToRow(float32 _fCoordY) const
+{
+ if (_fCoordY < m_fWindowMinY) return -1;
+ if (_fCoordY > m_fWindowMaxY) return -1;
+
+ int iRow = int((m_fWindowMaxY - _fCoordY) * m_fDivPixelLengthY);
+ ASTRA_ASSERT(iRow >= 0);
+ ASTRA_ASSERT(iRow < m_iGridRowCount);
+
+ return iRow;
+}
+
+// Convert an X-coordinate to an offset in the volume grid
+// (WindowMinX is converted to 0)
+inline float CVolumeGeometry2D::coordXToColF(float32 _fCoordX) const
+{
+ return (_fCoordX - m_fWindowMinX) * m_fDivPixelLengthX;
+}
+
+// Convert a Y-coordinate to an offset in the volume grid
+// (WindowMaxY is converted to 0)
+inline float CVolumeGeometry2D::coordYToRowF(float32 _fCoordY) const
+{
+ return (m_fWindowMaxY - _fCoordY) * m_fDivPixelLengthY;
+}
+
+
+
+} // end namespace astra
+
+#endif /* _INC_ASTRA_VOLUMEGEOMETRY2D */
diff --git a/include/astra/VolumeGeometry3D.h b/include/astra/VolumeGeometry3D.h
new file mode 100644
index 0000000..4ca8042
--- /dev/null
+++ b/include/astra/VolumeGeometry3D.h
@@ -0,0 +1,842 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_VOLUMEGEOMETRY3D
+#define _INC_ASTRA_VOLUMEGEOMETRY3D
+
+#include "Globals.h"
+#include "Config.h"
+#include "VolumeGeometry2D.h"
+
+namespace astra
+{
+
+/**
+ * This class represents a 3D pixel grid that is placed in the geometry. It defines a rectangular volume window.
+ *
+ * \par XML Configuration
+ * \astra_xml_item{GridColCount, integer, Number of columns in this geometry.}
+ * \astra_xml_item{GridRowCount, integer, Number of rows in this geometry.}
+ * \astra_xml_item{GridSliceCount, integer, Number of slices in this geometry.}
+ * \astra_xml_item_option{WindowMinX, float, -GridColCount/2, Minimal X-coordinate in the volume window.}
+ * \astra_xml_item_option{WindowMaxX, float, GridColCount/2, Maximal X-coordinate in the volume window.}
+ * \astra_xml_item_option{WindowMinY, float, -GridRowCount/2, Minimal Y-coordinate in the volume window.}
+ * \astra_xml_item_option{WindowMaxY, float, GridRowCount/2, Maximal Y-coordinate in the volume window.}
+ * \astra_xml_item_option{WindowMinZ, float, -GridSliceCount/2, Minimal Z-coordinate in the volume window.}
+ * \astra_xml_item_option{WindowMaxZ, float, GridSliceCount/2, Maximal Z-coordinate in the volume window.}
+ *
+ * \par MATLAB example
+ * \astra_code{
+ * vol_geom = struct();\n
+ * vol_geom.GridColCount = 1024;\n
+ * vol_geom.GridRowCount = 768;\n
+ * vol_geom.GridSliceCount = 300;\n
+ * vol_geom.option.WindowMinX = -512;\n
+ * vol_geom.option.WindowMaxX = -384;\n
+ * vol_geom.option.WindowMinY = 512;\n
+ * vol_geom.option.WindowMaxY = 384;\n
+ * vol_geom.option.WindowMinZ = -150;\n
+ * vol_geom.option.WindowMaxZ = 150;\n
+ * }
+ */
+class _AstraExport CVolumeGeometry3D {
+
+protected:
+ bool m_bInitialized; ///< Has this object been initialized?
+
+ int m_iGridColCount; ///< number of columns in the volume grid.
+ int m_iGridRowCount; ///< number of rows in the volume grid.
+ int m_iGridSliceCount; ///< number of slices in the volume grid.
+ int m_iGridTotCount; ///< total number of pixels in the volume grid (= m_iGridColCount * m_iGridRowCount * m_iGridSliceCount).
+
+ /** Width of the volume window, in unit lengths.
+ *
+ * Note that this width is independent of the number of pixels in the X-direction, as the width of a pixel can
+ * be different from 1.
+ */
+ float32 m_fWindowLengthX;
+
+ /** Height of the volume window, in unit lengths.
+ *
+ * Note that this height is independent of the number of pixels in the Y-direction, as the height of a pixel can
+ * be different from 1.
+ */
+ float32 m_fWindowLengthY;
+
+ /** Depth of the volume window, in unit lengths.
+ *
+ * Note that this depth is independent of the number of pixels in the Z-direction, as the depth of a pixel can
+ * be different from 1.
+ */
+ float32 m_fWindowLengthZ;
+
+ /** Total area of the volume window, in unit lengths squared.
+ */
+ float32 m_fWindowArea;
+
+ float32 m_fPixelLengthX; ///< Width of a single pixel, in unit lengths.
+ float32 m_fPixelLengthY; ///< Height of a single pixel, in unit lengths.
+ float32 m_fPixelLengthZ; ///< Depth of a single pixel, in unit lengths.
+ float32 m_fPixelArea; ///< Area of a single pixel, in unit lengths squared.
+
+ float32 m_fDivPixelLengthX; ///< 1/m_fPixelLengthX, used for fast division.
+ float32 m_fDivPixelLengthY; ///< 1/m_fPixelLengthY, used for fast division.
+ float32 m_fDivPixelLengthZ; ///< 1/m_fPixelLengthZ, used for fast division.
+
+ float32 m_fWindowMinX; ///< Minimal X-coordinate in the volume window.
+ float32 m_fWindowMinY; ///< Minimal Y-coordinate in the volume window.
+ float32 m_fWindowMinZ; ///< Minimal Z-coordinate in the volume window.
+ float32 m_fWindowMaxX; ///< Maximal X-coordinate in the volume window.
+ float32 m_fWindowMaxY; ///< Maximal Y-coordinate in the volume window.
+ float32 m_fWindowMaxZ; ///< Maximal Z-coordinate in the volume window.
+
+ /** Check the values of this object. If everything is ok, the object can be set to the initialized state.
+ * The following statements are then guaranteed to hold:
+ * - number of rows, columns and slices is larger than zero
+ * - window minima is smaller than window maxima
+ * - m_iGridTotCount, m_fWindowLengthX, m_fWindowLengthY, m_fWindowLengthZ, m_fWindowArea, m_fPixelLengthX,
+ * m_fPixelLengthY, m_fPixelLengthZ, m_fPixelArea, m_fDivPixelLengthX, m_fDivPixelLengthY
+ * and m_fDivPixelLengthZ are initialized ok
+ */
+ bool _check();
+
+public:
+
+ /** Default constructor. Sets all numeric member variables to 0 and all pointer member variables to NULL.
+ *
+ * If an object is constructed using this default constructor, it must always be followed by a call
+ * to one of the init() methods before the object can be used. Any use before calling init() is not allowed,
+ * except calling the member function isInitialized().
+ */
+ CVolumeGeometry3D();
+
+ /** Constructor. Create an instance of the CVolumeGeometry2D class.
+ * The minimal and coordinates values of the geometry will be set to -/+ the number of rows/columns.
+ *
+ * @param _iGridCountX Number of columns in the volume grid.
+ * @param _iGridCountY Number of rows in the volume grid.
+ * @param _iGridCountZ Number of slices in the volume grid.
+ */
+ CVolumeGeometry3D(int _iGridCountX, int _iGridCountY, int _iGridCountZ);
+
+ /** Constructor. Create an instance of the CVolumeGeometry2D class.
+ *
+ * @param _iGridCountX Number of columns in the volume grid.
+ * @param _iGridCountY Number of rows in the volume grid.
+ * @param _iGridCountZ Number of slices in the volume grid.
+ * @param _fWindowMinX Minimal X-coordinate in the volume window.
+ * @param _fWindowMinY Minimal Y-coordinate in the volume window.
+ * @param _fWindowMinZ Minimal Z-coordinate in the volume window.
+ * @param _fWindowMaxX Maximal X-coordinate in the volume window.
+ * @param _fWindowMaxY Maximal Y-coordinate in the volume window.
+ * @param _fWindowMaxZ Maximal Z-coordinate in the volume window.
+ */
+ CVolumeGeometry3D(int _iGridCountX,
+ int _iGridCountY,
+ int _iGridCountZ,
+ float32 _fWindowMinX,
+ float32 _fWindowMinY,
+ float32 _fWindowMinZ,
+ float32 _fWindowMaxX,
+ float32 _fWindowMaxY,
+ float32 _fWindowMaxZ);
+
+ /**
+ * Copy constructor
+ */
+ CVolumeGeometry3D(const CVolumeGeometry3D& _other);
+
+ /**
+ * Assignment operator
+ */
+ CVolumeGeometry3D& operator=(const CVolumeGeometry3D& _other);
+
+ /** Destructor.
+ */
+ virtual ~CVolumeGeometry3D();
+
+ /** Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+ */
+ void clear();
+
+ /** Create a hard copy.
+ */
+ CVolumeGeometry3D* clone() const;
+
+ /** Initialize the volume geometry with a config object.
+ *
+ * @param _cfg Configuration Object.
+ * @return initialization successful?
+ */
+ virtual bool initialize(const Config& _cfg);
+
+ /** Initialization. Initializes an instance of the CVolumeGeometry3D class.
+ * The minimal and maximal coordinates of the geometry will be set to -/+ half the number of rows/columns/slices.
+ *
+ * If the object has been initialized before, the object is reinitialized and
+ * memory is freed and reallocated if necessary.
+ *
+ * @param _iGridColCount Number of columns in the volume grid.
+ * @param _iGridRowCount Number of rows in the volume grid.
+ * @param _iGridSliceCount Number of slices in the volume grid.
+ * @return initialization successful
+ */
+ bool initialize(int _iGridColCount, int _iGridRowCount, int _iGridSliceCount);
+
+ /** Initialization. Initializes an instance of the CVolumeGeometry3D class.
+ *
+ * If the object has been initialized before, the object is reinitialized and
+ * memory is freed and reallocated if necessary.
+ *
+ * @param _iGridColCount Number of columns in the volume grid.
+ * @param _iGridRowCount Number of rows in the volume grid.
+ * @param _iGridSliceCount Number of slices in the volume grid.
+ * @param _fWindowMinX Minimal X-coordinate in the volume window.
+ * @param _fWindowMinY Minimal Y-coordinate in the volume window.
+ * @param _fWindowMinZ Minimal Z-coordinate in the volume window.
+ * @param _fWindowMaxX Maximal X-coordinate in the volume window.
+ * @param _fWindowMaxY Maximal Y-coordinate in the volume window.
+ * @param _fWindowMaxZ Maximal Z-coordinate in the volume window.
+ * @return initialization successful
+ */
+ bool initialize(int _iGridColCount,
+ int _iGridRowCount,
+ int _iGridSliceCount,
+ float32 _fWindowMinX,
+ float32 _fWindowMinY,
+ float32 _fWindowMinZ,
+ float32 _fWindowMaxX,
+ float32 _fWindowMaxY,
+ float32 _fWindowMaxZ);
+
+ /** Get the initialization state of the object.
+ *
+ * @return true iff the object has been initialized.
+ */
+ bool isInitialized() const;
+
+ /** Return true if this geometry instance is the same as the one specified.
+ *
+ * @return true if this geometry instance is the same as the one specified.
+ */
+ virtual bool isEqual(const CVolumeGeometry3D*) const;
+
+ /** Get the number of columns in the volume grid.
+ *
+ * @return Number of columns in the volume grid.
+ */
+ int getGridColCount() const;
+
+ /** Get the number of rows in the volume grid.
+ *
+ * @return Number of rows in the volume grid.
+ */
+ int getGridRowCount() const;
+
+ /** Get the number of slices in the volume grid.
+ *
+ * @return Number of slices in the volume grid.
+ */
+ int getGridSliceCount() const;
+
+ /** Get the total number of pixels in the volume grid.
+ *
+ * @return Total number of pixels.
+ */
+ int getGridTotCount() const;
+
+ /** Get the horizontal length of the volume window, in unit lengths.
+ *
+ * @return Horizontal length of the volume window.
+ */
+ float32 getWindowLengthX() const;
+
+ /** Get the vertical length of the volume window, in unit lengths.
+ *
+ * @return Vertical length of the volume window.
+ */
+ float32 getWindowLengthY() const;
+
+ /** Get the depth of the volume window, in unit lengths.
+ *
+ * @return Depth of the volume window.
+ */
+ float32 getWindowLengthZ() const;
+
+ /** Get the total area of the volume window, in unit lengths squared.
+ *
+ * @return Total area of the volume window.
+ */
+ float32 getWindowArea() const;
+
+ /** Get the horizontal length of a single pixel (i.e., width), in unit lengths.
+ *
+ * @return Horizontal length of a single pixel.
+ */
+ float32 getPixelLengthX() const;
+
+ /** Get the vertical length of a single pixel (i.e., height), in unit lengths.
+ *
+ * @return Vertical length of a single pixel.
+ */
+ float32 getPixelLengthY() const;
+
+ /** Get the depth of a single pixel in unit lengths.
+ *
+ * @return Depth of a single pixel.
+ */
+ float32 getPixelLengthZ() const;
+
+ /** Get the area of a single pixel (width*height*depth), in unit lengths squared.
+ *
+ * @return Area of a single pixel.
+ */
+ float32 getPixelArea() const;
+
+ /** Get the minimal X-coordinate in the volume window.
+ *
+ * @return Minimal X-coordinate in the volume window.
+ */
+ float32 getWindowMinX() const;
+
+ /** Get the minimal Y-coordinate in the volume window.
+ *
+ * @return Minimal Y-coordinate in the volume window.
+ */
+ float32 getWindowMinY() const;
+
+ /** Get the minimal Z-coordinate in the volume window.
+ *
+ * @return Minimal Z-coordinate in the volume window.
+ */
+ float32 getWindowMinZ() const;
+
+ /** Get the maximal X-coordinate in the volume window.
+ *
+ * @return Maximal X-coordinate in the volume window.
+ */
+ float32 getWindowMaxX() const;
+
+ /** Get the maximal Y-coordinate in the volume window.
+ *
+ * @return Maximal Y-coordinate in the volume window.
+ */
+ float32 getWindowMaxY() const;
+
+ /** Get the maximal Z-coordinate in the volume window.
+ *
+ * @return Maximal Z-coordinate in the volume window.
+ */
+ float32 getWindowMaxZ() const;
+
+ /** Convert row, column and slice index of a pixel to a single index in the interval [0..getGridTotCount()-1].
+ *
+ * @param _iPixelRow Row index of the pixel, in the interval [0..getGridRowCount()-1].
+ * @param _iPixelCol Column index of the pixel, in the interval [0..getGridColCount()-1].
+ * @param _iPixelSlice Slice index of the pixel, in the interval [0..getGridSliceCount()-1].
+ * @return Computed index of the pixel, in the interval [0..getGridTotCount()-1].
+ */
+ int pixelRowColSliceToIndex(int _iPixelRow, int _iPixelCol, int _iPixelSlice) const;
+
+ /** Convert a pixel index (from the interval [0..getGridTotCount()-1] to row, column and slice index.
+ *
+ * @param _iPixelIndex Index of the pixel, in the interval [0..getGridTotCount()-1].
+ * @param _iPixelRow Computed row index of the pixel, in the interval [0..getGridRowCount()-1].
+ * @param _iPixelCol Computed column index of the pixel, in the interval [0..getGridColCount()-1].
+ * @param _iPixelSlice Computed slice index of the pixel, in the interval [0..getGridSliceCount()-1].
+ */
+ void pixelIndexToRowColSlice(int _iPixelIndex, int &_iPixelRow, int &_iPixelCol, int &_iPixelSlice) const;
+
+ /** Convert a pixel column index to the X-coordinate of its center.
+ *
+ * @param _iPixelCol Column index of the pixel.
+ * @return X-coordinate of the pixel center.
+ */
+ float32 pixelColToCenterX(int _iPixelCol) const;
+
+ /** Convert a pixel column index to the minimum X-coordinate of points in that column.
+ *
+ * @param _iPixelCol Column index of the pixel.
+ * @return Minimum X-coordinate.
+ */
+ float32 pixelColToMinX(int _iPixelCol) const;
+
+ /** Convert a pixel column index to the maximum X-coordinate of points in that column.
+ *
+ * @param _iPixelCol Column index of the pixel.
+ * @return Maximum X-coordinate.
+ */
+ float32 pixelColToMaxX(int _iPixelCol) const;
+
+ /** Convert a pixel row index to the Y-coordinate of its center.
+ *
+ * @param _iPixelRow Row index of the pixel.
+ * @return Y-coordinate of the pixel center.
+ */
+ float32 pixelRowToCenterY(int _iPixelRow) const;
+
+ /** Convert a pixel row index to the minimum Y-coordinate of points in that row.
+ *
+ * @param _iPixelRow Row index of the pixel.
+ * @return Minimum Y-coordinate.
+ */
+ float32 pixelRowToMinY(int _iPixelRow) const;
+
+ /** Convert a pixel row index to the maximum Y-coordinate of points in that row.
+ *
+ * @param _iPixelRow Row index of the pixel.
+ * @return Maximum Y-coordinate.
+ */
+ float32 pixelRowToMaxY(int _iPixelRow) const;
+
+ /** Convert a pixel slice index to the Z-coordinate of its center.
+ *
+ * @param _iPixelSlice Slice index of the pixel.
+ * @return Z-coordinate of the pixel center.
+ */
+ float32 pixelSliceToCenterZ(int _iPixelSlice) const;
+
+ /** Convert a pixel slice index to the minimum Z-coordinate of points in that slice.
+ *
+ * @param _iPixelSlice Slice index of the pixel.
+ * @return Minimum Z-coordinate.
+ */
+ float32 pixelSliceToMinZ(int _iPixelSlice) const;
+
+ /** Convert a pixel slice index to the maximum Z-coordinate of points in that slice.
+ *
+ * @param _iPixelSlice Slice index of the pixel.
+ * @return Maximum Z-coordinate.
+ */
+ float32 pixelSliceToMaxZ(int _iPixelSlice) const;
+
+ /** Convert an X-coordinate to a column index in the volume grid.
+ *
+ * @param _fCoordX X-coordinate.
+ * @return If the X-coordinate falls within a column of the volume grid, the column index is returned.
+ * Otherwise, a value of -1 is returned.
+ */
+ int coordXToCol(float32 _fCoordX) const;
+
+ /** Convert a Y-coordinate to a row index in the volume grid.
+ *
+ * @param _fCoordY Y-coordinate
+ * @return If the Y-coordinate falls within a row of the volume grid, the row index is returned.
+ * Otherwise, a value of -1 is returned.
+ */
+ int coordYToRow(float32 _fCoordY) const;
+
+ /** Convert a Z-coordinate to a slice index in the volume grid.
+ *
+ * @param _fCoordZ Z-coordinate
+ * @return If the Z-coordinate falls within a slice of the volume grid, the slice index is returned.
+ * Otherwise, a value of -1 is returned.
+ */
+ int coordZToSlice(float32 _fCoordZ) const;
+
+ /** Convert an X-coordinate to a column index in the volume grid.
+ *
+ * @param _fCoordX X-coordinate.
+ * @return If the X-coordinate falls within a column of the volume grid, the column index is returned.
+ * Otherwise, a value of -1 is returned.
+ */
+ float32 coordXToColFloat(float32 _fCoordX) const;
+
+ /** Convert a Y-coordinate to a row index in the volume grid.
+ *
+ * @param _fCoordY Y-coordinate
+ * @return If the Y-coordinate falls within a row of the volume grid, the row index is returned.
+ * Otherwise, a value of -1 is returned.
+ */
+ float32 coordYToRowFloat(float32 _fCoordY) const;
+
+ /** Convert a Z-coordinate to a slice index in the volume grid.
+ *
+ * @param _fCoordZ Z-coordinate
+ * @return If the Z-coordinate falls within a slice of the volume grid, the slice index is returned.
+ * Otherwise, a value of -1 is returned.
+ */
+ float32 coordZToSliceFloat(float32 _fCoordZ) const;
+
+ CVolumeGeometry2D * createVolumeGeometry2D() const;
+
+
+ //< For Config unused argument checking
+ ConfigCheckData* configCheckData;
+ friend class ConfigStackCheck<CVolumeGeometry3D>;
+};
+
+
+//----------------------------------------------------------------------------------------
+// Get the initialization state of the object.
+inline bool CVolumeGeometry3D::isInitialized() const
+{
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of columns in the volume grid.
+inline int CVolumeGeometry3D::getGridColCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iGridColCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of rows in the volume grid.
+inline int CVolumeGeometry3D::getGridRowCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iGridRowCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the number of rows in the volume grid.
+inline int CVolumeGeometry3D::getGridSliceCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iGridSliceCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the total number of pixels in the volume window.
+inline int CVolumeGeometry3D::getGridTotCount() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_iGridTotCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the horizontal length of the volume window, in unit lengths.
+inline float32 CVolumeGeometry3D::getWindowLengthX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowLengthX;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the vertical length of the volume window, in unit lengths.
+inline float32 CVolumeGeometry3D::getWindowLengthY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowLengthY;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the vertical length of the volume window, in unit lengths.
+inline float32 CVolumeGeometry3D::getWindowLengthZ() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowLengthZ;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the total area of the volume window, in unit lengths squared.
+inline float32 CVolumeGeometry3D::getWindowArea() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowArea;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the horizontal length of a single pixel (i.e., width), in unit lengths.
+inline float32 CVolumeGeometry3D::getPixelLengthX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fPixelLengthX;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the vertical length of a single pixel (i.e., height), in unit lengths.
+inline float32 CVolumeGeometry3D::getPixelLengthY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fPixelLengthY;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the depth of a single pixel in unit lengths.
+inline float32 CVolumeGeometry3D::getPixelLengthZ() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fPixelLengthZ;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the area of a single pixel (width*height), in unit lengths squared.
+inline float32 CVolumeGeometry3D::getPixelArea() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fPixelArea;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the minimal X-coordinate in the volume window.
+inline float32 CVolumeGeometry3D::getWindowMinX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMinX;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the minimal Y-coordinate in the volume window.
+inline float32 CVolumeGeometry3D::getWindowMinY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMinY;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the minimal Y-coordinate in the volume window.
+inline float32 CVolumeGeometry3D::getWindowMinZ() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMinZ;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the maximal X-coordinate in the volume window.
+inline float32 CVolumeGeometry3D::getWindowMaxX() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMaxX;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the maximal Y-coordinate in the volume window.
+inline float32 CVolumeGeometry3D::getWindowMaxY() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMaxY;
+}
+
+//----------------------------------------------------------------------------------------
+// Get the maximal Z-coordinate in the volume window.
+inline float32 CVolumeGeometry3D::getWindowMaxZ() const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return m_fWindowMaxZ;
+}
+
+//----------------------------------------------------------------------------------------
+// Convert row, column and slice index of a pixel to a single index in the interval [0..getGridCountTot()-1].
+inline int CVolumeGeometry3D::pixelRowColSliceToIndex(int _iPixelRow, int _iPixelCol, int _iPixelSlice) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelCol >= 0);
+ ASTRA_ASSERT(_iPixelCol < m_iGridColCount);
+ ASTRA_ASSERT(_iPixelRow >= 0);
+ ASTRA_ASSERT(_iPixelRow < m_iGridRowCount);
+ ASTRA_ASSERT(_iPixelSlice >= 0);
+ ASTRA_ASSERT(_iPixelSlice < m_iGridSliceCount);
+
+ return (m_iGridColCount*m_iGridRowCount*_iPixelSlice + _iPixelRow * m_iGridColCount + _iPixelCol);
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel index (from the interval [0..getGridCountTot()-1] to a row, column and slice index.
+inline void CVolumeGeometry3D::pixelIndexToRowColSlice(int _iPixelIndex, int &_iPixelRow, int &_iPixelCol, int &_iPixelSlice) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelIndex >= 0);
+ ASTRA_ASSERT(_iPixelIndex < m_iGridTotCount);
+
+ _iPixelSlice = _iPixelIndex / (m_iGridRowCount*m_iGridColCount);
+ _iPixelRow = (_iPixelIndex-_iPixelSlice*m_iGridRowCount*m_iGridColCount) / m_iGridColCount;
+ _iPixelCol = (_iPixelIndex-_iPixelSlice*m_iGridRowCount*m_iGridColCount) % m_iGridColCount;
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel column index to the X-coordinate of its center
+inline float32 CVolumeGeometry3D::pixelColToCenterX(int _iPixelCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelCol >= 0);
+ ASTRA_ASSERT(_iPixelCol < m_iGridColCount);
+
+ return (m_fWindowMinX + (float32(_iPixelCol) + 0.5f) * m_fPixelLengthX);
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel column index to the minimum X-coordinate of points in that column
+inline float32 CVolumeGeometry3D::pixelColToMinX(int _iPixelCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelCol >= 0);
+ ASTRA_ASSERT(_iPixelCol < m_iGridColCount);
+
+ return (m_fWindowMinX + float32(_iPixelCol) * m_fPixelLengthX);
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel column index to the maximum X-coordinate of points in that column
+inline float32 CVolumeGeometry3D::pixelColToMaxX(int _iPixelCol) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelCol >= 0);
+ ASTRA_ASSERT(_iPixelCol < m_iGridColCount);
+
+ return (m_fWindowMaxX + (float32(_iPixelCol) + 1.0f) * m_fPixelLengthX);
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel row index to the Y-coordinate of its center
+inline float32 CVolumeGeometry3D::pixelRowToCenterY(int _iPixelRow) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelRow >= 0);
+ ASTRA_ASSERT(_iPixelRow < m_iGridRowCount);
+
+ return (m_fWindowMaxY - (float32(_iPixelRow) + 0.5f) * m_fPixelLengthY);
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel row index to the minimum Y-coordinate of points in that row
+inline float32 CVolumeGeometry3D::pixelRowToMinY(int _iPixelRow) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelRow >= 0);
+ ASTRA_ASSERT(_iPixelRow < m_iGridRowCount);
+
+ return (m_fWindowMaxY - (float32(_iPixelRow) + 1.0f) * m_fPixelLengthY);
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel row index to the maximum Y-coordinate of points in that row
+inline float32 CVolumeGeometry3D::pixelRowToMaxY(int _iPixelRow) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelRow >= 0);
+ ASTRA_ASSERT(_iPixelRow < m_iGridRowCount);
+
+ return (m_fWindowMaxY - (float32(_iPixelRow) * m_fPixelLengthY));
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel slice index to the Z-coordinate of its center
+inline float32 CVolumeGeometry3D::pixelSliceToCenterZ(int _iPixelSlice) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelSlice >= 0);
+ ASTRA_ASSERT(_iPixelSlice < m_iGridSliceCount);
+
+ return (m_fWindowMaxZ - (float32(_iPixelSlice) + 0.5f) * m_fPixelLengthZ);
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel row index to the minimum Y-coordinate of points in that row
+inline float32 CVolumeGeometry3D::pixelSliceToMinZ(int _iPixelSlice) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelSlice >= 0);
+ ASTRA_ASSERT(_iPixelSlice < m_iGridSliceCount);
+
+ return (m_fWindowMaxZ - (float32(_iPixelSlice) + 1.0f) * m_fPixelLengthZ);
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a pixel row index to the maximum Y-coordinate of points in that row
+inline float32 CVolumeGeometry3D::pixelSliceToMaxZ(int _iPixelSlice) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_iPixelSlice >= 0);
+ ASTRA_ASSERT(_iPixelSlice < m_iGridSliceCount);
+
+ return (m_fWindowMaxZ - (float32(_iPixelSlice) * m_fPixelLengthZ));
+}
+
+//----------------------------------------------------------------------------------------
+// Convert an X-coordinate to a column index in the volume grid
+inline int CVolumeGeometry3D::coordXToCol(float32 _fCoordX) const
+{
+ if (_fCoordX < m_fWindowMinX) return -1;
+ if (_fCoordX > m_fWindowMaxX) return -1;
+
+ int iCol = int((_fCoordX - m_fWindowMinX) * m_fDivPixelLengthX);
+ ASTRA_ASSERT(iCol >= 0);
+ ASTRA_ASSERT(iCol < m_iGridColCount);
+
+ return iCol;
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a Y-coordinate to a row index in the volume grid
+inline int CVolumeGeometry3D::coordYToRow(float32 _fCoordY) const
+{
+ if (_fCoordY < m_fWindowMinY) return -1;
+ if (_fCoordY > m_fWindowMaxY) return -1;
+
+ int iRow = int((m_fWindowMaxY - _fCoordY) * m_fDivPixelLengthY);
+ ASTRA_ASSERT(iRow >= 0);
+ ASTRA_ASSERT(iRow < m_iGridRowCount);
+
+ return iRow;
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a Z-coordinate to a slice index in the volume grid
+inline int CVolumeGeometry3D::coordZToSlice(float32 _fCoordZ) const
+{
+ if (_fCoordZ < m_fWindowMinZ) return -1;
+ if (_fCoordZ > m_fWindowMaxZ) return -1;
+
+ int iSlice = int((m_fWindowMaxZ - _fCoordZ) * m_fDivPixelLengthZ);
+ ASTRA_ASSERT(iSlice >= 0);
+ ASTRA_ASSERT(iSlice < m_iGridSliceCount);
+
+ return iSlice;
+}
+
+//----------------------------------------------------------------------------------------
+// Convert an X-coordinate to a column index in the volume grid
+inline float32 CVolumeGeometry3D::coordXToColFloat(float32 _fCoordX) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return (_fCoordX - m_fWindowMinX) * m_fDivPixelLengthX;
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a Y-coordinate to a row index in the volume grid
+inline float32 CVolumeGeometry3D::coordYToRowFloat(float32 _fCoordY) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return (m_fWindowMaxY - _fCoordY) * m_fDivPixelLengthY;
+}
+
+//----------------------------------------------------------------------------------------
+// Convert a Z-coordinate to a slice index in the volume grid
+inline float32 CVolumeGeometry3D::coordZToSliceFloat(float32 _fCoordZ) const
+{
+ ASTRA_ASSERT(m_bInitialized);
+ return (m_fWindowMaxZ - _fCoordZ) * m_fDivPixelLengthZ;
+}
+//----------------------------------------------------------------------------------------
+
+} // end namespace astra
+
+#endif /* _INC_ASTRA_VOLUMEGEOMETRY2D */
diff --git a/include/astra/XMLDocument.h b/include/astra/XMLDocument.h
new file mode 100644
index 0000000..dbcc679
--- /dev/null
+++ b/include/astra/XMLDocument.h
@@ -0,0 +1,101 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_XMLDOCUMENT
+#define _INC_ASTRA_XMLDOCUMENT
+
+#include <string>
+
+#if 1
+namespace rapidxml {
+ template<class Ch> class xml_document;
+}
+#else
+#include "rapidxml.hpp"
+#endif
+
+#include "Globals.h"
+#include "XMLNode.h"
+
+using namespace std;
+
+namespace astra {
+
+/** This class encapsulates an XML Document of the Xerces DOM Parser.
+ */
+class _AstraExport XMLDocument {
+
+public:
+
+ /** Default Constructor
+ */
+ XMLDocument();
+
+ /** Destructor
+ */
+ ~XMLDocument();
+
+ /** Construct an XML DOM tree and Document from an XML file
+ *
+ * @param sFilename Location of the XML file.
+ * @return XML Document containing the DOM tree
+ */
+ static XMLDocument* readFromFile(string sFilename);
+
+ /** Construct an empty XML DOM tree with a specific root tag.
+ *
+ * @param sRootName Element name of the root tag.
+ * @return XML Document with an empty root node
+ */
+ static XMLDocument* createDocument(string sRootName);
+
+ /** Get the rootnode of the XML document
+ *
+ * @return first XML node of the document
+ */
+ XMLNode* getRootNode();
+
+ /** Save an XML DOM tree to an XML file
+ *
+ * @param sFilename Location of the XML file.
+ */
+ void saveToFile(string sFilename);
+
+
+private:
+
+ //!< Document of rapidxml
+ rapidxml::xml_document<char>* fDOMDocument;
+
+ std::string fBuf;
+
+};
+
+} // end namespace
+
+#endif
diff --git a/include/astra/XMLNode.h b/include/astra/XMLNode.h
new file mode 100644
index 0000000..3ed6417
--- /dev/null
+++ b/include/astra/XMLNode.h
@@ -0,0 +1,325 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_XMLNODE
+#define _INC_ASTRA_XMLNODE
+
+#include <list>
+#include <string>
+#include <vector>
+
+#if 1
+namespace rapidxml {
+ template<class Ch> class xml_node;
+}
+#else
+#include "rapidxml.hpp"
+#endif
+
+#include "Globals.h"
+#include "Utilities.h"
+
+using namespace std;
+
+namespace astra {
+
+/**
+ * This class encapsulates an XML Node of the Xerces DOM Parser.
+ */
+class _AstraExport XMLNode {
+
+friend class XMLDocument;
+
+public:
+
+ /** Default Constructor
+ */
+ XMLNode();
+
+ /** Deconstructor
+ */
+ ~XMLNode();
+
+
+ /** Get a single child XML node. If there are more, the first one is returned
+ *
+ * @param _sName tagname of the requested child node
+ * @return first child node with the correct tagname, null pointer if it doesn't exist
+ */
+ XMLNode* getSingleNode(string _sName);
+
+ /** Get all child XML nodes that have the tagname name
+ *
+ * @param _sName tagname of the requested child nodes
+ * @return list with all child nodes with the correct tagname
+ */
+ std::list<XMLNode*> getNodes(string _sName);
+
+ /** Get all child XML nodes
+ *
+ * @return list with all child nodes
+ */
+ std::list<XMLNode*> getNodes();
+
+ /** Get the name of this node
+ *
+ * @return name of node
+ */
+ std::string getName();
+
+ /** Get the content of the XML node as a single string.
+ *
+ * @return node content
+ */
+ string getContent();
+
+ /** Get the content of the XML node as a numerical.
+ *
+ * @return node content
+ */
+ float32 getContentNumerical();
+
+ /** Get the content of the XML node as a boolean.
+ *
+ * @return node content
+ */
+ bool getContentBool();
+
+ /** Get the content of the XML node as a vector of strings.
+ *
+ * @return node content
+ */
+ vector<string> getContentArray();
+
+ /** Get the content of the XML node as a c-array of float32 data.
+ *
+ * @param _pfData data array, shouldn't be initialized already.
+ * @param _iSize number of elements stored in _pfData
+ */
+ void getContentNumericalArray(float32*& _pfData, int& _iSize);
+
+ /** Get the content of the XML node as a stl container of float32 data.
+ *
+ * @return node content
+ */
+ vector<float32> getContentNumericalArray();
+ vector<double> getContentNumericalArrayDouble();
+
+
+
+ /** Does this node contain an attribute with a certain name?
+ *
+ * @param _sName of the attribute.
+ * @return attribute value, empty string if it doesn't exist.
+ */
+ bool hasAttribute(string _sName);
+
+ /** Get the value of an attribute.
+ *
+ * @param _sName of the attribute.
+ * @param _sDefaultValue value to return if the attribute isn't found
+ * @return attribute value, _sDefaultValue if it doesn't exist.
+ */
+ string getAttribute(string _sName, string _sDefaultValue = "");
+
+ /** Get the value of a numerical attribute.
+ *
+ * @param _sName of the attribute.
+ * @param _fDefaultValue value to return if the attribute isn't found
+ * @return attribute value, _fDefaultValue if it doesn't exist.
+ */
+ float32 getAttributeNumerical(string _sName, float32 _fDefaultValue = 0);
+ double getAttributeNumericalDouble(string _sName, double _fDefaultValue = 0);
+
+ /** Get the value of a boolean attribute.
+ *
+ * @param _sName of the attribute.
+ * @param _bDefaultValue value to return if the attribute isn't found
+ * @return attribute value, _bDefaultValue if it doesn't exist.
+ */
+ bool getAttributeBool(string _sName, bool _bDefaultValue = false);
+
+
+
+
+ /** Does this node contain an option with a certain key?
+ *
+ * @param _sKey option key
+ * @return true if option does exist
+ */
+ bool hasOption(string _sKey);
+
+ /** Get the value of an option within this XML Node
+ *
+ * @param _sKey option key
+ * @param _sDefaultValue value to return if key isn't found
+ * @return option value, _sDefaultValue if the option doesn't exist
+ */
+ string getOption(string _sKey, string _sDefaultValue = "");
+
+ /** Get the value of an option within this XML Node
+ *
+ * @param _sKey option key
+ * @param _fDefaultValue value to return if key isn't found
+ * @return option value, _fDefaultValue if the option doesn't exist
+ */
+ float32 getOptionNumerical(string _sKey, float32 _fDefaultValue = 0);
+
+ /** Get the value of an option within this XML Node
+ *
+ * @param _sKey option key
+ * @param _bDefaultValue value to return if key isn't found
+ * @return option value, _bDefaultValue if the option doesn't exist
+ */
+ bool getOptionBool(string _sKey, bool _bDefaultValue = false);
+
+ /** Get the value of an option within this XML Node
+ *
+ * @param _sKey option key
+ * @return numerical array
+ */
+ vector<float32> getOptionNumericalArray(string _sKey);
+
+
+
+
+
+ /** Create a new XML node as a child to this one: &lt;...&gt;&lt;_sNodeName/&gt;</...&gt;
+ *
+ * @param _sNodeName the name of the new childnode
+ * @return new child node
+ */
+ XMLNode* addChildNode(string _sNodeName);
+
+ /** Create a new XML node as a child to this one, also add some content:
+ * &lt;...&gt;&lt;_sNodeName&gt;_sValue&lt;/_sNodeName>&lt;/...&gt;
+ *
+ * @param _sNodeName the name of the new childnode
+ * @param _sValue some node content
+ * @return new child node
+ */
+ XMLNode* addChildNode(string _sNodeName, string _sValue);
+
+ /** Create a new XML node as a child to this one, also add some numerical content:
+ * &lt;...&gt;&lt;_sNodeName&gt;_sValue&lt;/_sNodeName>&lt;/...&gt;
+ *
+ * @param _sNodeName the name of the new childnode
+ * @param _fValue some node content
+ * @return new child node
+ */
+ XMLNode* addChildNode(string _sNodeName, float32 _fValue);
+
+ /** Create a new XML node as a child to this one, also add a list of numerical content:
+ * &lt;...&gt;&lt;_sNodeName&gt;_sValue&lt;/_sNodeName>&lt;/...&gt;
+ *
+ * @param _sNodeName the name of the new childnode
+ * @param _pfList list data
+ * @param _iSize number of elements in _pfList
+ * @return new child node
+ */
+ XMLNode* addChildNode(string _sNodeName, float32* _pfList, int _iSize);
+
+ /** Add some text to the node: &lt;...&gt;_sText&lt;/...&gt;
+ *
+ * @param _sText text to insert
+ */
+ void setContent(string _sText);
+
+ /** Add a number to the node: &lt;...&gt;_sText&lt;/...&gt;
+ *
+ * @param _fValue number to insert
+ */
+ void setContent(float32 _fValue);
+
+ /** Add a list of numerical data to the node: &lt;...&gt;_sText&lt;/...&gt;
+ *
+ * @param _pfList data
+ * @param _iSize number of elements in the list
+ */
+ void setContent(float32* _pfList, int _iSize);
+
+ /** Add an attribute to this node: &lt;... _sName="_sValue"&gt;
+ *
+ * @param _sName name of the attribute
+ * @param _sValue value of the attribute
+ */
+ void addAttribute(string _sName, string _sValue);
+
+ /** Add an attribute with numerical data to this node: &lt;... _sName="_fValue"&gt;
+ *
+ * @param _sName name of the attribute
+ * @param _sValue value of the attribute
+ */
+ void addAttribute(string _sName, float32 _fValue);
+
+ /** Add an option node as a child: &lt;Option key="&lt;_sKey&gt;" value="&lt;_sValue&gt;"/>
+ *
+ * @param _sKey option key
+ * @param _sValue option value
+ */
+ void addOption(string _sKey, string _sValue);
+
+ /** Add an option node as a child: &lt;Option key="&lt;_sKey&gt;" value="&lt;_sValue&gt;"/>
+ *
+ * @param _sKey option key
+ * @param _sValue option value
+ */
+ void addOption(string _sKey, float32 _fValue);
+
+
+ /** Print to String
+ */
+ std::string toString();
+
+ /** Print the node
+ */
+ void print();
+
+protected:
+
+ /** Private Constructor.
+ *
+ * @param n rapidxml node
+ */
+ XMLNode(rapidxml::xml_node<char>* n);
+
+ /** Link this object to a rapidxml node
+ * @param n object of the Xerces C++ library
+ */
+ void setDOMNode(rapidxml::xml_node<char>* n);
+
+ // todo: rename "fDOMElement" to "m_fDOMElement"?
+
+ //!< Node of rapidxml
+ rapidxml::xml_node<char>* fDOMElement;
+
+};
+
+} // end namespace
+
+#endif
diff --git a/include/astra/jama_wrapper.h b/include/astra/jama_wrapper.h
new file mode 100644
index 0000000..2fbdef8
--- /dev/null
+++ b/include/astra/jama_wrapper.h
@@ -0,0 +1,35 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+// Wrapper include for jama header files
+
+#ifdef JAMA_NO_SUBDIR
+#include "jama_lu.h"
+#else
+#include <tnt/jama_lu.h>
+#endif
diff --git a/include/astra/swrap.h b/include/astra/swrap.h
new file mode 100644
index 0000000..af45838
--- /dev/null
+++ b/include/astra/swrap.h
@@ -0,0 +1,41 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_SWRAP_H
+#define _INC_ASTRA_SWRAP_H
+
+#ifndef _MSC_VER
+
+#include <cstdio>
+
+typedef int errno_t;
+errno_t fopen_s(FILE** pFile, const char *filename, const char *mode);
+
+#endif
+
+#endif
diff --git a/lib/include/rapidxml/rapidxml.hpp b/lib/include/rapidxml/rapidxml.hpp
new file mode 100644
index 0000000..ae91e08
--- /dev/null
+++ b/lib/include/rapidxml/rapidxml.hpp
@@ -0,0 +1,2596 @@
+#ifndef RAPIDXML_HPP_INCLUDED
+#define RAPIDXML_HPP_INCLUDED
+
+// Copyright (C) 2006, 2009 Marcin Kalicinski
+// Version 1.13
+// Revision $DateTime: 2009/05/13 01:46:17 $
+//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation
+
+// If standard library is disabled, user must provide implementations of required functions and typedefs
+#if !defined(RAPIDXML_NO_STDLIB)
+ #include <cstdlib> // For std::size_t
+ #include <cassert> // For assert
+ #include <new> // For placement new
+#endif
+
+// On MSVC, disable "conditional expression is constant" warning (level 4).
+// This warning is almost impossible to avoid with certain types of templated code
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable:4127) // Conditional expression is constant
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+// RAPIDXML_PARSE_ERROR
+
+#if defined(RAPIDXML_NO_EXCEPTIONS)
+
+#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); }
+
+namespace rapidxml
+{
+ //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS,
+ //! this function is called to notify user about the error.
+ //! It must be defined by the user.
+ //! <br><br>
+ //! This function cannot return. If it does, the results are undefined.
+ //! <br><br>
+ //! A very simple definition might look like that:
+ //! <pre>
+ //! void %rapidxml::%parse_error_handler(const char *what, void *where)
+ //! {
+ //! std::cout << "Parse error: " << what << "\n";
+ //! std::abort();
+ //! }
+ //! </pre>
+ //! \param what Human readable description of the error.
+ //! \param where Pointer to character data where error was detected.
+ void parse_error_handler(const char *what, void *where);
+}
+
+#else
+
+#include <exception> // For std::exception
+
+#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where)
+
+namespace rapidxml
+{
+
+ //! Parse error exception.
+ //! This exception is thrown by the parser when an error occurs.
+ //! Use what() function to get human-readable error message.
+ //! Use where() function to get a pointer to position within source text where error was detected.
+ //! <br><br>
+ //! If throwing exceptions by the parser is undesirable,
+ //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included.
+ //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception.
+ //! This function must be defined by the user.
+ //! <br><br>
+ //! This class derives from <code>std::exception</code> class.
+ class parse_error: public std::exception
+ {
+
+ public:
+
+ //! Constructs parse error
+ parse_error(const char *what, void *where)
+ : m_what(what)
+ , m_where(where)
+ {
+ }
+
+ //! Gets human readable description of error.
+ //! \return Pointer to null terminated description of the error.
+ virtual const char *what() const throw()
+ {
+ return m_what;
+ }
+
+ //! Gets pointer to character data where error happened.
+ //! Ch should be the same as char type of xml_document that produced the error.
+ //! \return Pointer to location within the parsed string where error occured.
+ template<class Ch>
+ Ch *where() const
+ {
+ return reinterpret_cast<Ch *>(m_where);
+ }
+
+ private:
+
+ const char *m_what;
+ void *m_where;
+
+ };
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+// Pool sizes
+
+#ifndef RAPIDXML_STATIC_POOL_SIZE
+ // Size of static memory block of memory_pool.
+ // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
+ // No dynamic memory allocations are performed by memory_pool until static memory is exhausted.
+ #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
+#endif
+
+#ifndef RAPIDXML_DYNAMIC_POOL_SIZE
+ // Size of dynamic memory block of memory_pool.
+ // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
+ // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool.
+ #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
+#endif
+
+#ifndef RAPIDXML_ALIGNMENT
+ // Memory allocation alignment.
+ // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer.
+ // All memory allocations for nodes, attributes and strings will be aligned to this value.
+ // This must be a power of 2 and at least 1, otherwise memory_pool will not work.
+ #define RAPIDXML_ALIGNMENT sizeof(void *)
+#endif
+
+namespace rapidxml
+{
+ // Forward declarations
+ template<class Ch> class xml_node;
+ template<class Ch> class xml_attribute;
+ template<class Ch> class xml_document;
+
+ //! Enumeration listing all node types produced by the parser.
+ //! Use xml_node::type() function to query node type.
+ enum node_type
+ {
+ node_document, //!< A document node. Name and value are empty.
+ node_element, //!< An element node. Name contains element name. Value contains text of first data node.
+ node_data, //!< A data node. Name is empty. Value contains data text.
+ node_cdata, //!< A CDATA node. Name is empty. Value contains data text.
+ node_comment, //!< A comment node. Name is empty. Value contains comment text.
+ node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
+ node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
+ node_pi //!< A PI node. Name contains target. Value contains instructions.
+ };
+
+ ///////////////////////////////////////////////////////////////////////
+ // Parsing flags
+
+ //! Parse flag instructing the parser to not create data nodes.
+ //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_no_data_nodes = 0x1;
+
+ //! Parse flag instructing the parser to not use text of first data node as a value of parent element.
+ //! Can be combined with other flags by use of | operator.
+ //! Note that child data nodes of element node take precendence over its value when printing.
+ //! That is, if element has one or more child data nodes <em>and</em> a value, the value will be ignored.
+ //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_no_element_values = 0x2;
+
+ //! Parse flag instructing the parser to not place zero terminators after strings in the source text.
+ //! By default zero terminators are placed, modifying source text.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_no_string_terminators = 0x4;
+
+ //! Parse flag instructing the parser to not translate entities in the source text.
+ //! By default entities are translated, modifying source text.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_no_entity_translation = 0x8;
+
+ //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters.
+ //! By default, UTF-8 handling is enabled.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_no_utf8 = 0x10;
+
+ //! Parse flag instructing the parser to create XML declaration node.
+ //! By default, declaration node is not created.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_declaration_node = 0x20;
+
+ //! Parse flag instructing the parser to create comments nodes.
+ //! By default, comment nodes are not created.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_comment_nodes = 0x40;
+
+ //! Parse flag instructing the parser to create DOCTYPE node.
+ //! By default, doctype node is not created.
+ //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_doctype_node = 0x80;
+
+ //! Parse flag instructing the parser to create PI nodes.
+ //! By default, PI nodes are not created.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_pi_nodes = 0x100;
+
+ //! Parse flag instructing the parser to validate closing tag names.
+ //! If not set, name inside closing tag is irrelevant to the parser.
+ //! By default, closing tags are not validated.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_validate_closing_tags = 0x200;
+
+ //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes.
+ //! By default, whitespace is not trimmed.
+ //! This flag does not cause the parser to modify source text.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_trim_whitespace = 0x400;
+
+ //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character.
+ //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag.
+ //! By default, whitespace is not normalized.
+ //! If this flag is specified, source text will be modified.
+ //! Can be combined with other flags by use of | operator.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_normalize_whitespace = 0x800;
+
+ // Compound flags
+
+ //! Parse flags which represent default behaviour of the parser.
+ //! This is always equal to 0, so that all other flags can be simply ored together.
+ //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values.
+ //! This also means that meaning of each flag is a <i>negation</i> of the default setting.
+ //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by default,
+ //! and using the flag will disable it.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_default = 0;
+
+ //! A combination of parse flags that forbids any modifications of the source text.
+ //! This also results in faster parsing. However, note that the following will occur:
+ //! <ul>
+ //! <li>names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends</li>
+ //! <li>entities will not be translated</li>
+ //! <li>whitespace will not be normalized</li>
+ //! </ul>
+ //! See xml_document::parse() function.
+ const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation;
+
+ //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_fastest = parse_non_destructive | parse_no_data_nodes;
+
+ //! A combination of parse flags resulting in largest amount of data being extracted.
+ //! This usually results in slowest parsing.
+ //! <br><br>
+ //! See xml_document::parse() function.
+ const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags;
+
+ ///////////////////////////////////////////////////////////////////////
+ // Internals
+
+ //! \cond internal
+ namespace internal
+ {
+
+ // Struct that contains lookup tables for the parser
+ // It must be a template to allow correct linking (because it has static data members, which are defined in a header file).
+ template<int Dummy>
+ struct lookup_tables
+ {
+ static const unsigned char lookup_whitespace[256]; // Whitespace table
+ static const unsigned char lookup_node_name[256]; // Node name table
+ static const unsigned char lookup_text[256]; // Text table
+ static const unsigned char lookup_text_pure_no_ws[256]; // Text table
+ static const unsigned char lookup_text_pure_with_ws[256]; // Text table
+ static const unsigned char lookup_attribute_name[256]; // Attribute name table
+ static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote
+ static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote
+ static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes
+ static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes
+ static const unsigned char lookup_digits[256]; // Digits
+ static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters
+ };
+
+ // Find length of the string
+ template<class Ch>
+ inline std::size_t measure(const Ch *p)
+ {
+ const Ch *tmp = p;
+ while (*tmp)
+ ++tmp;
+ return tmp - p;
+ }
+
+ // Compare strings for equality
+ template<class Ch>
+ inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive)
+ {
+ if (size1 != size2)
+ return false;
+ if (case_sensitive)
+ {
+ for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
+ if (*p1 != *p2)
+ return false;
+ }
+ else
+ {
+ for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
+ if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] != lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)])
+ return false;
+ }
+ return true;
+ }
+ }
+ //! \endcond
+
+ ///////////////////////////////////////////////////////////////////////
+ // Memory pool
+
+ //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation.
+ //! In most cases, you will not need to use this class directly.
+ //! However, if you need to create nodes manually or modify names/values of nodes,
+ //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory.
+ //! Not only is this faster than allocating them by using <code>new</code> operator,
+ //! but also their lifetime will be tied to the lifetime of document,
+ //! possibly simplyfing memory management.
+ //! <br><br>
+ //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool.
+ //! You can also call allocate_string() function to allocate strings.
+ //! Such strings can then be used as names or values of nodes without worrying about their lifetime.
+ //! Note that there is no <code>free()</code> function -- all allocations are freed at once when clear() function is called,
+ //! or when the pool is destroyed.
+ //! <br><br>
+ //! It is also possible to create a standalone memory_pool, and use it
+ //! to allocate nodes, whose lifetime will not be tied to any document.
+ //! <br><br>
+ //! Pool maintains <code>RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory.
+ //! Until static memory is exhausted, no dynamic memory allocations are done.
+ //! When static memory is exhausted, pool allocates additional blocks of memory of size <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> each,
+ //! by using global <code>new[]</code> and <code>delete[]</code> operators.
+ //! This behaviour can be changed by setting custom allocation routines.
+ //! Use set_allocator() function to set them.
+ //! <br><br>
+ //! Allocations for nodes, attributes and strings are aligned at <code>RAPIDXML_ALIGNMENT</code> bytes.
+ //! This value defaults to the size of pointer on target architecture.
+ //! <br><br>
+ //! To obtain absolutely top performance from the parser,
+ //! it is important that all nodes are allocated from a single, contiguous block of memory.
+ //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably.
+ //! If required, you can tweak <code>RAPIDXML_STATIC_POOL_SIZE</code>, <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>RAPIDXML_ALIGNMENT</code>
+ //! to obtain best wasted memory to performance compromise.
+ //! To do it, define their values before rapidxml.hpp file is included.
+ //! \param Ch Character type of created nodes.
+ template<class Ch = char>
+ class memory_pool
+ {
+
+ public:
+
+ //! \cond internal
+ typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory
+ typedef void (free_func)(void *); // Type of user-defined function used to free memory
+ //! \endcond
+
+ //! Constructs empty pool with default allocator functions.
+ memory_pool()
+ : m_alloc_func(0)
+ , m_free_func(0)
+ {
+ init();
+ }
+
+ //! Destroys pool and frees all the memory.
+ //! This causes memory occupied by nodes allocated by the pool to be freed.
+ //! Nodes allocated from the pool are no longer valid.
+ ~memory_pool()
+ {
+ clear();
+ }
+
+ //! Allocates a new node from the pool, and optionally assigns name and value to it.
+ //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+ //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+ //! will call rapidxml::parse_error_handler() function.
+ //! \param type Type of node to create.
+ //! \param name Name to assign to the node, or 0 to assign no name.
+ //! \param value Value to assign to the node, or 0 to assign no value.
+ //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
+ //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
+ //! \return Pointer to allocated node. This pointer will never be NULL.
+ xml_node<Ch> *allocate_node(node_type type,
+ const Ch *name = 0, const Ch *value = 0,
+ std::size_t name_size = 0, std::size_t value_size = 0)
+ {
+ void *memory = allocate_aligned(sizeof(xml_node<Ch>));
+ xml_node<Ch> *node = new(memory) xml_node<Ch>(type);
+ if (name)
+ {
+ if (name_size > 0)
+ node->name(name, name_size);
+ else
+ node->name(name);
+ }
+ if (value)
+ {
+ if (value_size > 0)
+ node->value(value, value_size);
+ else
+ node->value(value);
+ }
+ return node;
+ }
+
+ //! Allocates a new attribute from the pool, and optionally assigns name and value to it.
+ //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+ //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+ //! will call rapidxml::parse_error_handler() function.
+ //! \param name Name to assign to the attribute, or 0 to assign no name.
+ //! \param value Value to assign to the attribute, or 0 to assign no value.
+ //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
+ //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
+ //! \return Pointer to allocated attribute. This pointer will never be NULL.
+ xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0,
+ std::size_t name_size = 0, std::size_t value_size = 0)
+ {
+ void *memory = allocate_aligned(sizeof(xml_attribute<Ch>));
+ xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>;
+ if (name)
+ {
+ if (name_size > 0)
+ attribute->name(name, name_size);
+ else
+ attribute->name(name);
+ }
+ if (value)
+ {
+ if (value_size > 0)
+ attribute->value(value, value_size);
+ else
+ attribute->value(value);
+ }
+ return attribute;
+ }
+
+ //! Allocates a char array of given size from the pool, and optionally copies a given string to it.
+ //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
+ //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
+ //! will call rapidxml::parse_error_handler() function.
+ //! \param source String to initialize the allocated memory with, or 0 to not initialize it.
+ //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.
+ //! \return Pointer to allocated char array. This pointer will never be NULL.
+ Ch *allocate_string(const Ch *source = 0, std::size_t size = 0)
+ {
+ assert(source || size); // Either source or size (or both) must be specified
+ if (size == 0)
+ size = internal::measure(source) + 1;
+ Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch)));
+ if (source)
+ for (std::size_t i = 0; i < size; ++i)
+ result[i] = source[i];
+ return result;
+ }
+
+ //! Clones an xml_node and its hierarchy of child nodes and attributes.
+ //! Nodes and attributes are allocated from this memory pool.
+ //! Names and values are not cloned, they are shared between the clone and the source.
+ //! Result node can be optionally specified as a second parameter,
+ //! in which case its contents will be replaced with cloned source node.
+ //! This is useful when you want to clone entire document.
+ //! \param source Node to clone.
+ //! \param result Node to put results in, or 0 to automatically allocate result node
+ //! \return Pointer to cloned node. This pointer will never be NULL.
+ xml_node<Ch> *clone_node(const xml_node<Ch> *source, xml_node<Ch> *result = 0)
+ {
+ // Prepare result node
+ if (result)
+ {
+ result->remove_all_attributes();
+ result->remove_all_nodes();
+ result->type(source->type());
+ }
+ else
+ result = allocate_node(source->type());
+
+ // Clone name and value
+ result->name(source->name(), source->name_size());
+ result->value(source->value(), source->value_size());
+
+ // Clone child nodes and attributes
+ for (xml_node<Ch> *child = source->first_node(); child; child = child->next_sibling())
+ result->append_node(clone_node(child));
+ for (xml_attribute<Ch> *attr = source->first_attribute(); attr; attr = attr->next_attribute())
+ result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size()));
+
+ return result;
+ }
+
+ //! Clears the pool.
+ //! This causes memory occupied by nodes allocated by the pool to be freed.
+ //! Any nodes or strings allocated from the pool will no longer be valid.
+ void clear()
+ {
+ while (m_begin != m_static_memory)
+ {
+ char *previous_begin = reinterpret_cast<header *>(align(m_begin))->previous_begin;
+ if (m_free_func)
+ m_free_func(m_begin);
+ else
+ delete[] m_begin;
+ m_begin = previous_begin;
+ }
+ init();
+ }
+
+ //! Sets or resets the user-defined memory allocation functions for the pool.
+ //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined.
+ //! Allocation function must not return invalid pointer on failure. It should either throw,
+ //! stop the program, or use <code>longjmp()</code> function to pass control to other place of program.
+ //! If it returns invalid pointer, results are undefined.
+ //! <br><br>
+ //! User defined allocation functions must have the following forms:
+ //! <br><code>
+ //! <br>void *allocate(std::size_t size);
+ //! <br>void free(void *pointer);
+ //! </code><br>
+ //! \param af Allocation function, or 0 to restore default function
+ //! \param ff Free function, or 0 to restore default function
+ void set_allocator(alloc_func *af, free_func *ff)
+ {
+ assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet
+ m_alloc_func = af;
+ m_free_func = ff;
+ }
+
+ private:
+
+ struct header
+ {
+ char *previous_begin;
+ };
+
+ void init()
+ {
+ m_begin = m_static_memory;
+ m_ptr = align(m_begin);
+ m_end = m_static_memory + sizeof(m_static_memory);
+ }
+
+ char *align(char *ptr)
+ {
+ std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1));
+ return ptr + alignment;
+ }
+
+ char *allocate_raw(std::size_t size)
+ {
+ // Allocate
+ void *memory;
+ if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[]
+ {
+ memory = m_alloc_func(size);
+ assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp
+ }
+ else
+ {
+ memory = new char[size];
+#ifdef RAPIDXML_NO_EXCEPTIONS
+ if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc
+ RAPIDXML_PARSE_ERROR("out of memory", 0);
+#endif
+ }
+ return static_cast<char *>(memory);
+ }
+
+ void *allocate_aligned(std::size_t size)
+ {
+ // Calculate aligned pointer
+ char *result = align(m_ptr);
+
+ // If not enough memory left in current pool, allocate a new pool
+ if (result + size > m_end)
+ {
+ // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE)
+ std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE;
+ if (pool_size < size)
+ pool_size = size;
+
+ // Allocate
+ std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation
+ char *raw_memory = allocate_raw(alloc_size);
+
+ // Setup new pool in allocated memory
+ char *pool = align(raw_memory);
+ header *new_header = reinterpret_cast<header *>(pool);
+ new_header->previous_begin = m_begin;
+ m_begin = raw_memory;
+ m_ptr = pool + sizeof(header);
+ m_end = raw_memory + alloc_size;
+
+ // Calculate aligned pointer again using new pool
+ result = align(m_ptr);
+ }
+
+ // Update pool and return aligned pointer
+ m_ptr = result + size;
+ return result;
+ }
+
+ char *m_begin; // Start of raw memory making up current pool
+ char *m_ptr; // First free byte in current pool
+ char *m_end; // One past last available byte in current pool
+ char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory
+ alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used
+ free_func *m_free_func; // Free function, or 0 if default is to be used
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ // XML base
+
+ //! Base class for xml_node and xml_attribute implementing common functions:
+ //! name(), name_size(), value(), value_size() and parent().
+ //! \param Ch Character type to use
+ template<class Ch = char>
+ class xml_base
+ {
+
+ public:
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Construction & destruction
+
+ // Construct a base with empty name, value and parent
+ xml_base()
+ : m_name(0)
+ , m_value(0)
+ , m_parent(0)
+ {
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Node data access
+
+ //! Gets name of the node.
+ //! Interpretation of name depends on type of node.
+ //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
+ //! <br><br>
+ //! Use name_size() function to determine length of the name.
+ //! \return Name of node, or empty string if node has no name.
+ Ch *name() const
+ {
+ return m_name ? m_name : nullstr();
+ }
+
+ //! Gets size of node name, not including terminator character.
+ //! This function works correctly irrespective of whether name is or is not zero terminated.
+ //! \return Size of node name, in characters.
+ std::size_t name_size() const
+ {
+ return m_name ? m_name_size : 0;
+ }
+
+ //! Gets value of node.
+ //! Interpretation of value depends on type of node.
+ //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
+ //! <br><br>
+ //! Use value_size() function to determine length of the value.
+ //! \return Value of node, or empty string if node has no value.
+ Ch *value() const
+ {
+ return m_value ? m_value : nullstr();
+ }
+
+ //! Gets size of node value, not including terminator character.
+ //! This function works correctly irrespective of whether value is or is not zero terminated.
+ //! \return Size of node value, in characters.
+ std::size_t value_size() const
+ {
+ return m_value ? m_value_size : 0;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Node modification
+
+ //! Sets name of node to a non zero-terminated string.
+ //! See \ref ownership_of_strings.
+ //! <br><br>
+ //! Note that node does not own its name or value, it only stores a pointer to it.
+ //! It will not delete or otherwise free the pointer on destruction.
+ //! It is reponsibility of the user to properly manage lifetime of the string.
+ //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
+ //! on destruction of the document the string will be automatically freed.
+ //! <br><br>
+ //! Size of name must be specified separately, because name does not have to be zero terminated.
+ //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).
+ //! \param name Name of node to set. Does not have to be zero terminated.
+ //! \param size Size of name, in characters. This does not include zero terminator, if one is present.
+ void name(const Ch *name, std::size_t size)
+ {
+ m_name = const_cast<Ch *>(name);
+ m_name_size = size;
+ }
+
+ //! Sets name of node to a zero-terminated string.
+ //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t).
+ //! \param name Name of node to set. Must be zero terminated.
+ void name(const Ch *name)
+ {
+ this->name(name, internal::measure(name));
+ }
+
+ //! Sets value of node to a non zero-terminated string.
+ //! See \ref ownership_of_strings.
+ //! <br><br>
+ //! Note that node does not own its name or value, it only stores a pointer to it.
+ //! It will not delete or otherwise free the pointer on destruction.
+ //! It is reponsibility of the user to properly manage lifetime of the string.
+ //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
+ //! on destruction of the document the string will be automatically freed.
+ //! <br><br>
+ //! Size of value must be specified separately, because it does not have to be zero terminated.
+ //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).
+ //! <br><br>
+ //! If an element has a child node of type node_data, it will take precedence over element value when printing.
+ //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.
+ //! \param value value of node to set. Does not have to be zero terminated.
+ //! \param size Size of value, in characters. This does not include zero terminator, if one is present.
+ void value(const Ch *value, std::size_t size)
+ {
+ m_value = const_cast<Ch *>(value);
+ m_value_size = size;
+ }
+
+ //! Sets value of node to a zero-terminated string.
+ //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t).
+ //! \param value Vame of node to set. Must be zero terminated.
+ void value(const Ch *value)
+ {
+ this->value(value, internal::measure(value));
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Related nodes access
+
+ //! Gets node parent.
+ //! \return Pointer to parent node, or 0 if there is no parent.
+ xml_node<Ch> *parent() const
+ {
+ return m_parent;
+ }
+
+ protected:
+
+ // Return empty string
+ static Ch *nullstr()
+ {
+ static Ch zero = Ch('\0');
+ return &zero;
+ }
+
+ Ch *m_name; // Name of node, or 0 if no name
+ Ch *m_value; // Value of node, or 0 if no value
+ std::size_t m_name_size; // Length of node name, or undefined of no name
+ std::size_t m_value_size; // Length of node value, or undefined if no value
+ xml_node<Ch> *m_parent; // Pointer to parent node, or 0 if none
+
+ };
+
+ //! Class representing attribute node of XML document.
+ //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base).
+ //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing.
+ //! Thus, this text must persist in memory for the lifetime of attribute.
+ //! \param Ch Character type to use.
+ template<class Ch = char>
+ class xml_attribute: public xml_base<Ch>
+ {
+
+ friend class xml_node<Ch>;
+
+ public:
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Construction & destruction
+
+ //! Constructs an empty attribute with the specified type.
+ //! Consider using memory_pool of appropriate xml_document if allocating attributes manually.
+ xml_attribute()
+ {
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Related nodes access
+
+ //! Gets document of which attribute is a child.
+ //! \return Pointer to document that contains this attribute, or 0 if there is no parent document.
+ xml_document<Ch> *document() const
+ {
+ if (xml_node<Ch> *node = this->parent())
+ {
+ while (node->parent())
+ node = node->parent();
+ return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
+ }
+ else
+ return 0;
+ }
+
+ //! Gets previous attribute, optionally matching attribute name.
+ //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+ //! \return Pointer to found attribute, or 0 if not found.
+ xml_attribute<Ch> *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+ {
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute)
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+ return attribute;
+ return 0;
+ }
+ else
+ return this->m_parent ? m_prev_attribute : 0;
+ }
+
+ //! Gets next attribute, optionally matching attribute name.
+ //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+ //! \return Pointer to found attribute, or 0 if not found.
+ xml_attribute<Ch> *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+ {
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute)
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+ return attribute;
+ return 0;
+ }
+ else
+ return this->m_parent ? m_next_attribute : 0;
+ }
+
+ private:
+
+ xml_attribute<Ch> *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero
+ xml_attribute<Ch> *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero
+
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ // XML node
+
+ //! Class representing a node of XML document.
+ //! Each node may have associated name and value strings, which are available through name() and value() functions.
+ //! Interpretation of name and value depends on type of the node.
+ //! Type of node can be determined by using type() function.
+ //! <br><br>
+ //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing.
+ //! Thus, this text must persist in the memory for the lifetime of node.
+ //! \param Ch Character type to use.
+ template<class Ch = char>
+ class xml_node: public xml_base<Ch>
+ {
+
+ public:
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Construction & destruction
+
+ //! Constructs an empty node with the specified type.
+ //! Consider using memory_pool of appropriate document to allocate nodes manually.
+ //! \param type Type of node to construct.
+ xml_node(node_type type)
+ : m_type(type)
+ , m_first_node(0)
+ , m_first_attribute(0)
+ {
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Node data access
+
+ //! Gets type of node.
+ //! \return Type of node.
+ node_type type() const
+ {
+ return m_type;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Related nodes access
+
+ //! Gets document of which node is a child.
+ //! \return Pointer to document that contains this node, or 0 if there is no parent document.
+ xml_document<Ch> *document() const
+ {
+ xml_node<Ch> *node = const_cast<xml_node<Ch> *>(this);
+ while (node->parent())
+ node = node->parent();
+ return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
+ }
+
+ //! Gets first child node, optionally matching node name.
+ //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+ //! \return Pointer to found child, or 0 if not found.
+ xml_node<Ch> *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+ {
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling())
+ if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
+ return child;
+ return 0;
+ }
+ else
+ return m_first_node;
+ }
+
+ //! Gets last child node, optionally matching node name.
+ //! Behaviour is undefined if node has no children.
+ //! Use first_node() to test if node has children.
+ //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+ //! \return Pointer to found child, or 0 if not found.
+ xml_node<Ch> *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+ {
+ assert(m_first_node); // Cannot query for last child if node has no children
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling())
+ if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
+ return child;
+ return 0;
+ }
+ else
+ return m_last_node;
+ }
+
+ //! Gets previous sibling node, optionally matching node name.
+ //! Behaviour is undefined if node has no parent.
+ //! Use parent() to test if node has a parent.
+ //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+ //! \return Pointer to found sibling, or 0 if not found.
+ xml_node<Ch> *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+ {
+ assert(this->m_parent); // Cannot query for siblings if node has no parent
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling)
+ if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
+ return sibling;
+ return 0;
+ }
+ else
+ return m_prev_sibling;
+ }
+
+ //! Gets next sibling node, optionally matching node name.
+ //! Behaviour is undefined if node has no parent.
+ //! Use parent() to test if node has a parent.
+ //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+ //! \return Pointer to found sibling, or 0 if not found.
+ xml_node<Ch> *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+ {
+ assert(this->m_parent); // Cannot query for siblings if node has no parent
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
+ if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
+ return sibling;
+ return 0;
+ }
+ else
+ return m_next_sibling;
+ }
+
+ //! Gets first attribute of node, optionally matching attribute name.
+ //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+ //! \return Pointer to found attribute, or 0 if not found.
+ xml_attribute<Ch> *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+ {
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute)
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+ return attribute;
+ return 0;
+ }
+ else
+ return m_first_attribute;
+ }
+
+ //! Gets last attribute of node, optionally matching attribute name.
+ //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
+ //! \return Pointer to found attribute, or 0 if not found.
+ xml_attribute<Ch> *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
+ {
+ if (name)
+ {
+ if (name_size == 0)
+ name_size = internal::measure(name);
+ for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute)
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
+ return attribute;
+ return 0;
+ }
+ else
+ return m_first_attribute ? m_last_attribute : 0;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Node modification
+
+ //! Sets type of node.
+ //! \param type Type of node to set.
+ void type(node_type type)
+ {
+ m_type = type;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Node manipulation
+
+ //! Prepends a new child node.
+ //! The prepended child becomes the first child, and all existing children are moved one position back.
+ //! \param child Node to prepend.
+ void prepend_node(xml_node<Ch> *child)
+ {
+ assert(child && !child->parent() && child->type() != node_document);
+ if (first_node())
+ {
+ child->m_next_sibling = m_first_node;
+ m_first_node->m_prev_sibling = child;
+ }
+ else
+ {
+ child->m_next_sibling = 0;
+ m_last_node = child;
+ }
+ m_first_node = child;
+ child->m_parent = this;
+ child->m_prev_sibling = 0;
+ }
+
+ //! Appends a new child node.
+ //! The appended child becomes the last child.
+ //! \param child Node to append.
+ void append_node(xml_node<Ch> *child)
+ {
+ assert(child && !child->parent() && child->type() != node_document);
+ if (first_node())
+ {
+ child->m_prev_sibling = m_last_node;
+ m_last_node->m_next_sibling = child;
+ }
+ else
+ {
+ child->m_prev_sibling = 0;
+ m_first_node = child;
+ }
+ m_last_node = child;
+ child->m_parent = this;
+ child->m_next_sibling = 0;
+ }
+
+ //! Inserts a new child node at specified place inside the node.
+ //! All children after and including the specified node are moved one position back.
+ //! \param where Place where to insert the child, or 0 to insert at the back.
+ //! \param child Node to insert.
+ void insert_node(xml_node<Ch> *where, xml_node<Ch> *child)
+ {
+ assert(!where || where->parent() == this);
+ assert(child && !child->parent() && child->type() != node_document);
+ if (where == m_first_node)
+ prepend_node(child);
+ else if (where == 0)
+ append_node(child);
+ else
+ {
+ child->m_prev_sibling = where->m_prev_sibling;
+ child->m_next_sibling = where;
+ where->m_prev_sibling->m_next_sibling = child;
+ where->m_prev_sibling = child;
+ child->m_parent = this;
+ }
+ }
+
+ //! Removes first child node.
+ //! If node has no children, behaviour is undefined.
+ //! Use first_node() to test if node has children.
+ void remove_first_node()
+ {
+ assert(first_node());
+ xml_node<Ch> *child = m_first_node;
+ m_first_node = child->m_next_sibling;
+ if (child->m_next_sibling)
+ child->m_next_sibling->m_prev_sibling = 0;
+ else
+ m_last_node = 0;
+ child->m_parent = 0;
+ }
+
+ //! Removes last child of the node.
+ //! If node has no children, behaviour is undefined.
+ //! Use first_node() to test if node has children.
+ void remove_last_node()
+ {
+ assert(first_node());
+ xml_node<Ch> *child = m_last_node;
+ if (child->m_prev_sibling)
+ {
+ m_last_node = child->m_prev_sibling;
+ child->m_prev_sibling->m_next_sibling = 0;
+ }
+ else
+ m_first_node = 0;
+ child->m_parent = 0;
+ }
+
+ //! Removes specified child from the node
+ // \param where Pointer to child to be removed.
+ void remove_node(xml_node<Ch> *where)
+ {
+ assert(where && where->parent() == this);
+ assert(first_node());
+ if (where == m_first_node)
+ remove_first_node();
+ else if (where == m_last_node)
+ remove_last_node();
+ else
+ {
+ where->m_prev_sibling->m_next_sibling = where->m_next_sibling;
+ where->m_next_sibling->m_prev_sibling = where->m_prev_sibling;
+ where->m_parent = 0;
+ }
+ }
+
+ //! Removes all child nodes (but not attributes).
+ void remove_all_nodes()
+ {
+ for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling)
+ node->m_parent = 0;
+ m_first_node = 0;
+ }
+
+ //! Prepends a new attribute to the node.
+ //! \param attribute Attribute to prepend.
+ void prepend_attribute(xml_attribute<Ch> *attribute)
+ {
+ assert(attribute && !attribute->parent());
+ if (first_attribute())
+ {
+ attribute->m_next_attribute = m_first_attribute;
+ m_first_attribute->m_prev_attribute = attribute;
+ }
+ else
+ {
+ attribute->m_next_attribute = 0;
+ m_last_attribute = attribute;
+ }
+ m_first_attribute = attribute;
+ attribute->m_parent = this;
+ attribute->m_prev_attribute = 0;
+ }
+
+ //! Appends a new attribute to the node.
+ //! \param attribute Attribute to append.
+ void append_attribute(xml_attribute<Ch> *attribute)
+ {
+ assert(attribute && !attribute->parent());
+ if (first_attribute())
+ {
+ attribute->m_prev_attribute = m_last_attribute;
+ m_last_attribute->m_next_attribute = attribute;
+ }
+ else
+ {
+ attribute->m_prev_attribute = 0;
+ m_first_attribute = attribute;
+ }
+ m_last_attribute = attribute;
+ attribute->m_parent = this;
+ attribute->m_next_attribute = 0;
+ }
+
+ //! Inserts a new attribute at specified place inside the node.
+ //! All attributes after and including the specified attribute are moved one position back.
+ //! \param where Place where to insert the attribute, or 0 to insert at the back.
+ //! \param attribute Attribute to insert.
+ void insert_attribute(xml_attribute<Ch> *where, xml_attribute<Ch> *attribute)
+ {
+ assert(!where || where->parent() == this);
+ assert(attribute && !attribute->parent());
+ if (where == m_first_attribute)
+ prepend_attribute(attribute);
+ else if (where == 0)
+ append_attribute(attribute);
+ else
+ {
+ attribute->m_prev_attribute = where->m_prev_attribute;
+ attribute->m_next_attribute = where;
+ where->m_prev_attribute->m_next_attribute = attribute;
+ where->m_prev_attribute = attribute;
+ attribute->m_parent = this;
+ }
+ }
+
+ //! Removes first attribute of the node.
+ //! If node has no attributes, behaviour is undefined.
+ //! Use first_attribute() to test if node has attributes.
+ void remove_first_attribute()
+ {
+ assert(first_attribute());
+ xml_attribute<Ch> *attribute = m_first_attribute;
+ if (attribute->m_next_attribute)
+ {
+ attribute->m_next_attribute->m_prev_attribute = 0;
+ }
+ else
+ m_last_attribute = 0;
+ attribute->m_parent = 0;
+ m_first_attribute = attribute->m_next_attribute;
+ }
+
+ //! Removes last attribute of the node.
+ //! If node has no attributes, behaviour is undefined.
+ //! Use first_attribute() to test if node has attributes.
+ void remove_last_attribute()
+ {
+ assert(first_attribute());
+ xml_attribute<Ch> *attribute = m_last_attribute;
+ if (attribute->m_prev_attribute)
+ {
+ attribute->m_prev_attribute->m_next_attribute = 0;
+ m_last_attribute = attribute->m_prev_attribute;
+ }
+ else
+ m_first_attribute = 0;
+ attribute->m_parent = 0;
+ }
+
+ //! Removes specified attribute from node.
+ //! \param where Pointer to attribute to be removed.
+ void remove_attribute(xml_attribute<Ch> *where)
+ {
+ assert(first_attribute() && where->parent() == this);
+ if (where == m_first_attribute)
+ remove_first_attribute();
+ else if (where == m_last_attribute)
+ remove_last_attribute();
+ else
+ {
+ where->m_prev_attribute->m_next_attribute = where->m_next_attribute;
+ where->m_next_attribute->m_prev_attribute = where->m_prev_attribute;
+ where->m_parent = 0;
+ }
+ }
+
+ //! Removes all attributes of node.
+ void remove_all_attributes()
+ {
+ for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute)
+ attribute->m_parent = 0;
+ m_first_attribute = 0;
+ }
+
+ private:
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Restrictions
+
+ // No copying
+ xml_node(const xml_node &);
+ void operator =(const xml_node &);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Data members
+
+ // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0.
+ // This is required for maximum performance, as it allows the parser to omit initialization of
+ // unneded/redundant values.
+ //
+ // The rules are as follows:
+ // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively
+ // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage
+ // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage
+
+ node_type m_type; // Type of node; always valid
+ xml_node<Ch> *m_first_node; // Pointer to first child node, or 0 if none; always valid
+ xml_node<Ch> *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero
+ xml_attribute<Ch> *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid
+ xml_attribute<Ch> *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero
+ xml_node<Ch> *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero
+ xml_node<Ch> *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero
+
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
+ // XML document
+
+ //! This class represents root of the DOM hierarchy.
+ //! It is also an xml_node and a memory_pool through public inheritance.
+ //! Use parse() function to build a DOM tree from a zero-terminated XML text string.
+ //! parse() function allocates memory for nodes and attributes by using functions of xml_document,
+ //! which are inherited from memory_pool.
+ //! To access root node of the document, use the document itself, as if it was an xml_node.
+ //! \param Ch Character type to use.
+ template<class Ch = char>
+ class xml_document: public xml_node<Ch>, public memory_pool<Ch>
+ {
+
+ public:
+
+ //! Constructs empty XML document
+ xml_document()
+ : xml_node<Ch>(node_document)
+ {
+ }
+
+ //! Parses zero-terminated XML string according to given flags.
+ //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used.
+ //! The string must persist for the lifetime of the document.
+ //! In case of error, rapidxml::parse_error exception will be thrown.
+ //! <br><br>
+ //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning.
+ //! Make sure that data is zero-terminated.
+ //! <br><br>
+ //! Document can be parsed into multiple times.
+ //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.
+ //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.
+ template<int Flags>
+ void parse(Ch *text)
+ {
+ assert(text);
+
+ // Remove current contents
+ this->remove_all_nodes();
+ this->remove_all_attributes();
+
+ // Parse BOM, if any
+ parse_bom<Flags>(text);
+
+ // Parse children
+ while (1)
+ {
+ // Skip whitespace before node
+ skip<whitespace_pred, Flags>(text);
+ if (*text == 0)
+ break;
+
+ // Parse and append new child
+ if (*text == Ch('<'))
+ {
+ ++text; // Skip '<'
+ if (xml_node<Ch> *node = parse_node<Flags>(text))
+ this->append_node(node);
+ }
+ else
+ RAPIDXML_PARSE_ERROR("expected <", text);
+ }
+
+ }
+
+ //! Clears the document by deleting all nodes and clearing the memory pool.
+ //! All nodes owned by document pool are destroyed.
+ void clear()
+ {
+ this->remove_all_nodes();
+ this->remove_all_attributes();
+ memory_pool<Ch>::clear();
+ }
+
+ private:
+
+ ///////////////////////////////////////////////////////////////////////
+ // Internal character utility functions
+
+ // Detect whitespace character
+ struct whitespace_pred
+ {
+ static unsigned char test(Ch ch)
+ {
+ return internal::lookup_tables<0>::lookup_whitespace[static_cast<unsigned char>(ch)];
+ }
+ };
+
+ // Detect node name character
+ struct node_name_pred
+ {
+ static unsigned char test(Ch ch)
+ {
+ return internal::lookup_tables<0>::lookup_node_name[static_cast<unsigned char>(ch)];
+ }
+ };
+
+ // Detect attribute name character
+ struct attribute_name_pred
+ {
+ static unsigned char test(Ch ch)
+ {
+ return internal::lookup_tables<0>::lookup_attribute_name[static_cast<unsigned char>(ch)];
+ }
+ };
+
+ // Detect text character (PCDATA)
+ struct text_pred
+ {
+ static unsigned char test(Ch ch)
+ {
+ return internal::lookup_tables<0>::lookup_text[static_cast<unsigned char>(ch)];
+ }
+ };
+
+ // Detect text character (PCDATA) that does not require processing
+ struct text_pure_no_ws_pred
+ {
+ static unsigned char test(Ch ch)
+ {
+ return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast<unsigned char>(ch)];
+ }
+ };
+
+ // Detect text character (PCDATA) that does not require processing
+ struct text_pure_with_ws_pred
+ {
+ static unsigned char test(Ch ch)
+ {
+ return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast<unsigned char>(ch)];
+ }
+ };
+
+ // Detect attribute value character
+ template<Ch Quote>
+ struct attribute_value_pred
+ {
+ static unsigned char test(Ch ch)
+ {
+ if (Quote == Ch('\''))
+ return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast<unsigned char>(ch)];
+ if (Quote == Ch('\"'))
+ return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast<unsigned char>(ch)];
+ return 0; // Should never be executed, to avoid warnings on Comeau
+ }
+ };
+
+ // Detect attribute value character
+ template<Ch Quote>
+ struct attribute_value_pure_pred
+ {
+ static unsigned char test(Ch ch)
+ {
+ if (Quote == Ch('\''))
+ return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)];
+ if (Quote == Ch('\"'))
+ return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)];
+ return 0; // Should never be executed, to avoid warnings on Comeau
+ }
+ };
+
+ // Insert coded character, using UTF8 or 8-bit ASCII
+ template<int Flags>
+ static void insert_coded_character(Ch *&text, unsigned long code)
+ {
+ if (Flags & parse_no_utf8)
+ {
+ // Insert 8-bit ASCII character
+ // Todo: possibly verify that code is less than 256 and use replacement char otherwise?
+ text[0] = static_cast<unsigned char>(code);
+ text += 1;
+ }
+ else
+ {
+ // Insert UTF8 sequence
+ if (code < 0x80) // 1 byte sequence
+ {
+ text[0] = static_cast<unsigned char>(code);
+ text += 1;
+ }
+ else if (code < 0x800) // 2 byte sequence
+ {
+ text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+ text[0] = static_cast<unsigned char>(code | 0xC0);
+ text += 2;
+ }
+ else if (code < 0x10000) // 3 byte sequence
+ {
+ text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+ text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+ text[0] = static_cast<unsigned char>(code | 0xE0);
+ text += 3;
+ }
+ else if (code < 0x110000) // 4 byte sequence
+ {
+ text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+ text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+ text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
+ text[0] = static_cast<unsigned char>(code | 0xF0);
+ text += 4;
+ }
+ else // Invalid, only codes up to 0x10FFFF are allowed in Unicode
+ {
+ RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
+ }
+ }
+ }
+
+ // Skip characters until predicate evaluates to true
+ template<class StopPred, int Flags>
+ static void skip(Ch *&text)
+ {
+ Ch *tmp = text;
+ while (StopPred::test(*tmp))
+ ++tmp;
+ text = tmp;
+ }
+
+ // Skip characters until predicate evaluates to true while doing the following:
+ // - replacing XML character entity references with proper characters (&apos; &amp; &quot; &lt; &gt; &#...;)
+ // - condensing whitespace sequences to single space character
+ template<class StopPred, class StopPredPure, int Flags>
+ static Ch *skip_and_expand_character_refs(Ch *&text)
+ {
+ // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
+ if (Flags & parse_no_entity_translation &&
+ !(Flags & parse_normalize_whitespace) &&
+ !(Flags & parse_trim_whitespace))
+ {
+ skip<StopPred, Flags>(text);
+ return text;
+ }
+
+ // Use simple skip until first modification is detected
+ skip<StopPredPure, Flags>(text);
+
+ // Use translation skip
+ Ch *src = text;
+ Ch *dest = src;
+ while (StopPred::test(*src))
+ {
+ // If entity translation is enabled
+ if (!(Flags & parse_no_entity_translation))
+ {
+ // Test if replacement is needed
+ if (src[0] == Ch('&'))
+ {
+ switch (src[1])
+ {
+
+ // &amp; &apos;
+ case Ch('a'):
+ if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';'))
+ {
+ *dest = Ch('&');
+ ++dest;
+ src += 5;
+ continue;
+ }
+ if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';'))
+ {
+ *dest = Ch('\'');
+ ++dest;
+ src += 6;
+ continue;
+ }
+ break;
+
+ // &quot;
+ case Ch('q'):
+ if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';'))
+ {
+ *dest = Ch('"');
+ ++dest;
+ src += 6;
+ continue;
+ }
+ break;
+
+ // &gt;
+ case Ch('g'):
+ if (src[2] == Ch('t') && src[3] == Ch(';'))
+ {
+ *dest = Ch('>');
+ ++dest;
+ src += 4;
+ continue;
+ }
+ break;
+
+ // &lt;
+ case Ch('l'):
+ if (src[2] == Ch('t') && src[3] == Ch(';'))
+ {
+ *dest = Ch('<');
+ ++dest;
+ src += 4;
+ continue;
+ }
+ break;
+
+ // &#...; - assumes ASCII
+ case Ch('#'):
+ if (src[2] == Ch('x'))
+ {
+ unsigned long code = 0;
+ src += 3; // Skip &#x
+ while (1)
+ {
+ unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
+ if (digit == 0xFF)
+ break;
+ code = code * 16 + digit;
+ ++src;
+ }
+ insert_coded_character<Flags>(dest, code); // Put character in output
+ }
+ else
+ {
+ unsigned long code = 0;
+ src += 2; // Skip &#
+ while (1)
+ {
+ unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
+ if (digit == 0xFF)
+ break;
+ code = code * 10 + digit;
+ ++src;
+ }
+ insert_coded_character<Flags>(dest, code); // Put character in output
+ }
+ if (*src == Ch(';'))
+ ++src;
+ else
+ RAPIDXML_PARSE_ERROR("expected ;", src);
+ continue;
+
+ // Something else
+ default:
+ // Ignore, just copy '&' verbatim
+ break;
+
+ }
+ }
+ }
+
+ // If whitespace condensing is enabled
+ if (Flags & parse_normalize_whitespace)
+ {
+ // Test if condensing is needed
+ if (whitespace_pred::test(*src))
+ {
+ *dest = Ch(' '); ++dest; // Put single space in dest
+ ++src; // Skip first whitespace char
+ // Skip remaining whitespace chars
+ while (whitespace_pred::test(*src))
+ ++src;
+ continue;
+ }
+ }
+
+ // No replacement, only copy character
+ *dest++ = *src++;
+
+ }
+
+ // Return new end
+ text = src;
+ return dest;
+
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Internal parsing functions
+
+ // Parse BOM, if any
+ template<int Flags>
+ void parse_bom(Ch *&text)
+ {
+ // UTF-8?
+ if (static_cast<unsigned char>(text[0]) == 0xEF &&
+ static_cast<unsigned char>(text[1]) == 0xBB &&
+ static_cast<unsigned char>(text[2]) == 0xBF)
+ {
+ text += 3; // Skup utf-8 bom
+ }
+ }
+
+ // Parse XML declaration (<?xml...)
+ template<int Flags>
+ xml_node<Ch> *parse_xml_declaration(Ch *&text)
+ {
+ // If parsing of declaration is disabled
+ if (!(Flags & parse_declaration_node))
+ {
+ // Skip until end of declaration
+ while (text[0] != Ch('?') || text[1] != Ch('>'))
+ {
+ if (!text[0])
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ ++text;
+ }
+ text += 2; // Skip '?>'
+ return 0;
+ }
+
+ // Create declaration
+ xml_node<Ch> *declaration = this->allocate_node(node_declaration);
+
+ // Skip whitespace before attributes or ?>
+ skip<whitespace_pred, Flags>(text);
+
+ // Parse declaration attributes
+ parse_node_attributes<Flags>(text, declaration);
+
+ // Skip ?>
+ if (text[0] != Ch('?') || text[1] != Ch('>'))
+ RAPIDXML_PARSE_ERROR("expected ?>", text);
+ text += 2;
+
+ return declaration;
+ }
+
+ // Parse XML comment (<!--...)
+ template<int Flags>
+ xml_node<Ch> *parse_comment(Ch *&text)
+ {
+ // If parsing of comments is disabled
+ if (!(Flags & parse_comment_nodes))
+ {
+ // Skip until end of comment
+ while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
+ {
+ if (!text[0])
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ ++text;
+ }
+ text += 3; // Skip '-->'
+ return 0; // Do not produce comment node
+ }
+
+ // Remember value start
+ Ch *value = text;
+
+ // Skip until end of comment
+ while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
+ {
+ if (!text[0])
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ ++text;
+ }
+
+ // Create comment node
+ xml_node<Ch> *comment = this->allocate_node(node_comment);
+ comment->value(value, text - value);
+
+ // Place zero terminator after comment value
+ if (!(Flags & parse_no_string_terminators))
+ *text = Ch('\0');
+
+ text += 3; // Skip '-->'
+ return comment;
+ }
+
+ // Parse DOCTYPE
+ template<int Flags>
+ xml_node<Ch> *parse_doctype(Ch *&text)
+ {
+ // Remember value start
+ Ch *value = text;
+
+ // Skip to >
+ while (*text != Ch('>'))
+ {
+ // Determine character type
+ switch (*text)
+ {
+
+ // If '[' encountered, scan for matching ending ']' using naive algorithm with depth
+ // This works for all W3C test files except for 2 most wicked
+ case Ch('['):
+ {
+ ++text; // Skip '['
+ int depth = 1;
+ while (depth > 0)
+ {
+ switch (*text)
+ {
+ case Ch('['): ++depth; break;
+ case Ch(']'): --depth; break;
+ case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ }
+ ++text;
+ }
+ break;
+ }
+
+ // Error on end of text
+ case Ch('\0'):
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+
+ // Other character, skip it
+ default:
+ ++text;
+
+ }
+ }
+
+ // If DOCTYPE nodes enabled
+ if (Flags & parse_doctype_node)
+ {
+ // Create a new doctype node
+ xml_node<Ch> *doctype = this->allocate_node(node_doctype);
+ doctype->value(value, text - value);
+
+ // Place zero terminator after value
+ if (!(Flags & parse_no_string_terminators))
+ *text = Ch('\0');
+
+ text += 1; // skip '>'
+ return doctype;
+ }
+ else
+ {
+ text += 1; // skip '>'
+ return 0;
+ }
+
+ }
+
+ // Parse PI
+ template<int Flags>
+ xml_node<Ch> *parse_pi(Ch *&text)
+ {
+ // If creation of PI nodes is enabled
+ if (Flags & parse_pi_nodes)
+ {
+ // Create pi node
+ xml_node<Ch> *pi = this->allocate_node(node_pi);
+
+ // Extract PI target name
+ Ch *name = text;
+ skip<node_name_pred, Flags>(text);
+ if (text == name)
+ RAPIDXML_PARSE_ERROR("expected PI target", text);
+ pi->name(name, text - name);
+
+ // Skip whitespace between pi target and pi
+ skip<whitespace_pred, Flags>(text);
+
+ // Remember start of pi
+ Ch *value = text;
+
+ // Skip to '?>'
+ while (text[0] != Ch('?') || text[1] != Ch('>'))
+ {
+ if (*text == Ch('\0'))
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ ++text;
+ }
+
+ // Set pi value (verbatim, no entity expansion or whitespace normalization)
+ pi->value(value, text - value);
+
+ // Place zero terminator after name and value
+ if (!(Flags & parse_no_string_terminators))
+ {
+ pi->name()[pi->name_size()] = Ch('\0');
+ pi->value()[pi->value_size()] = Ch('\0');
+ }
+
+ text += 2; // Skip '?>'
+ return pi;
+ }
+ else
+ {
+ // Skip to '?>'
+ while (text[0] != Ch('?') || text[1] != Ch('>'))
+ {
+ if (*text == Ch('\0'))
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ ++text;
+ }
+ text += 2; // Skip '?>'
+ return 0;
+ }
+ }
+
+ // Parse and append data
+ // Return character that ends data.
+ // This is necessary because this character might have been overwritten by a terminating 0
+ template<int Flags>
+ Ch parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start)
+ {
+ // Backup to contents start if whitespace trimming is disabled
+ if (!(Flags & parse_trim_whitespace))
+ text = contents_start;
+
+ // Skip until end of data
+ Ch *value = text, *end;
+ if (Flags & parse_normalize_whitespace)
+ end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text);
+ else
+ end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text);
+
+ // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
+ if (Flags & parse_trim_whitespace)
+ {
+ if (Flags & parse_normalize_whitespace)
+ {
+ // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end
+ if (*(end - 1) == Ch(' '))
+ --end;
+ }
+ else
+ {
+ // Backup until non-whitespace character is found
+ while (whitespace_pred::test(*(end - 1)))
+ --end;
+ }
+ }
+
+ // If characters are still left between end and value (this test is only necessary if normalization is enabled)
+ // Create new data node
+ if (!(Flags & parse_no_data_nodes))
+ {
+ xml_node<Ch> *data = this->allocate_node(node_data);
+ data->value(value, end - value);
+ node->append_node(data);
+ }
+
+ // Add data to parent node if no data exists yet
+ if (!(Flags & parse_no_element_values))
+ if (*node->value() == Ch('\0'))
+ node->value(value, end - value);
+
+ // Place zero terminator after value
+ if (!(Flags & parse_no_string_terminators))
+ {
+ Ch ch = *text;
+ *end = Ch('\0');
+ return ch; // Return character that ends data; this is required because zero terminator overwritten it
+ }
+
+ // Return character that ends data
+ return *text;
+ }
+
+ // Parse CDATA
+ template<int Flags>
+ xml_node<Ch> *parse_cdata(Ch *&text)
+ {
+ // If CDATA is disabled
+ if (Flags & parse_no_data_nodes)
+ {
+ // Skip until end of cdata
+ while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
+ {
+ if (!text[0])
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ ++text;
+ }
+ text += 3; // Skip ]]>
+ return 0; // Do not produce CDATA node
+ }
+
+ // Skip until end of cdata
+ Ch *value = text;
+ while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
+ {
+ if (!text[0])
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ ++text;
+ }
+
+ // Create new cdata node
+ xml_node<Ch> *cdata = this->allocate_node(node_cdata);
+ cdata->value(value, text - value);
+
+ // Place zero terminator after value
+ if (!(Flags & parse_no_string_terminators))
+ *text = Ch('\0');
+
+ text += 3; // Skip ]]>
+ return cdata;
+ }
+
+ // Parse element node
+ template<int Flags>
+ xml_node<Ch> *parse_element(Ch *&text)
+ {
+ // Create element node
+ xml_node<Ch> *element = this->allocate_node(node_element);
+
+ // Extract element name
+ Ch *name = text;
+ skip<node_name_pred, Flags>(text);
+ if (text == name)
+ RAPIDXML_PARSE_ERROR("expected element name", text);
+ element->name(name, text - name);
+
+ // Skip whitespace between element name and attributes or >
+ skip<whitespace_pred, Flags>(text);
+
+ // Parse attributes, if any
+ parse_node_attributes<Flags>(text, element);
+
+ // Determine ending type
+ if (*text == Ch('>'))
+ {
+ ++text;
+ parse_node_contents<Flags>(text, element);
+ }
+ else if (*text == Ch('/'))
+ {
+ ++text;
+ if (*text != Ch('>'))
+ RAPIDXML_PARSE_ERROR("expected >", text);
+ ++text;
+ }
+ else
+ RAPIDXML_PARSE_ERROR("expected >", text);
+
+ // Place zero terminator after name
+ if (!(Flags & parse_no_string_terminators))
+ element->name()[element->name_size()] = Ch('\0');
+
+ // Return parsed element
+ return element;
+ }
+
+ // Determine node type, and parse it
+ template<int Flags>
+ xml_node<Ch> *parse_node(Ch *&text)
+ {
+ // Parse proper node type
+ switch (text[0])
+ {
+
+ // <...
+ default:
+ // Parse and append element node
+ return parse_element<Flags>(text);
+
+ // <?...
+ case Ch('?'):
+ ++text; // Skip ?
+ if ((text[0] == Ch('x') || text[0] == Ch('X')) &&
+ (text[1] == Ch('m') || text[1] == Ch('M')) &&
+ (text[2] == Ch('l') || text[2] == Ch('L')) &&
+ whitespace_pred::test(text[3]))
+ {
+ // '<?xml ' - xml declaration
+ text += 4; // Skip 'xml '
+ return parse_xml_declaration<Flags>(text);
+ }
+ else
+ {
+ // Parse PI
+ return parse_pi<Flags>(text);
+ }
+
+ // <!...
+ case Ch('!'):
+
+ // Parse proper subset of <! node
+ switch (text[1])
+ {
+
+ // <!-
+ case Ch('-'):
+ if (text[2] == Ch('-'))
+ {
+ // '<!--' - xml comment
+ text += 3; // Skip '!--'
+ return parse_comment<Flags>(text);
+ }
+ break;
+
+ // <![
+ case Ch('['):
+ if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') &&
+ text[5] == Ch('T') && text[6] == Ch('A') && text[7] == Ch('['))
+ {
+ // '<![CDATA[' - cdata
+ text += 8; // Skip '![CDATA['
+ return parse_cdata<Flags>(text);
+ }
+ break;
+
+ // <!D
+ case Ch('D'):
+ if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') &&
+ text[5] == Ch('Y') && text[6] == Ch('P') && text[7] == Ch('E') &&
+ whitespace_pred::test(text[8]))
+ {
+ // '<!DOCTYPE ' - doctype
+ text += 9; // skip '!DOCTYPE '
+ return parse_doctype<Flags>(text);
+ }
+
+ } // switch
+
+ // Attempt to skip other, unrecognized node types starting with <!
+ ++text; // Skip !
+ while (*text != Ch('>'))
+ {
+ if (*text == 0)
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+ ++text;
+ }
+ ++text; // Skip '>'
+ return 0; // No node recognized
+
+ }
+ }
+
+ // Parse contents of the node - children, data etc.
+ template<int Flags>
+ void parse_node_contents(Ch *&text, xml_node<Ch> *node)
+ {
+ // For all children and text
+ while (1)
+ {
+ // Skip whitespace between > and node contents
+ Ch *contents_start = text; // Store start of node contents before whitespace is skipped
+ skip<whitespace_pred, Flags>(text);
+ Ch next_char = *text;
+
+ // After data nodes, instead of continuing the loop, control jumps here.
+ // This is because zero termination inside parse_and_append_data() function
+ // would wreak havoc with the above code.
+ // Also, skipping whitespace after data nodes is unnecessary.
+ after_data_node:
+
+ // Determine what comes next: node closing, child node, data node, or 0?
+ switch (next_char)
+ {
+
+ // Node closing or child node
+ case Ch('<'):
+ if (text[1] == Ch('/'))
+ {
+ // Node closing
+ text += 2; // Skip '</'
+ if (Flags & parse_validate_closing_tags)
+ {
+ // Skip and validate closing tag name
+ Ch *closing_name = text;
+ skip<node_name_pred, Flags>(text);
+ if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true))
+ RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
+ }
+ else
+ {
+ // No validation, just skip name
+ skip<node_name_pred, Flags>(text);
+ }
+ // Skip remaining whitespace after node name
+ skip<whitespace_pred, Flags>(text);
+ if (*text != Ch('>'))
+ RAPIDXML_PARSE_ERROR("expected >", text);
+ ++text; // Skip '>'
+ return; // Node closed, finished parsing contents
+ }
+ else
+ {
+ // Child node
+ ++text; // Skip '<'
+ if (xml_node<Ch> *child = parse_node<Flags>(text))
+ node->append_node(child);
+ }
+ break;
+
+ // End of data - error
+ case Ch('\0'):
+ RAPIDXML_PARSE_ERROR("unexpected end of data", text);
+
+ // Data node
+ default:
+ next_char = parse_and_append_data<Flags>(node, text, contents_start);
+ goto after_data_node; // Bypass regular processing after data nodes
+
+ }
+ }
+ }
+
+ // Parse XML attributes of the node
+ template<int Flags>
+ void parse_node_attributes(Ch *&text, xml_node<Ch> *node)
+ {
+ // For all attributes
+ while (attribute_name_pred::test(*text))
+ {
+ // Extract attribute name
+ Ch *name = text;
+ ++text; // Skip first character of attribute name
+ skip<attribute_name_pred, Flags>(text);
+ if (text == name)
+ RAPIDXML_PARSE_ERROR("expected attribute name", name);
+
+ // Create new attribute
+ xml_attribute<Ch> *attribute = this->allocate_attribute();
+ attribute->name(name, text - name);
+ node->append_attribute(attribute);
+
+ // Skip whitespace after attribute name
+ skip<whitespace_pred, Flags>(text);
+
+ // Skip =
+ if (*text != Ch('='))
+ RAPIDXML_PARSE_ERROR("expected =", text);
+ ++text;
+
+ // Add terminating zero after name
+ if (!(Flags & parse_no_string_terminators))
+ attribute->name()[attribute->name_size()] = 0;
+
+ // Skip whitespace after =
+ skip<whitespace_pred, Flags>(text);
+
+ // Skip quote and remember if it was ' or "
+ Ch quote = *text;
+ if (quote != Ch('\'') && quote != Ch('"'))
+ RAPIDXML_PARSE_ERROR("expected ' or \"", text);
+ ++text;
+
+ // Extract attribute value and expand char refs in it
+ Ch *value = text, *end;
+ const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes
+ if (quote == Ch('\''))
+ end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text);
+ else
+ end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text);
+
+ // Set attribute value
+ attribute->value(value, end - value);
+
+ // Make sure that end quote is present
+ if (*text != quote)
+ RAPIDXML_PARSE_ERROR("expected ' or \"", text);
+ ++text; // Skip quote
+
+ // Add terminating zero after value
+ if (!(Flags & parse_no_string_terminators))
+ attribute->value()[attribute->value_size()] = 0;
+
+ // Skip whitespace after attribute value
+ skip<whitespace_pred, Flags>(text);
+ }
+ }
+
+ };
+
+ //! \cond internal
+ namespace internal
+ {
+
+ // Whitespace (space \n \r \t)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
+ };
+
+ // Node name (anything but space \n \r \t / > ? \0)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_node_name[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Text (i.e. PCDATA) (anything but < \0)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_text[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled
+ // (anything but < \0 &)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled
+ // (anything but < \0 & space \n \r \t)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Attribute name (anything but space \n \r \t / < > = ? ! \0)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Attribute data with single quote (anything but ' \0)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Attribute data with single quote that does not require processing (anything but ' \0 &)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Attribute data with double quote (anything but " \0)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Attribute data with double quote that does not require processing (anything but " \0 &)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
+ 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
+ };
+
+ // Digits (dec and hex, 255 denotes end of numeric character reference)
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_digits[256] =
+ {
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3
+ 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5
+ 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F
+ };
+
+ // Upper case conversion
+ template<int Dummy>
+ const unsigned char lookup_tables<Dummy>::lookup_upcase[256] =
+ {
+ // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5
+ 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B
+ 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C
+ 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F
+ };
+ }
+ //! \endcond
+
+}
+
+// Undefine internal macros
+#undef RAPIDXML_PARSE_ERROR
+
+// On MSVC, restore warnings state
+#ifdef _MSC_VER
+ #pragma warning(pop)
+#endif
+
+#endif
diff --git a/lib/include/rapidxml/rapidxml_print.hpp b/lib/include/rapidxml/rapidxml_print.hpp
new file mode 100644
index 0000000..4432273
--- /dev/null
+++ b/lib/include/rapidxml/rapidxml_print.hpp
@@ -0,0 +1,424 @@
+#ifndef RAPIDXML_PRINT_HPP_INCLUDED
+#define RAPIDXML_PRINT_HPP_INCLUDED
+
+// Copyright (C) 2006, 2009 Marcin Kalicinski
+// Version 1.13
+// Revision $DateTime: 2009/05/13 01:46:17 $
+//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
+
+#include "rapidxml.hpp"
+
+// Only include streams if not disabled
+#ifndef RAPIDXML_NO_STREAMS
+ #include <ostream>
+ #include <iterator>
+#endif
+
+namespace rapidxml
+{
+
+ ///////////////////////////////////////////////////////////////////////
+ // Printing flags
+
+ const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
+
+ ///////////////////////////////////////////////////////////////////////
+ // Internal
+
+ //! \cond internal
+ namespace internal
+ {
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Internal character operations
+
+ // Copy characters from given range to given output iterator
+ template<class OutIt, class Ch>
+ inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
+ {
+ while (begin != end)
+ *out++ = *begin++;
+ return out;
+ }
+
+ // Copy characters from given range to given output iterator and expand
+ // characters into references (&lt; &gt; &apos; &quot; &amp;)
+ template<class OutIt, class Ch>
+ inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
+ {
+ while (begin != end)
+ {
+ if (*begin == noexpand)
+ {
+ *out++ = *begin; // No expansion, copy character
+ }
+ else
+ {
+ switch (*begin)
+ {
+ case Ch('<'):
+ *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
+ break;
+ case Ch('>'):
+ *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
+ break;
+ case Ch('\''):
+ *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
+ break;
+ case Ch('"'):
+ *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
+ break;
+ case Ch('&'):
+ *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
+ break;
+ default:
+ *out++ = *begin; // No expansion, copy character
+ }
+ }
+ ++begin; // Step to next character
+ }
+ return out;
+ }
+
+ // Fill given output iterator with repetitions of the same character
+ template<class OutIt, class Ch>
+ inline OutIt fill_chars(OutIt out, int n, Ch ch)
+ {
+ for (int i = 0; i < n; ++i)
+ *out++ = ch;
+ return out;
+ }
+
+ // Find character
+ template<class Ch, Ch ch>
+ inline bool find_char(const Ch *begin, const Ch *end)
+ {
+ while (begin != end)
+ if (*begin++ == ch)
+ return true;
+ return false;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Internal printing operations
+
+ template<class OutIt, class Ch>
+ inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
+
+ // Print children of the node
+ template<class OutIt, class Ch>
+ inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
+ out = print_node(out, child, flags, indent);
+ return out;
+ }
+
+ // Print attributes of the node
+ template<class OutIt, class Ch>
+ inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
+ {
+ for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
+ {
+ if (attribute->name() && attribute->value())
+ {
+ // Print attribute name
+ *out = Ch(' '), ++out;
+ out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
+ *out = Ch('='), ++out;
+ // Print attribute value using appropriate quote type
+ if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
+ {
+ *out = Ch('\''), ++out;
+ out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
+ *out = Ch('\''), ++out;
+ }
+ else
+ {
+ *out = Ch('"'), ++out;
+ out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
+ *out = Ch('"'), ++out;
+ }
+ }
+ }
+ return out;
+ }
+
+ // Print data node
+ template<class OutIt, class Ch>
+ inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ assert(node->type() == node_data);
+ if (!(flags & print_no_indenting))
+ out = fill_chars(out, indent, Ch('\t'));
+ out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
+ return out;
+ }
+
+ // Print data node
+ template<class OutIt, class Ch>
+ inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ assert(node->type() == node_cdata);
+ if (!(flags & print_no_indenting))
+ out = fill_chars(out, indent, Ch('\t'));
+ *out = Ch('<'); ++out;
+ *out = Ch('!'); ++out;
+ *out = Ch('['); ++out;
+ *out = Ch('C'); ++out;
+ *out = Ch('D'); ++out;
+ *out = Ch('A'); ++out;
+ *out = Ch('T'); ++out;
+ *out = Ch('A'); ++out;
+ *out = Ch('['); ++out;
+ out = copy_chars(node->value(), node->value() + node->value_size(), out);
+ *out = Ch(']'); ++out;
+ *out = Ch(']'); ++out;
+ *out = Ch('>'); ++out;
+ return out;
+ }
+
+ // Print element node
+ template<class OutIt, class Ch>
+ inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ assert(node->type() == node_element);
+
+ // Print element name and attributes, if any
+ if (!(flags & print_no_indenting))
+ out = fill_chars(out, indent, Ch('\t'));
+ *out = Ch('<'), ++out;
+ out = copy_chars(node->name(), node->name() + node->name_size(), out);
+ out = print_attributes(out, node, flags);
+
+ // If node is childless
+ if (node->value_size() == 0 && !node->first_node())
+ {
+ // Print childless node tag ending
+ *out = Ch('/'), ++out;
+ *out = Ch('>'), ++out;
+ }
+ else
+ {
+ // Print normal node tag ending
+ *out = Ch('>'), ++out;
+
+ // Test if node contains a single data node only (and no other nodes)
+ xml_node<Ch> *child = node->first_node();
+ if (!child)
+ {
+ // If node has no children, only print its value without indenting
+ out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
+ }
+ else if (child->next_sibling() == 0 && child->type() == node_data)
+ {
+ // If node has a sole data child, only print its value without indenting
+ out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
+ }
+ else
+ {
+ // Print all children with full indenting
+ if (!(flags & print_no_indenting))
+ *out = Ch('\n'), ++out;
+ out = print_children(out, node, flags, indent + 1);
+ if (!(flags & print_no_indenting))
+ out = fill_chars(out, indent, Ch('\t'));
+ }
+
+ // Print node end
+ *out = Ch('<'), ++out;
+ *out = Ch('/'), ++out;
+ out = copy_chars(node->name(), node->name() + node->name_size(), out);
+ *out = Ch('>'), ++out;
+ }
+ return out;
+ }
+
+ // Print declaration node
+ template<class OutIt, class Ch>
+ inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ // Print declaration start
+ if (!(flags & print_no_indenting))
+ out = fill_chars(out, indent, Ch('\t'));
+ *out = Ch('<'), ++out;
+ *out = Ch('?'), ++out;
+ *out = Ch('x'), ++out;
+ *out = Ch('m'), ++out;
+ *out = Ch('l'), ++out;
+
+ // Print attributes
+ out = print_attributes(out, node, flags);
+
+ // Print declaration end
+ *out = Ch('?'), ++out;
+ *out = Ch('>'), ++out;
+
+ return out;
+ }
+
+ // Print comment node
+ template<class OutIt, class Ch>
+ inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ assert(node->type() == node_comment);
+ if (!(flags & print_no_indenting))
+ out = fill_chars(out, indent, Ch('\t'));
+ *out = Ch('<'), ++out;
+ *out = Ch('!'), ++out;
+ *out = Ch('-'), ++out;
+ *out = Ch('-'), ++out;
+ out = copy_chars(node->value(), node->value() + node->value_size(), out);
+ *out = Ch('-'), ++out;
+ *out = Ch('-'), ++out;
+ *out = Ch('>'), ++out;
+ return out;
+ }
+
+ // Print doctype node
+ template<class OutIt, class Ch>
+ inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ assert(node->type() == node_doctype);
+ if (!(flags & print_no_indenting))
+ out = fill_chars(out, indent, Ch('\t'));
+ *out = Ch('<'), ++out;
+ *out = Ch('!'), ++out;
+ *out = Ch('D'), ++out;
+ *out = Ch('O'), ++out;
+ *out = Ch('C'), ++out;
+ *out = Ch('T'), ++out;
+ *out = Ch('Y'), ++out;
+ *out = Ch('P'), ++out;
+ *out = Ch('E'), ++out;
+ *out = Ch(' '), ++out;
+ out = copy_chars(node->value(), node->value() + node->value_size(), out);
+ *out = Ch('>'), ++out;
+ return out;
+ }
+
+ // Print pi node
+ template<class OutIt, class Ch>
+ inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ assert(node->type() == node_pi);
+ if (!(flags & print_no_indenting))
+ out = fill_chars(out, indent, Ch('\t'));
+ *out = Ch('<'), ++out;
+ *out = Ch('?'), ++out;
+ out = copy_chars(node->name(), node->name() + node->name_size(), out);
+ *out = Ch(' '), ++out;
+ out = copy_chars(node->value(), node->value() + node->value_size(), out);
+ *out = Ch('?'), ++out;
+ *out = Ch('>'), ++out;
+ return out;
+ }
+
+ // Print node
+ template<class OutIt, class Ch>
+ inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
+ {
+ // Print proper node type
+ switch (node->type())
+ {
+
+ // Document
+ case node_document:
+ out = print_children(out, node, flags, indent);
+ break;
+
+ // Element
+ case node_element:
+ out = print_element_node(out, node, flags, indent);
+ break;
+
+ // Data
+ case node_data:
+ out = print_data_node(out, node, flags, indent);
+ break;
+
+ // CDATA
+ case node_cdata:
+ out = print_cdata_node(out, node, flags, indent);
+ break;
+
+ // Declaration
+ case node_declaration:
+ out = print_declaration_node(out, node, flags, indent);
+ break;
+
+ // Comment
+ case node_comment:
+ out = print_comment_node(out, node, flags, indent);
+ break;
+
+ // Doctype
+ case node_doctype:
+ out = print_doctype_node(out, node, flags, indent);
+ break;
+
+ // Pi
+ case node_pi:
+ out = print_pi_node(out, node, flags, indent);
+ break;
+
+ // Unknown
+ default:
+ assert(0);
+ break;
+ }
+
+ // If indenting not disabled, add line break after node
+ if (!(flags & print_no_indenting))
+ *out = Ch('\n'), ++out;
+
+ // Return modified iterator
+ return out;
+ }
+
+ }
+ //! \endcond
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Printing
+
+ //! Prints XML to given output iterator.
+ //! \param out Output iterator to print to.
+ //! \param node Node to be printed. Pass xml_document to print entire document.
+ //! \param flags Flags controlling how XML is printed.
+ //! \return Output iterator pointing to position immediately after last character of printed text.
+ template<class OutIt, class Ch>
+ inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
+ {
+ return internal::print_node(out, &node, flags, 0);
+ }
+
+#ifndef RAPIDXML_NO_STREAMS
+
+ //! Prints XML to given output stream.
+ //! \param out Output stream to print to.
+ //! \param node Node to be printed. Pass xml_document to print entire document.
+ //! \param flags Flags controlling how XML is printed.
+ //! \return Output stream.
+ template<class Ch>
+ inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
+ {
+ print(std::ostream_iterator<Ch>(out), node, flags);
+ return out;
+ }
+
+ //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
+ //! \param out Output stream to print to.
+ //! \param node Node to be printed.
+ //! \return Output stream.
+ template<class Ch>
+ inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
+ {
+ return print(out, node);
+ }
+
+#endif
+
+}
+
+#endif
diff --git a/lib/include/tnt/jama_cholesky.h b/lib/include/tnt/jama_cholesky.h
new file mode 100644
index 0000000..371d2f7
--- /dev/null
+++ b/lib/include/tnt/jama_cholesky.h
@@ -0,0 +1,258 @@
+#ifndef JAMA_CHOLESKY_H
+#define JAMA_CHOLESKY_H
+
+#include "math.h"
+ /* needed for sqrt() below. */
+
+
+namespace JAMA
+{
+
+using namespace TNT;
+
+/**
+ <P>
+ For a symmetric, positive definite matrix A, this function
+ computes the Cholesky factorization, i.e. it computes a lower
+ triangular matrix L such that A = L*L'.
+ If the matrix is not symmetric or positive definite, the function
+ computes only a partial decomposition. This can be tested with
+ the is_spd() flag.
+
+ <p>Typical usage looks like:
+ <pre>
+ Array2D<double> A(n,n);
+ Array2D<double> L;
+
+ ...
+
+ Cholesky<double> chol(A);
+
+ if (chol.is_spd())
+ L = chol.getL();
+
+ else
+ cout << "factorization was not complete.\n";
+
+ </pre>
+
+
+ <p>
+ (Adapted from JAMA, a Java Matrix Library, developed by jointly
+ by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
+
+ */
+
+template <class Real>
+class Cholesky
+{
+ Array2D<Real> L_; // lower triangular factor
+ int isspd; // 1 if matrix to be factored was SPD
+
+public:
+
+ Cholesky();
+ Cholesky(const Array2D<Real> &A);
+ Array2D<Real> getL() const;
+ Array1D<Real> solve(const Array1D<Real> &B);
+ Array2D<Real> solve(const Array2D<Real> &B);
+ int is_spd() const;
+
+};
+
+template <class Real>
+Cholesky<Real>::Cholesky() : L_(0,0), isspd(0) {}
+
+/**
+ @return 1, if original matrix to be factored was symmetric
+ positive-definite (SPD).
+*/
+template <class Real>
+int Cholesky<Real>::is_spd() const
+{
+ return isspd;
+}
+
+/**
+ @return the lower triangular factor, L, such that L*L'=A.
+*/
+template <class Real>
+Array2D<Real> Cholesky<Real>::getL() const
+{
+ return L_;
+}
+
+/**
+ Constructs a lower triangular matrix L, such that L*L'= A.
+ If A is not symmetric positive-definite (SPD), only a
+ partial factorization is performed. If is_spd()
+ evalutate true (1) then the factorizaiton was successful.
+*/
+template <class Real>
+Cholesky<Real>::Cholesky(const Array2D<Real> &A)
+{
+
+
+ int m = A.dim1();
+ int n = A.dim2();
+
+ isspd = (m == n);
+
+ if (m != n)
+ {
+ L_ = Array2D<Real>(0,0);
+ return;
+ }
+
+ L_ = Array2D<Real>(n,n);
+
+
+ // Main loop.
+ for (int j = 0; j < n; j++)
+ {
+ Real d(0.0);
+ for (int k = 0; k < j; k++)
+ {
+ Real s(0.0);
+ for (int i = 0; i < k; i++)
+ {
+ s += L_[k][i]*L_[j][i];
+ }
+ L_[j][k] = s = (A[j][k] - s)/L_[k][k];
+ d = d + s*s;
+ isspd = isspd && (A[k][j] == A[j][k]);
+ }
+ d = A[j][j] - d;
+ isspd = isspd && (d > 0.0);
+ L_[j][j] = sqrt(d > 0.0 ? d : 0.0);
+ for (int k = j+1; k < n; k++)
+ {
+ L_[j][k] = 0.0;
+ }
+ }
+}
+
+/**
+
+ Solve a linear system A*x = b, using the previously computed
+ cholesky factorization of A: L*L'.
+
+ @param B A Matrix with as many rows as A and any number of columns.
+ @return x so that L*L'*x = b. If b is nonconformat, or if A
+ was not symmetric posidtive definite, a null (0x0)
+ array is returned.
+*/
+template <class Real>
+Array1D<Real> Cholesky<Real>::solve(const Array1D<Real> &b)
+{
+ int n = L_.dim1();
+ if (b.dim1() != n)
+ return Array1D<Real>();
+
+
+ Array1D<Real> x = b.copy();
+
+
+ // Solve L*y = b;
+ for (int k = 0; k < n; k++)
+ {
+ for (int i = 0; i < k; i++)
+ x[k] -= x[i]*L_[k][i];
+ x[k] /= L_[k][k];
+
+ }
+
+ // Solve L'*X = Y;
+ for (int k = n-1; k >= 0; k--)
+ {
+ for (int i = k+1; i < n; i++)
+ x[k] -= x[i]*L_[i][k];
+ x[k] /= L_[k][k];
+ }
+
+ return x;
+}
+
+
+/**
+
+ Solve a linear system A*X = B, using the previously computed
+ cholesky factorization of A: L*L'.
+
+ @param B A Matrix with as many rows as A and any number of columns.
+ @return X so that L*L'*X = B. If B is nonconformat, or if A
+ was not symmetric posidtive definite, a null (0x0)
+ array is returned.
+*/
+template <class Real>
+Array2D<Real> Cholesky<Real>::solve(const Array2D<Real> &B)
+{
+ int n = L_.dim1();
+ if (B.dim1() != n)
+ return Array2D<Real>();
+
+
+ Array2D<Real> X = B.copy();
+ int nx = B.dim2();
+
+// Cleve's original code
+#if 0
+ // Solve L*Y = B;
+ for (int k = 0; k < n; k++) {
+ for (int i = k+1; i < n; i++) {
+ for (int j = 0; j < nx; j++) {
+ X[i][j] -= X[k][j]*L_[k][i];
+ }
+ }
+ for (int j = 0; j < nx; j++) {
+ X[k][j] /= L_[k][k];
+ }
+ }
+
+ // Solve L'*X = Y;
+ for (int k = n-1; k >= 0; k--) {
+ for (int j = 0; j < nx; j++) {
+ X[k][j] /= L_[k][k];
+ }
+ for (int i = 0; i < k; i++) {
+ for (int j = 0; j < nx; j++) {
+ X[i][j] -= X[k][j]*L_[k][i];
+ }
+ }
+ }
+#endif
+
+
+ // Solve L*y = b;
+ for (int j=0; j< nx; j++)
+ {
+ for (int k = 0; k < n; k++)
+ {
+ for (int i = 0; i < k; i++)
+ X[k][j] -= X[i][j]*L_[k][i];
+ X[k][j] /= L_[k][k];
+ }
+ }
+
+ // Solve L'*X = Y;
+ for (int j=0; j<nx; j++)
+ {
+ for (int k = n-1; k >= 0; k--)
+ {
+ for (int i = k+1; i < n; i++)
+ X[k][j] -= X[i][j]*L_[i][k];
+ X[k][j] /= L_[k][k];
+ }
+ }
+
+
+
+ return X;
+}
+
+
+}
+// namespace JAMA
+
+#endif
+// JAMA_CHOLESKY_H
diff --git a/lib/include/tnt/jama_eig.h b/lib/include/tnt/jama_eig.h
new file mode 100644
index 0000000..8e3572f
--- /dev/null
+++ b/lib/include/tnt/jama_eig.h
@@ -0,0 +1,1034 @@
+#ifndef JAMA_EIG_H
+#define JAMA_EIG_H
+
+
+#include "tnt_array1d.h"
+#include "tnt_array2d.h"
+#include "tnt_math_utils.h"
+
+#include <algorithm>
+// for min(), max() below
+
+#include <cmath>
+// for abs() below
+
+using namespace TNT;
+using namespace std;
+
+// Modification by Willem Jan Palenstijn, 2010-03-11:
+// Use std::min() instead of min(), std::max() instead of max()
+
+
+namespace JAMA
+{
+
+/**
+
+ Computes eigenvalues and eigenvectors of a real (non-complex)
+ matrix.
+<P>
+ If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
+ diagonal and the eigenvector matrix V is orthogonal. That is,
+ the diagonal values of D are the eigenvalues, and
+ V*V' = I, where I is the identity matrix. The columns of V
+ represent the eigenvectors in the sense that A*V = V*D.
+
+<P>
+ If A is not symmetric, then the eigenvalue matrix D is block diagonal
+ with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
+ a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex
+ eigenvalues look like
+<pre>
+
+ u + iv . . . . .
+ . u - iv . . . .
+ . . a + ib . . .
+ . . . a - ib . .
+ . . . . x .
+ . . . . . y
+</pre>
+ then D looks like
+<pre>
+
+ u v . . . .
+ -v u . . . .
+ . . a b . .
+ . . -b a . .
+ . . . . x .
+ . . . . . y
+</pre>
+ This keeps V a real matrix in both symmetric and non-symmetric
+ cases, and A*V = V*D.
+
+
+
+ <p>
+ The matrix V may be badly
+ conditioned, or even singular, so the validity of the equation
+ A = V*D*inverse(V) depends upon the condition number of V.
+
+ <p>
+ (Adapted from JAMA, a Java Matrix Library, developed by jointly
+ by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
+**/
+
+template <class Real>
+class Eigenvalue
+{
+
+
+ /** Row and column dimension (square matrix). */
+ int n;
+
+ int issymmetric; /* boolean*/
+
+ /** Arrays for internal storage of eigenvalues. */
+
+ TNT::Array1D<Real> d; /* real part */
+ TNT::Array1D<Real> e; /* img part */
+
+ /** Array for internal storage of eigenvectors. */
+ TNT::Array2D<Real> V;
+
+ /** Array for internal storage of nonsymmetric Hessenberg form.
+ @serial internal storage of nonsymmetric Hessenberg form.
+ */
+ TNT::Array2D<Real> H;
+
+
+ /** Working storage for nonsymmetric algorithm.
+ @serial working storage for nonsymmetric algorithm.
+ */
+ TNT::Array1D<Real> ort;
+
+
+ // Symmetric Householder reduction to tridiagonal form.
+
+ void tred2() {
+
+ // This is derived from the Algol procedures tred2 by
+ // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+ // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+ // Fortran subroutine in EISPACK.
+
+ for (int j = 0; j < n; j++) {
+ d[j] = V[n-1][j];
+ }
+
+ // Householder reduction to tridiagonal form.
+
+ for (int i = n-1; i > 0; i--) {
+
+ // Scale to avoid under/overflow.
+
+ Real scale = 0.0;
+ Real h = 0.0;
+ for (int k = 0; k < i; k++) {
+ scale = scale + abs(d[k]);
+ }
+ if (scale == 0.0) {
+ e[i] = d[i-1];
+ for (int j = 0; j < i; j++) {
+ d[j] = V[i-1][j];
+ V[i][j] = 0.0;
+ V[j][i] = 0.0;
+ }
+ } else {
+
+ // Generate Householder vector.
+
+ for (int k = 0; k < i; k++) {
+ d[k] /= scale;
+ h += d[k] * d[k];
+ }
+ Real f = d[i-1];
+ Real g = sqrt(h);
+ if (f > 0) {
+ g = -g;
+ }
+ e[i] = scale * g;
+ h = h - f * g;
+ d[i-1] = f - g;
+ for (int j = 0; j < i; j++) {
+ e[j] = 0.0;
+ }
+
+ // Apply similarity transformation to remaining columns.
+
+ for (int j = 0; j < i; j++) {
+ f = d[j];
+ V[j][i] = f;
+ g = e[j] + V[j][j] * f;
+ for (int k = j+1; k <= i-1; k++) {
+ g += V[k][j] * d[k];
+ e[k] += V[k][j] * f;
+ }
+ e[j] = g;
+ }
+ f = 0.0;
+ for (int j = 0; j < i; j++) {
+ e[j] /= h;
+ f += e[j] * d[j];
+ }
+ Real hh = f / (h + h);
+ for (int j = 0; j < i; j++) {
+ e[j] -= hh * d[j];
+ }
+ for (int j = 0; j < i; j++) {
+ f = d[j];
+ g = e[j];
+ for (int k = j; k <= i-1; k++) {
+ V[k][j] -= (f * e[k] + g * d[k]);
+ }
+ d[j] = V[i-1][j];
+ V[i][j] = 0.0;
+ }
+ }
+ d[i] = h;
+ }
+
+ // Accumulate transformations.
+
+ for (int i = 0; i < n-1; i++) {
+ V[n-1][i] = V[i][i];
+ V[i][i] = 1.0;
+ Real h = d[i+1];
+ if (h != 0.0) {
+ for (int k = 0; k <= i; k++) {
+ d[k] = V[k][i+1] / h;
+ }
+ for (int j = 0; j <= i; j++) {
+ Real g = 0.0;
+ for (int k = 0; k <= i; k++) {
+ g += V[k][i+1] * V[k][j];
+ }
+ for (int k = 0; k <= i; k++) {
+ V[k][j] -= g * d[k];
+ }
+ }
+ }
+ for (int k = 0; k <= i; k++) {
+ V[k][i+1] = 0.0;
+ }
+ }
+ for (int j = 0; j < n; j++) {
+ d[j] = V[n-1][j];
+ V[n-1][j] = 0.0;
+ }
+ V[n-1][n-1] = 1.0;
+ e[0] = 0.0;
+ }
+
+ // Symmetric tridiagonal QL algorithm.
+
+ void tql2 () {
+
+ // This is derived from the Algol procedures tql2, by
+ // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+ // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+ // Fortran subroutine in EISPACK.
+
+ for (int i = 1; i < n; i++) {
+ e[i-1] = e[i];
+ }
+ e[n-1] = 0.0;
+
+ Real f = 0.0;
+ Real tst1 = 0.0;
+ Real eps = pow(2.0,-52.0);
+ for (int l = 0; l < n; l++) {
+
+ // Find small subdiagonal element
+
+ tst1 = std::max(tst1,abs(d[l]) + abs(e[l]));
+ int m = l;
+
+ // Original while-loop from Java code
+ while (m < n) {
+ if (abs(e[m]) <= eps*tst1) {
+ break;
+ }
+ m++;
+ }
+
+
+ // If m == l, d[l] is an eigenvalue,
+ // otherwise, iterate.
+
+ if (m > l) {
+ int iter = 0;
+ do {
+ iter = iter + 1; // (Could check iteration count here.)
+
+ // Compute implicit shift
+
+ Real g = d[l];
+ Real p = (d[l+1] - g) / (2.0 * e[l]);
+ Real r = hypot(p,1.0);
+ if (p < 0) {
+ r = -r;
+ }
+ d[l] = e[l] / (p + r);
+ d[l+1] = e[l] * (p + r);
+ Real dl1 = d[l+1];
+ Real h = g - d[l];
+ for (int i = l+2; i < n; i++) {
+ d[i] -= h;
+ }
+ f = f + h;
+
+ // Implicit QL transformation.
+
+ p = d[m];
+ Real c = 1.0;
+ Real c2 = c;
+ Real c3 = c;
+ Real el1 = e[l+1];
+ Real s = 0.0;
+ Real s2 = 0.0;
+ for (int i = m-1; i >= l; i--) {
+ c3 = c2;
+ c2 = c;
+ s2 = s;
+ g = c * e[i];
+ h = c * p;
+ r = hypot(p,e[i]);
+ e[i+1] = s * r;
+ s = e[i] / r;
+ c = p / r;
+ p = c * d[i] - s * g;
+ d[i+1] = h + s * (c * g + s * d[i]);
+
+ // Accumulate transformation.
+
+ for (int k = 0; k < n; k++) {
+ h = V[k][i+1];
+ V[k][i+1] = s * V[k][i] + c * h;
+ V[k][i] = c * V[k][i] - s * h;
+ }
+ }
+ p = -s * s2 * c3 * el1 * e[l] / dl1;
+ e[l] = s * p;
+ d[l] = c * p;
+
+ // Check for convergence.
+
+ } while (abs(e[l]) > eps*tst1);
+ }
+ d[l] = d[l] + f;
+ e[l] = 0.0;
+ }
+
+ // Sort eigenvalues and corresponding vectors.
+
+ for (int i = 0; i < n-1; i++) {
+ int k = i;
+ Real p = d[i];
+ for (int j = i+1; j < n; j++) {
+ if (d[j] < p) {
+ k = j;
+ p = d[j];
+ }
+ }
+ if (k != i) {
+ d[k] = d[i];
+ d[i] = p;
+ for (int j = 0; j < n; j++) {
+ p = V[j][i];
+ V[j][i] = V[j][k];
+ V[j][k] = p;
+ }
+ }
+ }
+ }
+
+ // Nonsymmetric reduction to Hessenberg form.
+
+ void orthes () {
+
+ // This is derived from the Algol procedures orthes and ortran,
+ // by Martin and Wilkinson, Handbook for Auto. Comp.,
+ // Vol.ii-Linear Algebra, and the corresponding
+ // Fortran subroutines in EISPACK.
+
+ int low = 0;
+ int high = n-1;
+
+ for (int m = low+1; m <= high-1; m++) {
+
+ // Scale column.
+
+ Real scale = 0.0;
+ for (int i = m; i <= high; i++) {
+ scale = scale + abs(H[i][m-1]);
+ }
+ if (scale != 0.0) {
+
+ // Compute Householder transformation.
+
+ Real h = 0.0;
+ for (int i = high; i >= m; i--) {
+ ort[i] = H[i][m-1]/scale;
+ h += ort[i] * ort[i];
+ }
+ Real g = sqrt(h);
+ if (ort[m] > 0) {
+ g = -g;
+ }
+ h = h - ort[m] * g;
+ ort[m] = ort[m] - g;
+
+ // Apply Householder similarity transformation
+ // H = (I-u*u'/h)*H*(I-u*u')/h)
+
+ for (int j = m; j < n; j++) {
+ Real f = 0.0;
+ for (int i = high; i >= m; i--) {
+ f += ort[i]*H[i][j];
+ }
+ f = f/h;
+ for (int i = m; i <= high; i++) {
+ H[i][j] -= f*ort[i];
+ }
+ }
+
+ for (int i = 0; i <= high; i++) {
+ Real f = 0.0;
+ for (int j = high; j >= m; j--) {
+ f += ort[j]*H[i][j];
+ }
+ f = f/h;
+ for (int j = m; j <= high; j++) {
+ H[i][j] -= f*ort[j];
+ }
+ }
+ ort[m] = scale*ort[m];
+ H[m][m-1] = scale*g;
+ }
+ }
+
+ // Accumulate transformations (Algol's ortran).
+
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ V[i][j] = (i == j ? 1.0 : 0.0);
+ }
+ }
+
+ for (int m = high-1; m >= low+1; m--) {
+ if (H[m][m-1] != 0.0) {
+ for (int i = m+1; i <= high; i++) {
+ ort[i] = H[i][m-1];
+ }
+ for (int j = m; j <= high; j++) {
+ Real g = 0.0;
+ for (int i = m; i <= high; i++) {
+ g += ort[i] * V[i][j];
+ }
+ // Double division avoids possible underflow
+ g = (g / ort[m]) / H[m][m-1];
+ for (int i = m; i <= high; i++) {
+ V[i][j] += g * ort[i];
+ }
+ }
+ }
+ }
+ }
+
+
+ // Complex scalar division.
+
+ Real cdivr, cdivi;
+ void cdiv(Real xr, Real xi, Real yr, Real yi) {
+ Real r,d;
+ if (abs(yr) > abs(yi)) {
+ r = yi/yr;
+ d = yr + r*yi;
+ cdivr = (xr + r*xi)/d;
+ cdivi = (xi - r*xr)/d;
+ } else {
+ r = yr/yi;
+ d = yi + r*yr;
+ cdivr = (r*xr + xi)/d;
+ cdivi = (r*xi - xr)/d;
+ }
+ }
+
+
+ // Nonsymmetric reduction from Hessenberg to real Schur form.
+
+ void hqr2 () {
+
+ // This is derived from the Algol procedure hqr2,
+ // by Martin and Wilkinson, Handbook for Auto. Comp.,
+ // Vol.ii-Linear Algebra, and the corresponding
+ // Fortran subroutine in EISPACK.
+
+ // Initialize
+
+ int nn = this->n;
+ int n = nn-1;
+ int low = 0;
+ int high = nn-1;
+ Real eps = pow(2.0,-52.0);
+ Real exshift = 0.0;
+ Real p=0,q=0,r=0,s=0,z=0,t,w,x,y;
+
+ // Store roots isolated by balanc and compute matrix norm
+
+ Real norm = 0.0;
+ for (int i = 0; i < nn; i++) {
+ if ((i < low) || (i > high)) {
+ d[i] = H[i][i];
+ e[i] = 0.0;
+ }
+ for (int j = std::max(i-1,0); j < nn; j++) {
+ norm = norm + abs(H[i][j]);
+ }
+ }
+
+ // Outer loop over eigenvalue index
+
+ int iter = 0;
+ while (n >= low) {
+
+ // Look for single small sub-diagonal element
+
+ int l = n;
+ while (l > low) {
+ s = abs(H[l-1][l-1]) + abs(H[l][l]);
+ if (s == 0.0) {
+ s = norm;
+ }
+ if (abs(H[l][l-1]) < eps * s) {
+ break;
+ }
+ l--;
+ }
+
+ // Check for convergence
+ // One root found
+
+ if (l == n) {
+ H[n][n] = H[n][n] + exshift;
+ d[n] = H[n][n];
+ e[n] = 0.0;
+ n--;
+ iter = 0;
+
+ // Two roots found
+
+ } else if (l == n-1) {
+ w = H[n][n-1] * H[n-1][n];
+ p = (H[n-1][n-1] - H[n][n]) / 2.0;
+ q = p * p + w;
+ z = sqrt(abs(q));
+ H[n][n] = H[n][n] + exshift;
+ H[n-1][n-1] = H[n-1][n-1] + exshift;
+ x = H[n][n];
+
+ // Real pair
+
+ if (q >= 0) {
+ if (p >= 0) {
+ z = p + z;
+ } else {
+ z = p - z;
+ }
+ d[n-1] = x + z;
+ d[n] = d[n-1];
+ if (z != 0.0) {
+ d[n] = x - w / z;
+ }
+ e[n-1] = 0.0;
+ e[n] = 0.0;
+ x = H[n][n-1];
+ s = abs(x) + abs(z);
+ p = x / s;
+ q = z / s;
+ r = sqrt(p * p+q * q);
+ p = p / r;
+ q = q / r;
+
+ // Row modification
+
+ for (int j = n-1; j < nn; j++) {
+ z = H[n-1][j];
+ H[n-1][j] = q * z + p * H[n][j];
+ H[n][j] = q * H[n][j] - p * z;
+ }
+
+ // Column modification
+
+ for (int i = 0; i <= n; i++) {
+ z = H[i][n-1];
+ H[i][n-1] = q * z + p * H[i][n];
+ H[i][n] = q * H[i][n] - p * z;
+ }
+
+ // Accumulate transformations
+
+ for (int i = low; i <= high; i++) {
+ z = V[i][n-1];
+ V[i][n-1] = q * z + p * V[i][n];
+ V[i][n] = q * V[i][n] - p * z;
+ }
+
+ // Complex pair
+
+ } else {
+ d[n-1] = x + p;
+ d[n] = x + p;
+ e[n-1] = z;
+ e[n] = -z;
+ }
+ n = n - 2;
+ iter = 0;
+
+ // No convergence yet
+
+ } else {
+
+ // Form shift
+
+ x = H[n][n];
+ y = 0.0;
+ w = 0.0;
+ if (l < n) {
+ y = H[n-1][n-1];
+ w = H[n][n-1] * H[n-1][n];
+ }
+
+ // Wilkinson's original ad hoc shift
+
+ if (iter == 10) {
+ exshift += x;
+ for (int i = low; i <= n; i++) {
+ H[i][i] -= x;
+ }
+ s = abs(H[n][n-1]) + abs(H[n-1][n-2]);
+ x = y = 0.75 * s;
+ w = -0.4375 * s * s;
+ }
+
+ // MATLAB's new ad hoc shift
+
+ if (iter == 30) {
+ s = (y - x) / 2.0;
+ s = s * s + w;
+ if (s > 0) {
+ s = sqrt(s);
+ if (y < x) {
+ s = -s;
+ }
+ s = x - w / ((y - x) / 2.0 + s);
+ for (int i = low; i <= n; i++) {
+ H[i][i] -= s;
+ }
+ exshift += s;
+ x = y = w = 0.964;
+ }
+ }
+
+ iter = iter + 1; // (Could check iteration count here.)
+
+ // Look for two consecutive small sub-diagonal elements
+
+ int m = n-2;
+ while (m >= l) {
+ z = H[m][m];
+ r = x - z;
+ s = y - z;
+ p = (r * s - w) / H[m+1][m] + H[m][m+1];
+ q = H[m+1][m+1] - z - r - s;
+ r = H[m+2][m+1];
+ s = abs(p) + abs(q) + abs(r);
+ p = p / s;
+ q = q / s;
+ r = r / s;
+ if (m == l) {
+ break;
+ }
+ if (abs(H[m][m-1]) * (abs(q) + abs(r)) <
+ eps * (abs(p) * (abs(H[m-1][m-1]) + abs(z) +
+ abs(H[m+1][m+1])))) {
+ break;
+ }
+ m--;
+ }
+
+ for (int i = m+2; i <= n; i++) {
+ H[i][i-2] = 0.0;
+ if (i > m+2) {
+ H[i][i-3] = 0.0;
+ }
+ }
+
+ // Double QR step involving rows l:n and columns m:n
+
+ for (int k = m; k <= n-1; k++) {
+ int notlast = (k != n-1);
+ if (k != m) {
+ p = H[k][k-1];
+ q = H[k+1][k-1];
+ r = (notlast ? H[k+2][k-1] : 0.0);
+ x = abs(p) + abs(q) + abs(r);
+ if (x != 0.0) {
+ p = p / x;
+ q = q / x;
+ r = r / x;
+ }
+ }
+ if (x == 0.0) {
+ break;
+ }
+ s = sqrt(p * p + q * q + r * r);
+ if (p < 0) {
+ s = -s;
+ }
+ if (s != 0) {
+ if (k != m) {
+ H[k][k-1] = -s * x;
+ } else if (l != m) {
+ H[k][k-1] = -H[k][k-1];
+ }
+ p = p + s;
+ x = p / s;
+ y = q / s;
+ z = r / s;
+ q = q / p;
+ r = r / p;
+
+ // Row modification
+
+ for (int j = k; j < nn; j++) {
+ p = H[k][j] + q * H[k+1][j];
+ if (notlast) {
+ p = p + r * H[k+2][j];
+ H[k+2][j] = H[k+2][j] - p * z;
+ }
+ H[k][j] = H[k][j] - p * x;
+ H[k+1][j] = H[k+1][j] - p * y;
+ }
+
+ // Column modification
+
+ for (int i = 0; i <= std::min(n,k+3); i++) {
+ p = x * H[i][k] + y * H[i][k+1];
+ if (notlast) {
+ p = p + z * H[i][k+2];
+ H[i][k+2] = H[i][k+2] - p * r;
+ }
+ H[i][k] = H[i][k] - p;
+ H[i][k+1] = H[i][k+1] - p * q;
+ }
+
+ // Accumulate transformations
+
+ for (int i = low; i <= high; i++) {
+ p = x * V[i][k] + y * V[i][k+1];
+ if (notlast) {
+ p = p + z * V[i][k+2];
+ V[i][k+2] = V[i][k+2] - p * r;
+ }
+ V[i][k] = V[i][k] - p;
+ V[i][k+1] = V[i][k+1] - p * q;
+ }
+ } // (s != 0)
+ } // k loop
+ } // check convergence
+ } // while (n >= low)
+
+ // Backsubstitute to find vectors of upper triangular form
+
+ if (norm == 0.0) {
+ return;
+ }
+
+ for (n = nn-1; n >= 0; n--) {
+ p = d[n];
+ q = e[n];
+
+ // Real vector
+
+ if (q == 0) {
+ int l = n;
+ H[n][n] = 1.0;
+ for (int i = n-1; i >= 0; i--) {
+ w = H[i][i] - p;
+ r = 0.0;
+ for (int j = l; j <= n; j++) {
+ r = r + H[i][j] * H[j][n];
+ }
+ if (e[i] < 0.0) {
+ z = w;
+ s = r;
+ } else {
+ l = i;
+ if (e[i] == 0.0) {
+ if (w != 0.0) {
+ H[i][n] = -r / w;
+ } else {
+ H[i][n] = -r / (eps * norm);
+ }
+
+ // Solve real equations
+
+ } else {
+ x = H[i][i+1];
+ y = H[i+1][i];
+ q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
+ t = (x * s - z * r) / q;
+ H[i][n] = t;
+ if (abs(x) > abs(z)) {
+ H[i+1][n] = (-r - w * t) / x;
+ } else {
+ H[i+1][n] = (-s - y * t) / z;
+ }
+ }
+
+ // Overflow control
+
+ t = abs(H[i][n]);
+ if ((eps * t) * t > 1) {
+ for (int j = i; j <= n; j++) {
+ H[j][n] = H[j][n] / t;
+ }
+ }
+ }
+ }
+
+ // Complex vector
+
+ } else if (q < 0) {
+ int l = n-1;
+
+ // Last vector component imaginary so matrix is triangular
+
+ if (abs(H[n][n-1]) > abs(H[n-1][n])) {
+ H[n-1][n-1] = q / H[n][n-1];
+ H[n-1][n] = -(H[n][n] - p) / H[n][n-1];
+ } else {
+ cdiv(0.0,-H[n-1][n],H[n-1][n-1]-p,q);
+ H[n-1][n-1] = cdivr;
+ H[n-1][n] = cdivi;
+ }
+ H[n][n-1] = 0.0;
+ H[n][n] = 1.0;
+ for (int i = n-2; i >= 0; i--) {
+ Real ra,sa,vr,vi;
+ ra = 0.0;
+ sa = 0.0;
+ for (int j = l; j <= n; j++) {
+ ra = ra + H[i][j] * H[j][n-1];
+ sa = sa + H[i][j] * H[j][n];
+ }
+ w = H[i][i] - p;
+
+ if (e[i] < 0.0) {
+ z = w;
+ r = ra;
+ s = sa;
+ } else {
+ l = i;
+ if (e[i] == 0) {
+ cdiv(-ra,-sa,w,q);
+ H[i][n-1] = cdivr;
+ H[i][n] = cdivi;
+ } else {
+
+ // Solve complex equations
+
+ x = H[i][i+1];
+ y = H[i+1][i];
+ vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
+ vi = (d[i] - p) * 2.0 * q;
+ if ((vr == 0.0) && (vi == 0.0)) {
+ vr = eps * norm * (abs(w) + abs(q) +
+ abs(x) + abs(y) + abs(z));
+ }
+ cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
+ H[i][n-1] = cdivr;
+ H[i][n] = cdivi;
+ if (abs(x) > (abs(z) + abs(q))) {
+ H[i+1][n-1] = (-ra - w * H[i][n-1] + q * H[i][n]) / x;
+ H[i+1][n] = (-sa - w * H[i][n] - q * H[i][n-1]) / x;
+ } else {
+ cdiv(-r-y*H[i][n-1],-s-y*H[i][n],z,q);
+ H[i+1][n-1] = cdivr;
+ H[i+1][n] = cdivi;
+ }
+ }
+
+ // Overflow control
+
+ t = std::max(abs(H[i][n-1]),abs(H[i][n]));
+ if ((eps * t) * t > 1) {
+ for (int j = i; j <= n; j++) {
+ H[j][n-1] = H[j][n-1] / t;
+ H[j][n] = H[j][n] / t;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Vectors of isolated roots
+
+ for (int i = 0; i < nn; i++) {
+ if (i < low || i > high) {
+ for (int j = i; j < nn; j++) {
+ V[i][j] = H[i][j];
+ }
+ }
+ }
+
+ // Back transformation to get eigenvectors of original matrix
+
+ for (int j = nn-1; j >= low; j--) {
+ for (int i = low; i <= high; i++) {
+ z = 0.0;
+ for (int k = low; k <= std::min(j,high); k++) {
+ z = z + V[i][k] * H[k][j];
+ }
+ V[i][j] = z;
+ }
+ }
+ }
+
+public:
+
+
+ /** Check for symmetry, then construct the eigenvalue decomposition
+ @param A Square real (non-complex) matrix
+ */
+
+ Eigenvalue(const TNT::Array2D<Real> &A) {
+ n = A.dim2();
+ V = Array2D<Real>(n,n);
+ d = Array1D<Real>(n);
+ e = Array1D<Real>(n);
+
+ issymmetric = 1;
+ for (int j = 0; (j < n) && issymmetric; j++) {
+ for (int i = 0; (i < n) && issymmetric; i++) {
+ issymmetric = (A[i][j] == A[j][i]);
+ }
+ }
+
+ if (issymmetric) {
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ V[i][j] = A[i][j];
+ }
+ }
+
+ // Tridiagonalize.
+ tred2();
+
+ // Diagonalize.
+ tql2();
+
+ } else {
+ H = TNT::Array2D<Real>(n,n);
+ ort = TNT::Array1D<Real>(n);
+
+ for (int j = 0; j < n; j++) {
+ for (int i = 0; i < n; i++) {
+ H[i][j] = A[i][j];
+ }
+ }
+
+ // Reduce to Hessenberg form.
+ orthes();
+
+ // Reduce Hessenberg to real Schur form.
+ hqr2();
+ }
+ }
+
+
+ /** Return the eigenvector matrix
+ @return V
+ */
+
+ void getV (TNT::Array2D<Real> &V_) {
+ V_ = V;
+ return;
+ }
+
+ /** Return the real parts of the eigenvalues
+ @return real(diag(D))
+ */
+
+ void getRealEigenvalues (TNT::Array1D<Real> &d_) {
+ d_ = d;
+ return ;
+ }
+
+ /** Return the imaginary parts of the eigenvalues
+ in parameter e_.
+
+ @pararm e_: new matrix with imaginary parts of the eigenvalues.
+ */
+ void getImagEigenvalues (TNT::Array1D<Real> &e_) {
+ e_ = e;
+ return;
+ }
+
+
+/**
+ Computes the block diagonal eigenvalue matrix.
+ If the original matrix A is not symmetric, then the eigenvalue
+ matrix D is block diagonal with the real eigenvalues in 1-by-1
+ blocks and any complex eigenvalues,
+ a + i*b, in 2-by-2 blocks, [a, b; -b, a]. That is, if the complex
+ eigenvalues look like
+<pre>
+
+ u + iv . . . . .
+ . u - iv . . . .
+ . . a + ib . . .
+ . . . a - ib . .
+ . . . . x .
+ . . . . . y
+</pre>
+ then D looks like
+<pre>
+
+ u v . . . .
+ -v u . . . .
+ . . a b . .
+ . . -b a . .
+ . . . . x .
+ . . . . . y
+</pre>
+ This keeps V a real matrix in both symmetric and non-symmetric
+ cases, and A*V = V*D.
+
+ @param D: upon return, the matrix is filled with the block diagonal
+ eigenvalue matrix.
+
+*/
+ void getD (TNT::Array2D<Real> &D) {
+ D = Array2D<Real>(n,n);
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ D[i][j] = 0.0;
+ }
+ D[i][i] = d[i];
+ if (e[i] > 0) {
+ D[i][i+1] = e[i];
+ } else if (e[i] < 0) {
+ D[i][i-1] = e[i];
+ }
+ }
+ }
+};
+
+} //namespace JAMA
+
+
+#endif
+// JAMA_EIG_H
diff --git a/lib/include/tnt/jama_lu.h b/lib/include/tnt/jama_lu.h
new file mode 100644
index 0000000..e95b433
--- /dev/null
+++ b/lib/include/tnt/jama_lu.h
@@ -0,0 +1,323 @@
+#ifndef JAMA_LU_H
+#define JAMA_LU_H
+
+#include "tnt.h"
+#include <algorithm>
+//for min(), max() below
+
+using namespace TNT;
+using namespace std;
+
+
+// Modification by Willem Jan Palenstijn, 2010-03-11:
+// Use std::min() instead of min()
+
+namespace JAMA
+{
+
+ /** LU Decomposition.
+ <P>
+ For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
+ unit lower triangular matrix L, an n-by-n upper triangular matrix U,
+ and a permutation vector piv of length m so that A(piv,:) = L*U.
+ If m < n, then L is m-by-m and U is m-by-n.
+ <P>
+ The LU decompostion with pivoting always exists, even if the matrix is
+ singular, so the constructor will never fail. The primary use of the
+ LU decomposition is in the solution of square systems of simultaneous
+ linear equations. This will fail if isNonsingular() returns false.
+ */
+template <class Real>
+class LU
+{
+
+
+
+ /* Array for internal storage of decomposition. */
+ Array2D<Real> LU_;
+ int m, n, pivsign;
+ Array1D<int> piv;
+
+
+ Array2D<Real> permute_copy(const Array2D<Real> &A,
+ const Array1D<int> &piv, int j0, int j1)
+ {
+ int piv_length = piv.dim();
+
+ Array2D<Real> X(piv_length, j1-j0+1);
+
+
+ for (int i = 0; i < piv_length; i++)
+ for (int j = j0; j <= j1; j++)
+ X[i][j-j0] = A[piv[i]][j];
+
+ return X;
+ }
+
+ Array1D<Real> permute_copy(const Array1D<Real> &A,
+ const Array1D<int> &piv)
+ {
+ int piv_length = piv.dim();
+ if (piv_length != A.dim())
+ return Array1D<Real>();
+
+ Array1D<Real> x(piv_length);
+
+
+ for (int i = 0; i < piv_length; i++)
+ x[i] = A[piv[i]];
+
+ return x;
+ }
+
+
+ public :
+
+ /** LU Decomposition
+ @param A Rectangular matrix
+ @return LU Decomposition object to access L, U and piv.
+ */
+
+ LU (const Array2D<Real> &A) : LU_(A.copy()), m(A.dim1()), n(A.dim2()),
+ piv(A.dim1())
+
+ {
+
+ // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+
+
+ for (int i = 0; i < m; i++) {
+ piv[i] = i;
+ }
+ pivsign = 1;
+ Real *LUrowi = 0;;
+ Array1D<Real> LUcolj(m);
+
+ // Outer loop.
+
+ for (int j = 0; j < n; j++) {
+
+ // Make a copy of the j-th column to localize references.
+
+ for (int i = 0; i < m; i++) {
+ LUcolj[i] = LU_[i][j];
+ }
+
+ // Apply previous transformations.
+
+ for (int i = 0; i < m; i++) {
+ LUrowi = LU_[i];
+
+ // Most of the time is spent in the following dot product.
+
+ int kmax = std::min(i,j);
+ double s = 0.0;
+ for (int k = 0; k < kmax; k++) {
+ s += LUrowi[k]*LUcolj[k];
+ }
+
+ LUrowi[j] = LUcolj[i] -= s;
+ }
+
+ // Find pivot and exchange if necessary.
+
+ int p = j;
+ for (int i = j+1; i < m; i++) {
+ if (abs(LUcolj[i]) > abs(LUcolj[p])) {
+ p = i;
+ }
+ }
+ if (p != j) {
+ int k=0;
+ for (k = 0; k < n; k++) {
+ double t = LU_[p][k];
+ LU_[p][k] = LU_[j][k];
+ LU_[j][k] = t;
+ }
+ k = piv[p];
+ piv[p] = piv[j];
+ piv[j] = k;
+ pivsign = -pivsign;
+ }
+
+ // Compute multipliers.
+
+ if ((j < m) && (LU_[j][j] != 0.0)) {
+ for (int i = j+1; i < m; i++) {
+ LU_[i][j] /= LU_[j][j];
+ }
+ }
+ }
+ }
+
+
+ /** Is the matrix nonsingular?
+ @return 1 (true) if upper triangular factor U (and hence A)
+ is nonsingular, 0 otherwise.
+ */
+
+ int isNonsingular () {
+ for (int j = 0; j < n; j++) {
+ if (LU_[j][j] == 0)
+ return 0;
+ }
+ return 1;
+ }
+
+ /** Return lower triangular factor
+ @return L
+ */
+
+ Array2D<Real> getL () {
+ Array2D<Real> L_(m,n);
+ for (int i = 0; i < m; i++) {
+ for (int j = 0; j < n; j++) {
+ if (i > j) {
+ L_[i][j] = LU_[i][j];
+ } else if (i == j) {
+ L_[i][j] = 1.0;
+ } else {
+ L_[i][j] = 0.0;
+ }
+ }
+ }
+ return L_;
+ }
+
+ /** Return upper triangular factor
+ @return U portion of LU factorization.
+ */
+
+ Array2D<Real> getU () {
+ Array2D<Real> U_(n,n);
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ if (i <= j) {
+ U_[i][j] = LU_[i][j];
+ } else {
+ U_[i][j] = 0.0;
+ }
+ }
+ }
+ return U_;
+ }
+
+ /** Return pivot permutation vector
+ @return piv
+ */
+
+ Array1D<int> getPivot () {
+ return piv;
+ }
+
+
+ /** Compute determinant using LU factors.
+ @return determinant of A, or 0 if A is not square.
+ */
+
+ Real det () {
+ if (m != n) {
+ return Real(0);
+ }
+ Real d = Real(pivsign);
+ for (int j = 0; j < n; j++) {
+ d *= LU_[j][j];
+ }
+ return d;
+ }
+
+ /** Solve A*X = B
+ @param B A Matrix with as many rows as A and any number of columns.
+ @return X so that L*U*X = B(piv,:), if B is nonconformant, returns
+ 0x0 (null) array.
+ */
+
+ Array2D<Real> solve (const Array2D<Real> &B)
+ {
+
+ /* Dimensions: A is mxn, X is nxk, B is mxk */
+
+ if (B.dim1() != m) {
+ return Array2D<Real>(0,0);
+ }
+ if (!isNonsingular()) {
+ return Array2D<Real>(0,0);
+ }
+
+ // Copy right hand side with pivoting
+ int nx = B.dim2();
+
+
+ Array2D<Real> X = permute_copy(B, piv, 0, nx-1);
+
+ // Solve L*Y = B(piv,:)
+ for (int k = 0; k < n; k++) {
+ for (int i = k+1; i < n; i++) {
+ for (int j = 0; j < nx; j++) {
+ X[i][j] -= X[k][j]*LU_[i][k];
+ }
+ }
+ }
+ // Solve U*X = Y;
+ for (int k = n-1; k >= 0; k--) {
+ for (int j = 0; j < nx; j++) {
+ X[k][j] /= LU_[k][k];
+ }
+ for (int i = 0; i < k; i++) {
+ for (int j = 0; j < nx; j++) {
+ X[i][j] -= X[k][j]*LU_[i][k];
+ }
+ }
+ }
+ return X;
+ }
+
+
+ /** Solve A*x = b, where x and b are vectors of length equal
+ to the number of rows in A.
+
+ @param b a vector (Array1D> of length equal to the first dimension
+ of A.
+ @return x a vector (Array1D> so that L*U*x = b(piv), if B is nonconformant,
+ returns 0x0 (null) array.
+ */
+
+ Array1D<Real> solve (const Array1D<Real> &b)
+ {
+
+ /* Dimensions: A is mxn, X is nxk, B is mxk */
+
+ if (b.dim1() != m) {
+ return Array1D<Real>();
+ }
+ if (!isNonsingular()) {
+ return Array1D<Real>();
+ }
+
+
+ Array1D<Real> x = permute_copy(b, piv);
+
+ // Solve L*Y = B(piv)
+ for (int k = 0; k < n; k++) {
+ for (int i = k+1; i < n; i++) {
+ x[i] -= x[k]*LU_[i][k];
+ }
+ }
+
+ // Solve U*X = Y;
+ for (int k = n-1; k >= 0; k--) {
+ x[k] /= LU_[k][k];
+ for (int i = 0; i < k; i++)
+ x[i] -= x[k]*LU_[i][k];
+ }
+
+
+ return x;
+ }
+
+}; /* class LU */
+
+} /* namespace JAMA */
+
+#endif
+/* JAMA_LU_H */
diff --git a/lib/include/tnt/jama_qr.h b/lib/include/tnt/jama_qr.h
new file mode 100644
index 0000000..98d37f5
--- /dev/null
+++ b/lib/include/tnt/jama_qr.h
@@ -0,0 +1,326 @@
+#ifndef JAMA_QR_H
+#define JAMA_QR_H
+
+#include "tnt_array1d.h"
+#include "tnt_array2d.h"
+#include "tnt_math_utils.h"
+
+namespace JAMA
+{
+
+/**
+<p>
+ Classical QR Decompisition:
+ for an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
+ orthogonal matrix Q and an n-by-n upper triangular matrix R so that
+ A = Q*R.
+<P>
+ The QR decompostion always exists, even if the matrix does not have
+ full rank, so the constructor will never fail. The primary use of the
+ QR decomposition is in the least squares solution of nonsquare systems
+ of simultaneous linear equations. This will fail if isFullRank()
+ returns 0 (false).
+
+<p>
+ The Q and R factors can be retrived via the getQ() and getR()
+ methods. Furthermore, a solve() method is provided to find the
+ least squares solution of Ax=b using the QR factors.
+
+ <p>
+ (Adapted from JAMA, a Java Matrix Library, developed by jointly
+ by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
+*/
+
+template <class Real>
+class QR {
+
+
+ /** Array for internal storage of decomposition.
+ @serial internal array storage.
+ */
+
+ TNT::Array2D<Real> QR_;
+
+ /** Row and column dimensions.
+ @serial column dimension.
+ @serial row dimension.
+ */
+ int m, n;
+
+ /** Array for internal storage of diagonal of R.
+ @serial diagonal of R.
+ */
+ TNT::Array1D<Real> Rdiag;
+
+
+public:
+
+/**
+ Create a QR factorization object for A.
+
+ @param A rectangular (m>=n) matrix.
+*/
+ QR(const TNT::Array2D<Real> &A) /* constructor */
+ {
+ QR_ = A.copy();
+ m = A.dim1();
+ n = A.dim2();
+ Rdiag = TNT::Array1D<Real>(n);
+ int i=0, j=0, k=0;
+
+ // Main loop.
+ for (k = 0; k < n; k++) {
+ // Compute 2-norm of k-th column without under/overflow.
+ Real nrm = 0;
+ for (i = k; i < m; i++) {
+ nrm = TNT::hypot(nrm,QR_[i][k]);
+ }
+
+ if (nrm != 0.0) {
+ // Form k-th Householder vector.
+ if (QR_[k][k] < 0) {
+ nrm = -nrm;
+ }
+ for (i = k; i < m; i++) {
+ QR_[i][k] /= nrm;
+ }
+ QR_[k][k] += 1.0;
+
+ // Apply transformation to remaining columns.
+ for (j = k+1; j < n; j++) {
+ Real s = 0.0;
+ for (i = k; i < m; i++) {
+ s += QR_[i][k]*QR_[i][j];
+ }
+ s = -s/QR_[k][k];
+ for (i = k; i < m; i++) {
+ QR_[i][j] += s*QR_[i][k];
+ }
+ }
+ }
+ Rdiag[k] = -nrm;
+ }
+ }
+
+
+/**
+ Flag to denote the matrix is of full rank.
+
+ @return 1 if matrix is full rank, 0 otherwise.
+*/
+ int isFullRank() const
+ {
+ for (int j = 0; j < n; j++)
+ {
+ if (Rdiag[j] == 0)
+ return 0;
+ }
+ return 1;
+ }
+
+
+
+
+ /**
+
+ Retreive the Householder vectors from QR factorization
+ @returns lower trapezoidal matrix whose columns define the reflections
+ */
+
+ TNT::Array2D<Real> getHouseholder (void) const
+ {
+ TNT::Array2D<Real> H(m,n);
+
+ /* note: H is completely filled in by algorithm, so
+ initializaiton of H is not necessary.
+ */
+ for (int i = 0; i < m; i++)
+ {
+ for (int j = 0; j < n; j++)
+ {
+ if (i >= j) {
+ H[i][j] = QR_[i][j];
+ } else {
+ H[i][j] = 0.0;
+ }
+ }
+ }
+ return H;
+ }
+
+
+
+ /** Return the upper triangular factor, R, of the QR factorization
+ @return R
+ */
+
+ TNT::Array2D<Real> getR() const
+ {
+ TNT::Array2D<Real> R(n,n);
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ if (i < j) {
+ R[i][j] = QR_[i][j];
+ } else if (i == j) {
+ R[i][j] = Rdiag[i];
+ } else {
+ R[i][j] = 0.0;
+ }
+ }
+ }
+ return R;
+ }
+
+
+
+
+
+ /**
+ Generate and return the (economy-sized) orthogonal factor
+ @param Q the (ecnomy-sized) orthogonal factor (Q*R=A).
+ */
+
+ TNT::Array2D<Real> getQ() const
+ {
+ int i=0, j=0, k=0;
+
+ TNT::Array2D<Real> Q(m,n);
+ for (k = n-1; k >= 0; k--) {
+ for (i = 0; i < m; i++) {
+ Q[i][k] = 0.0;
+ }
+ Q[k][k] = 1.0;
+ for (j = k; j < n; j++) {
+ if (QR_[k][k] != 0) {
+ Real s = 0.0;
+ for (i = k; i < m; i++) {
+ s += QR_[i][k]*Q[i][j];
+ }
+ s = -s/QR_[k][k];
+ for (i = k; i < m; i++) {
+ Q[i][j] += s*QR_[i][k];
+ }
+ }
+ }
+ }
+ return Q;
+ }
+
+
+ /** Least squares solution of A*x = b
+ @param B m-length array (vector).
+ @return x n-length array (vector) that minimizes the two norm of Q*R*X-B.
+ If B is non-conformant, or if QR.isFullRank() is false,
+ the routine returns a null (0-length) vector.
+ */
+
+ TNT::Array1D<Real> solve(const TNT::Array1D<Real> &b) const
+ {
+ if (b.dim1() != m) /* arrays must be conformant */
+ return TNT::Array1D<Real>();
+
+ if ( !isFullRank() ) /* matrix is rank deficient */
+ {
+ return TNT::Array1D<Real>();
+ }
+
+ TNT::Array1D<Real> x = b.copy();
+
+ // Compute Y = transpose(Q)*b
+ for (int k = 0; k < n; k++)
+ {
+ Real s = 0.0;
+ for (int i = k; i < m; i++)
+ {
+ s += QR_[i][k]*x[i];
+ }
+ s = -s/QR_[k][k];
+ for (int i = k; i < m; i++)
+ {
+ x[i] += s*QR_[i][k];
+ }
+ }
+ // Solve R*X = Y;
+ for (int k = n-1; k >= 0; k--)
+ {
+ x[k] /= Rdiag[k];
+ for (int i = 0; i < k; i++) {
+ x[i] -= x[k]*QR_[i][k];
+ }
+ }
+
+
+ /* return n x nx portion of X */
+ TNT::Array1D<Real> x_(n);
+ for (int i=0; i<n; i++)
+ x_[i] = x[i];
+
+ return x_;
+ }
+
+ /** Least squares solution of A*X = B
+ @param B m x k Array (must conform).
+ @return X n x k Array that minimizes the two norm of Q*R*X-B. If
+ B is non-conformant, or if QR.isFullRank() is false,
+ the routine returns a null (0x0) array.
+ */
+
+ TNT::Array2D<Real> solve(const TNT::Array2D<Real> &B) const
+ {
+ if (B.dim1() != m) /* arrays must be conformant */
+ return TNT::Array2D<Real>(0,0);
+
+ if ( !isFullRank() ) /* matrix is rank deficient */
+ {
+ return TNT::Array2D<Real>(0,0);
+ }
+
+ int nx = B.dim2();
+ TNT::Array2D<Real> X = B.copy();
+ int i=0, j=0, k=0;
+
+ // Compute Y = transpose(Q)*B
+ for (k = 0; k < n; k++) {
+ for (j = 0; j < nx; j++) {
+ Real s = 0.0;
+ for (i = k; i < m; i++) {
+ s += QR_[i][k]*X[i][j];
+ }
+ s = -s/QR_[k][k];
+ for (i = k; i < m; i++) {
+ X[i][j] += s*QR_[i][k];
+ }
+ }
+ }
+ // Solve R*X = Y;
+ for (k = n-1; k >= 0; k--) {
+ for (j = 0; j < nx; j++) {
+ X[k][j] /= Rdiag[k];
+ }
+ for (i = 0; i < k; i++) {
+ for (j = 0; j < nx; j++) {
+ X[i][j] -= X[k][j]*QR_[i][k];
+ }
+ }
+ }
+
+
+ /* return n x nx portion of X */
+ TNT::Array2D<Real> X_(n,nx);
+ for (i=0; i<n; i++)
+ for (j=0; j<nx; j++)
+ X_[i][j] = X[i][j];
+
+ return X_;
+ }
+
+
+};
+
+
+}
+// namespace JAMA
+
+#endif
+// JAMA_QR__H
+
diff --git a/lib/include/tnt/jama_svd.h b/lib/include/tnt/jama_svd.h
new file mode 100644
index 0000000..72ce3a7
--- /dev/null
+++ b/lib/include/tnt/jama_svd.h
@@ -0,0 +1,543 @@
+#ifndef JAMA_SVD_H
+#define JAMA_SVD_H
+
+
+#include "tnt_array1d.h"
+#include "tnt_array1d_utils.h"
+#include "tnt_array2d.h"
+#include "tnt_array2d_utils.h"
+#include "tnt_math_utils.h"
+
+#include <algorithm>
+// for min(), max() below
+#include <cmath>
+// for abs() below
+
+using namespace TNT;
+using namespace std;
+
+
+// Modification by Willem Jan Palenstijn, 2010-03-11:
+// Use std::min() instead of min(), std::max() instead of max()
+
+
+namespace JAMA
+{
+ /** Singular Value Decomposition.
+ <P>
+ For an m-by-n matrix A with m >= n, the singular value decomposition is
+ an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
+ an n-by-n orthogonal matrix V so that A = U*S*V'.
+ <P>
+ The singular values, sigma[k] = S[k][k], are ordered so that
+ sigma[0] >= sigma[1] >= ... >= sigma[n-1].
+ <P>
+ The singular value decompostion always exists, so the constructor will
+ never fail. The matrix condition number and the effective numerical
+ rank can be computed from this decomposition.
+
+ <p>
+ (Adapted from JAMA, a Java Matrix Library, developed by jointly
+ by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
+ */
+template <class Real>
+class SVD
+{
+
+
+ Array2D<Real> U, V;
+ Array1D<Real> s;
+ int m, n;
+
+ public:
+
+
+ SVD (const Array2D<Real> &Arg) {
+
+
+ m = Arg.dim1();
+ n = Arg.dim2();
+ int nu = std::min(m,n);
+ s = Array1D<Real>(std::min(m+1,n));
+ U = Array2D<Real>(m, nu, Real(0));
+ V = Array2D<Real>(n,n);
+ Array1D<Real> e(n);
+ Array1D<Real> work(m);
+ Array2D<Real> A(Arg.copy());
+ int wantu = 1; /* boolean */
+ int wantv = 1; /* boolean */
+ int i=0, j=0, k=0;
+
+ // Reduce A to bidiagonal form, storing the diagonal elements
+ // in s and the super-diagonal elements in e.
+
+ int nct = std::min(m-1,n);
+ int nrt = std::max(0,std::min(n-2,m));
+ for (k = 0; k < std::max(nct,nrt); k++) {
+ if (k < nct) {
+
+ // Compute the transformation for the k-th column and
+ // place the k-th diagonal in s[k].
+ // Compute 2-norm of k-th column without under/overflow.
+ s[k] = 0;
+ for (i = k; i < m; i++) {
+ s[k] = hypot(s[k],A[i][k]);
+ }
+ if (s[k] != 0.0) {
+ if (A[k][k] < 0.0) {
+ s[k] = -s[k];
+ }
+ for (i = k; i < m; i++) {
+ A[i][k] /= s[k];
+ }
+ A[k][k] += 1.0;
+ }
+ s[k] = -s[k];
+ }
+ for (j = k+1; j < n; j++) {
+ if ((k < nct) && (s[k] != 0.0)) {
+
+ // Apply the transformation.
+
+ Real t(0.0);
+ for (i = k; i < m; i++) {
+ t += A[i][k]*A[i][j];
+ }
+ t = -t/A[k][k];
+ for (i = k; i < m; i++) {
+ A[i][j] += t*A[i][k];
+ }
+ }
+
+ // Place the k-th row of A into e for the
+ // subsequent calculation of the row transformation.
+
+ e[j] = A[k][j];
+ }
+ if (wantu & (k < nct)) {
+
+ // Place the transformation in U for subsequent back
+ // multiplication.
+
+ for (i = k; i < m; i++) {
+ U[i][k] = A[i][k];
+ }
+ }
+ if (k < nrt) {
+
+ // Compute the k-th row transformation and place the
+ // k-th super-diagonal in e[k].
+ // Compute 2-norm without under/overflow.
+ e[k] = 0;
+ for (i = k+1; i < n; i++) {
+ e[k] = hypot(e[k],e[i]);
+ }
+ if (e[k] != 0.0) {
+ if (e[k+1] < 0.0) {
+ e[k] = -e[k];
+ }
+ for (i = k+1; i < n; i++) {
+ e[i] /= e[k];
+ }
+ e[k+1] += 1.0;
+ }
+ e[k] = -e[k];
+ if ((k+1 < m) & (e[k] != 0.0)) {
+
+ // Apply the transformation.
+
+ for (i = k+1; i < m; i++) {
+ work[i] = 0.0;
+ }
+ for (j = k+1; j < n; j++) {
+ for (i = k+1; i < m; i++) {
+ work[i] += e[j]*A[i][j];
+ }
+ }
+ for (j = k+1; j < n; j++) {
+ Real t(-e[j]/e[k+1]);
+ for (i = k+1; i < m; i++) {
+ A[i][j] += t*work[i];
+ }
+ }
+ }
+ if (wantv) {
+
+ // Place the transformation in V for subsequent
+ // back multiplication.
+
+ for (i = k+1; i < n; i++) {
+ V[i][k] = e[i];
+ }
+ }
+ }
+ }
+
+ // Set up the final bidiagonal matrix or order p.
+
+ int p = std::min(n,m+1);
+ if (nct < n) {
+ s[nct] = A[nct][nct];
+ }
+ if (m < p) {
+ s[p-1] = 0.0;
+ }
+ if (nrt+1 < p) {
+ e[nrt] = A[nrt][p-1];
+ }
+ e[p-1] = 0.0;
+
+ // If required, generate U.
+
+ if (wantu) {
+ for (j = nct; j < nu; j++) {
+ for (i = 0; i < m; i++) {
+ U[i][j] = 0.0;
+ }
+ U[j][j] = 1.0;
+ }
+ for (k = nct-1; k >= 0; k--) {
+ if (s[k] != 0.0) {
+ for (j = k+1; j < nu; j++) {
+ Real t(0.0);
+ for (i = k; i < m; i++) {
+ t += U[i][k]*U[i][j];
+ }
+ t = -t/U[k][k];
+ for (i = k; i < m; i++) {
+ U[i][j] += t*U[i][k];
+ }
+ }
+ for (i = k; i < m; i++ ) {
+ U[i][k] = -U[i][k];
+ }
+ U[k][k] = 1.0 + U[k][k];
+ for (i = 0; i < k-1; i++) {
+ U[i][k] = 0.0;
+ }
+ } else {
+ for (i = 0; i < m; i++) {
+ U[i][k] = 0.0;
+ }
+ U[k][k] = 1.0;
+ }
+ }
+ }
+
+ // If required, generate V.
+
+ if (wantv) {
+ for (k = n-1; k >= 0; k--) {
+ if ((k < nrt) & (e[k] != 0.0)) {
+ for (j = k+1; j < nu; j++) {
+ Real t(0.0);
+ for (i = k+1; i < n; i++) {
+ t += V[i][k]*V[i][j];
+ }
+ t = -t/V[k+1][k];
+ for (i = k+1; i < n; i++) {
+ V[i][j] += t*V[i][k];
+ }
+ }
+ }
+ for (i = 0; i < n; i++) {
+ V[i][k] = 0.0;
+ }
+ V[k][k] = 1.0;
+ }
+ }
+
+ // Main iteration loop for the singular values.
+
+ int pp = p-1;
+ int iter = 0;
+ Real eps(pow(2.0,-52.0));
+ while (p > 0) {
+ int k=0;
+ int kase=0;
+
+ // Here is where a test for too many iterations would go.
+
+ // This section of the program inspects for
+ // negligible elements in the s and e arrays. On
+ // completion the variables kase and k are set as follows.
+
+ // kase = 1 if s(p) and e[k-1] are negligible and k<p
+ // kase = 2 if s(k) is negligible and k<p
+ // kase = 3 if e[k-1] is negligible, k<p, and
+ // s(k), ..., s(p) are not negligible (qr step).
+ // kase = 4 if e(p-1) is negligible (convergence).
+
+ for (k = p-2; k >= -1; k--) {
+ if (k == -1) {
+ break;
+ }
+ if (abs(e[k]) <= eps*(abs(s[k]) + abs(s[k+1]))) {
+ e[k] = 0.0;
+ break;
+ }
+ }
+ if (k == p-2) {
+ kase = 4;
+ } else {
+ int ks;
+ for (ks = p-1; ks >= k; ks--) {
+ if (ks == k) {
+ break;
+ }
+ Real t( (ks != p ? abs(e[ks]) : 0.) +
+ (ks != k+1 ? abs(e[ks-1]) : 0.));
+ if (abs(s[ks]) <= eps*t) {
+ s[ks] = 0.0;
+ break;
+ }
+ }
+ if (ks == k) {
+ kase = 3;
+ } else if (ks == p-1) {
+ kase = 1;
+ } else {
+ kase = 2;
+ k = ks;
+ }
+ }
+ k++;
+
+ // Perform the task indicated by kase.
+
+ switch (kase) {
+
+ // Deflate negligible s(p).
+
+ case 1: {
+ Real f(e[p-2]);
+ e[p-2] = 0.0;
+ for (j = p-2; j >= k; j--) {
+ Real t( hypot(s[j],f));
+ Real cs(s[j]/t);
+ Real sn(f/t);
+ s[j] = t;
+ if (j != k) {
+ f = -sn*e[j-1];
+ e[j-1] = cs*e[j-1];
+ }
+ if (wantv) {
+ for (i = 0; i < n; i++) {
+ t = cs*V[i][j] + sn*V[i][p-1];
+ V[i][p-1] = -sn*V[i][j] + cs*V[i][p-1];
+ V[i][j] = t;
+ }
+ }
+ }
+ }
+ break;
+
+ // Split at negligible s(k).
+
+ case 2: {
+ Real f(e[k-1]);
+ e[k-1] = 0.0;
+ for (j = k; j < p; j++) {
+ Real t(hypot(s[j],f));
+ Real cs( s[j]/t);
+ Real sn(f/t);
+ s[j] = t;
+ f = -sn*e[j];
+ e[j] = cs*e[j];
+ if (wantu) {
+ for (i = 0; i < m; i++) {
+ t = cs*U[i][j] + sn*U[i][k-1];
+ U[i][k-1] = -sn*U[i][j] + cs*U[i][k-1];
+ U[i][j] = t;
+ }
+ }
+ }
+ }
+ break;
+
+ // Perform one qr step.
+
+ case 3: {
+
+ // Calculate the shift.
+
+ Real scale = std::max(std::max(std::max(std::max(
+ abs(s[p-1]),abs(s[p-2])),abs(e[p-2])),
+ abs(s[k])),abs(e[k]));
+ Real sp = s[p-1]/scale;
+ Real spm1 = s[p-2]/scale;
+ Real epm1 = e[p-2]/scale;
+ Real sk = s[k]/scale;
+ Real ek = e[k]/scale;
+ Real b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/2.0;
+ Real c = (sp*epm1)*(sp*epm1);
+ Real shift = 0.0;
+ if ((b != 0.0) || (c != 0.0)) {
+ shift = sqrt(b*b + c);
+ if (b < 0.0) {
+ shift = -shift;
+ }
+ shift = c/(b + shift);
+ }
+ Real f = (sk + sp)*(sk - sp) + shift;
+ Real g = sk*ek;
+
+ // Chase zeros.
+
+ for (j = k; j < p-1; j++) {
+ Real t = hypot(f,g);
+ Real cs = f/t;
+ Real sn = g/t;
+ if (j != k) {
+ e[j-1] = t;
+ }
+ f = cs*s[j] + sn*e[j];
+ e[j] = cs*e[j] - sn*s[j];
+ g = sn*s[j+1];
+ s[j+1] = cs*s[j+1];
+ if (wantv) {
+ for (i = 0; i < n; i++) {
+ t = cs*V[i][j] + sn*V[i][j+1];
+ V[i][j+1] = -sn*V[i][j] + cs*V[i][j+1];
+ V[i][j] = t;
+ }
+ }
+ t = hypot(f,g);
+ cs = f/t;
+ sn = g/t;
+ s[j] = t;
+ f = cs*e[j] + sn*s[j+1];
+ s[j+1] = -sn*e[j] + cs*s[j+1];
+ g = sn*e[j+1];
+ e[j+1] = cs*e[j+1];
+ if (wantu && (j < m-1)) {
+ for (i = 0; i < m; i++) {
+ t = cs*U[i][j] + sn*U[i][j+1];
+ U[i][j+1] = -sn*U[i][j] + cs*U[i][j+1];
+ U[i][j] = t;
+ }
+ }
+ }
+ e[p-2] = f;
+ iter = iter + 1;
+ }
+ break;
+
+ // Convergence.
+
+ case 4: {
+
+ // Make the singular values positive.
+
+ if (s[k] <= 0.0) {
+ s[k] = (s[k] < 0.0 ? -s[k] : 0.0);
+ if (wantv) {
+ for (i = 0; i <= pp; i++) {
+ V[i][k] = -V[i][k];
+ }
+ }
+ }
+
+ // Order the singular values.
+
+ while (k < pp) {
+ if (s[k] >= s[k+1]) {
+ break;
+ }
+ Real t = s[k];
+ s[k] = s[k+1];
+ s[k+1] = t;
+ if (wantv && (k < n-1)) {
+ for (i = 0; i < n; i++) {
+ t = V[i][k+1]; V[i][k+1] = V[i][k]; V[i][k] = t;
+ }
+ }
+ if (wantu && (k < m-1)) {
+ for (i = 0; i < m; i++) {
+ t = U[i][k+1]; U[i][k+1] = U[i][k]; U[i][k] = t;
+ }
+ }
+ k++;
+ }
+ iter = 0;
+ p--;
+ }
+ break;
+ }
+ }
+ }
+
+
+ void getU (Array2D<Real> &A)
+ {
+ int minm = std::min(m+1,n);
+
+ A = Array2D<Real>(m, minm);
+
+ for (int i=0; i<m; i++)
+ for (int j=0; j<minm; j++)
+ A[i][j] = U[i][j];
+
+ }
+
+ /* Return the right singular vectors */
+
+ void getV (Array2D<Real> &A)
+ {
+ A = V;
+ }
+
+ /** Return the one-dimensional array of singular values */
+
+ void getSingularValues (Array1D<Real> &x)
+ {
+ x = s;
+ }
+
+ /** Return the diagonal matrix of singular values
+ @return S
+ */
+
+ void getS (Array2D<Real> &A) {
+ A = Array2D<Real>(n,n);
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ A[i][j] = 0.0;
+ }
+ A[i][i] = s[i];
+ }
+ }
+
+ /** Two norm (max(S)) */
+
+ Real norm2 () {
+ return s[0];
+ }
+
+ /** Two norm of condition number (max(S)/min(S)) */
+
+ Real cond () {
+ return s[0]/s[std::min(m,n)-1];
+ }
+
+ /** Effective numerical matrix rank
+ @return Number of nonnegligible singular values.
+ */
+
+ int rank ()
+ {
+ Real eps = pow(2.0,-52.0);
+ Real tol = std::max(m,n)*s[0]*eps;
+ int r = 0;
+ for (int i = 0; i < s.dim(); i++) {
+ if (s[i] > tol) {
+ r++;
+ }
+ }
+ return r;
+ }
+};
+
+}
+#endif
+// JAMA_SVD_H
diff --git a/lib/include/tnt/tnt.h b/lib/include/tnt/tnt.h
new file mode 100644
index 0000000..92463e0
--- /dev/null
+++ b/lib/include/tnt/tnt.h
@@ -0,0 +1,64 @@
+/*
+*
+* Template Numerical Toolkit (TNT): Linear Algebra Module
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+#ifndef TNT_H
+#define TNT_H
+
+
+
+//---------------------------------------------------------------------
+// Define this macro if you want TNT to track some of the out-of-bounds
+// indexing. This can encur a small run-time overhead, but is recommended
+// while developing code. It can be turned off for production runs.
+//
+// #define TNT_BOUNDS_CHECK
+//---------------------------------------------------------------------
+//
+
+//#define TNT_BOUNDS_CHECK
+
+
+
+#include "tnt_version.h"
+#include "tnt_math_utils.h"
+#include "tnt_array1d.h"
+#include "tnt_array2d.h"
+#include "tnt_array3d.h"
+#include "tnt_array1d_utils.h"
+#include "tnt_array2d_utils.h"
+#include "tnt_array3d_utils.h"
+
+#include "tnt_fortran_array1d.h"
+#include "tnt_fortran_array2d.h"
+#include "tnt_fortran_array3d.h"
+#include "tnt_fortran_array1d_utils.h"
+#include "tnt_fortran_array2d_utils.h"
+#include "tnt_fortran_array3d_utils.h"
+
+#include "tnt_sparse_matrix_csr.h"
+
+#include "tnt_stopwatch.h"
+#include "tnt_subscript.h"
+#include "tnt_vec.h"
+#include "tnt_cmat.h"
+
+
+#endif
+// TNT_H
diff --git a/lib/include/tnt/tnt_array1d.h b/lib/include/tnt/tnt_array1d.h
new file mode 100644
index 0000000..858df57
--- /dev/null
+++ b/lib/include/tnt/tnt_array1d.h
@@ -0,0 +1,278 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef TNT_ARRAY1D_H
+#define TNT_ARRAY1D_H
+
+//#include <cstdlib>
+#include <iostream>
+
+#ifdef TNT_BOUNDS_CHECK
+#include <assert.h>
+#endif
+
+
+#include "tnt_i_refvec.h"
+
+namespace TNT
+{
+
+template <class T>
+class Array1D
+{
+
+ private:
+
+ /* ... */
+ i_refvec<T> v_;
+ int n_;
+ T* data_; /* this normally points to v_.begin(), but
+ * could also point to a portion (subvector)
+ * of v_.
+ */
+
+ void copy_(T* p, const T* q, int len) const;
+ void set_(T* begin, T* end, const T& val);
+
+
+ public:
+
+ typedef T value_type;
+
+
+ Array1D();
+ explicit Array1D(int n);
+ Array1D(int n, const T &a);
+ Array1D(int n, T *a);
+ inline Array1D(const Array1D &A);
+ inline operator T*();
+ inline operator const T*();
+ inline Array1D & operator=(const T &a);
+ inline Array1D & operator=(const Array1D &A);
+ inline Array1D & ref(const Array1D &A);
+ Array1D copy() const;
+ Array1D & inject(const Array1D & A);
+ inline T& operator[](int i);
+ inline const T& operator[](int i) const;
+ inline int dim1() const;
+ inline int dim() const;
+ ~Array1D();
+
+
+ /* ... extended interface ... */
+
+ inline int ref_count() const;
+ inline Array1D<T> subarray(int i0, int i1);
+
+};
+
+
+
+
+template <class T>
+Array1D<T>::Array1D() : v_(), n_(0), data_(0) {}
+
+template <class T>
+Array1D<T>::Array1D(const Array1D<T> &A) : v_(A.v_), n_(A.n_),
+ data_(A.data_)
+{
+#ifdef TNT_DEBUG
+ std::cout << "Created Array1D(const Array1D<T> &A) \n";
+#endif
+
+}
+
+
+template <class T>
+Array1D<T>::Array1D(int n) : v_(n), n_(n), data_(v_.begin())
+{
+#ifdef TNT_DEBUG
+ std::cout << "Created Array1D(int n) \n";
+#endif
+}
+
+template <class T>
+Array1D<T>::Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin())
+{
+#ifdef TNT_DEBUG
+ std::cout << "Created Array1D(int n, const T& val) \n";
+#endif
+ set_(data_, data_+ n, val);
+
+}
+
+template <class T>
+Array1D<T>::Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin())
+{
+#ifdef TNT_DEBUG
+ std::cout << "Created Array1D(int n, T* a) \n";
+#endif
+}
+
+template <class T>
+inline Array1D<T>::operator T*()
+{
+ return &(v_[0]);
+}
+
+
+template <class T>
+inline Array1D<T>::operator const T*()
+{
+ return &(v_[0]);
+}
+
+
+
+template <class T>
+inline T& Array1D<T>::operator[](int i)
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i>= 0);
+ assert(i < n_);
+#endif
+ return data_[i];
+}
+
+template <class T>
+inline const T& Array1D<T>::operator[](int i) const
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i>= 0);
+ assert(i < n_);
+#endif
+ return data_[i];
+}
+
+
+
+
+template <class T>
+Array1D<T> & Array1D<T>::operator=(const T &a)
+{
+ set_(data_, data_+n_, a);
+ return *this;
+}
+
+template <class T>
+Array1D<T> Array1D<T>::copy() const
+{
+ Array1D A( n_);
+ copy_(A.data_, data_, n_);
+
+ return A;
+}
+
+
+template <class T>
+Array1D<T> & Array1D<T>::inject(const Array1D &A)
+{
+ if (A.n_ == n_)
+ copy_(data_, A.data_, n_);
+
+ return *this;
+}
+
+
+
+
+
+template <class T>
+Array1D<T> & Array1D<T>::ref(const Array1D<T> &A)
+{
+ if (this != &A)
+ {
+ v_ = A.v_; /* operator= handles the reference counting. */
+ n_ = A.n_;
+ data_ = A.data_;
+
+ }
+ return *this;
+}
+
+template <class T>
+Array1D<T> & Array1D<T>::operator=(const Array1D<T> &A)
+{
+ return ref(A);
+}
+
+template <class T>
+inline int Array1D<T>::dim1() const { return n_; }
+
+template <class T>
+inline int Array1D<T>::dim() const { return n_; }
+
+template <class T>
+Array1D<T>::~Array1D() {}
+
+
+/* ............................ exented interface ......................*/
+
+template <class T>
+inline int Array1D<T>::ref_count() const
+{
+ return v_.ref_count();
+}
+
+template <class T>
+inline Array1D<T> Array1D<T>::subarray(int i0, int i1)
+{
+ if ((i0 > 0) && (i1 < n_) || (i0 <= i1))
+ {
+ Array1D<T> X(*this); /* create a new instance of this array. */
+ X.n_ = i1-i0+1;
+ X.data_ += i0;
+
+ return X;
+ }
+ else
+ {
+ return Array1D<T>();
+ }
+}
+
+
+/* private internal functions */
+
+
+template <class T>
+void Array1D<T>::set_(T* begin, T* end, const T& a)
+{
+ for (T* p=begin; p<end; p++)
+ *p = a;
+
+}
+
+template <class T>
+void Array1D<T>::copy_(T* p, const T* q, int len) const
+{
+ T *end = p + len;
+ while (p<end )
+ *p++ = *q++;
+
+}
+
+
+} /* namespace TNT */
+
+#endif
+/* TNT_ARRAY1D_H */
+
diff --git a/lib/include/tnt/tnt_array1d_utils.h b/lib/include/tnt/tnt_array1d_utils.h
new file mode 100644
index 0000000..683e0e2
--- /dev/null
+++ b/lib/include/tnt/tnt_array1d_utils.h
@@ -0,0 +1,230 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+#ifndef TNT_ARRAY1D_UTILS_H
+#define TNT_ARRAY1D_UTILS_H
+
+#include <cstdlib>
+#include <cassert>
+
+namespace TNT
+{
+
+
+template <class T>
+std::ostream& operator<<(std::ostream &s, const Array1D<T> &A)
+{
+ int N=A.dim1();
+
+#ifdef TNT_DEBUG
+ s << "addr: " << (void *) &A[0] << "\n";
+#endif
+ s << N << "\n";
+ for (int j=0; j<N; j++)
+ {
+ s << A[j] << "\n";
+ }
+ s << "\n";
+
+ return s;
+}
+
+template <class T>
+std::istream& operator>>(std::istream &s, Array1D<T> &A)
+{
+ int N;
+ s >> N;
+
+ Array1D<T> B(N);
+ for (int i=0; i<N; i++)
+ s >> B[i];
+ A = B;
+ return s;
+}
+
+
+
+template <class T>
+Array1D<T> operator+(const Array1D<T> &A, const Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() != n )
+ return Array1D<T>();
+
+ else
+ {
+ Array1D<T> C(n);
+
+ for (int i=0; i<n; i++)
+ {
+ C[i] = A[i] + B[i];
+ }
+ return C;
+ }
+}
+
+
+
+template <class T>
+Array1D<T> operator-(const Array1D<T> &A, const Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() != n )
+ return Array1D<T>();
+
+ else
+ {
+ Array1D<T> C(n);
+
+ for (int i=0; i<n; i++)
+ {
+ C[i] = A[i] - B[i];
+ }
+ return C;
+ }
+}
+
+
+template <class T>
+Array1D<T> operator*(const Array1D<T> &A, const Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() != n )
+ return Array1D<T>();
+
+ else
+ {
+ Array1D<T> C(n);
+
+ for (int i=0; i<n; i++)
+ {
+ C[i] = A[i] * B[i];
+ }
+ return C;
+ }
+}
+
+
+template <class T>
+Array1D<T> operator/(const Array1D<T> &A, const Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() != n )
+ return Array1D<T>();
+
+ else
+ {
+ Array1D<T> C(n);
+
+ for (int i=0; i<n; i++)
+ {
+ C[i] = A[i] / B[i];
+ }
+ return C;
+ }
+}
+
+
+
+
+
+
+
+
+
+template <class T>
+Array1D<T>& operator+=(Array1D<T> &A, const Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() == n)
+ {
+ for (int i=0; i<n; i++)
+ {
+ A[i] += B[i];
+ }
+ }
+ return A;
+}
+
+
+
+
+template <class T>
+Array1D<T>& operator-=(Array1D<T> &A, const Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() == n)
+ {
+ for (int i=0; i<n; i++)
+ {
+ A[i] -= B[i];
+ }
+ }
+ return A;
+}
+
+
+
+template <class T>
+Array1D<T>& operator*=(Array1D<T> &A, const Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() == n)
+ {
+ for (int i=0; i<n; i++)
+ {
+ A[i] *= B[i];
+ }
+ }
+ return A;
+}
+
+
+
+
+template <class T>
+Array1D<T>& operator/=(Array1D<T> &A, const Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() == n)
+ {
+ for (int i=0; i<n; i++)
+ {
+ A[i] /= B[i];
+ }
+ }
+ return A;
+}
+
+
+
+
+
+
+} // namespace TNT
+
+#endif
diff --git a/lib/include/tnt/tnt_array2d.h b/lib/include/tnt/tnt_array2d.h
new file mode 100644
index 0000000..c791575
--- /dev/null
+++ b/lib/include/tnt/tnt_array2d.h
@@ -0,0 +1,315 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef TNT_ARRAY2D_H
+#define TNT_ARRAY2D_H
+
+#include <cstdlib>
+#include <iostream>
+#ifdef TNT_BOUNDS_CHECK
+#include <assert.h>
+#endif
+
+#include "tnt_array1d.h"
+
+namespace TNT
+{
+
+template <class T>
+class Array2D
+{
+
+
+ private:
+
+
+
+ Array1D<T> data_;
+ Array1D<T*> v_;
+ int m_;
+ int n_;
+
+ public:
+
+ typedef T value_type;
+ Array2D();
+ Array2D(int m, int n);
+ Array2D(int m, int n, T *a);
+ Array2D(int m, int n, const T &a);
+ inline Array2D(const Array2D &A);
+ inline operator T**();
+ inline operator const T**();
+ inline Array2D & operator=(const T &a);
+ inline Array2D & operator=(const Array2D &A);
+ inline Array2D & ref(const Array2D &A);
+ Array2D copy() const;
+ Array2D & inject(const Array2D & A);
+ inline T* operator[](int i);
+ inline const T* operator[](int i) const;
+ inline int dim1() const;
+ inline int dim2() const;
+ ~Array2D();
+
+ /* extended interface (not part of the standard) */
+
+
+ inline int ref_count();
+ inline int ref_count_data();
+ inline int ref_count_dim1();
+ Array2D subarray(int i0, int i1, int j0, int j1);
+
+};
+
+
+template <class T>
+Array2D<T>::Array2D() : data_(), v_(), m_(0), n_(0) {}
+
+template <class T>
+Array2D<T>::Array2D(const Array2D<T> &A) : data_(A.data_), v_(A.v_),
+ m_(A.m_), n_(A.n_) {}
+
+
+
+
+template <class T>
+Array2D<T>::Array2D(int m, int n) : data_(m*n), v_(m), m_(m), n_(n)
+{
+ if (m>0 && n>0)
+ {
+ T* p = &(data_[0]);
+ for (int i=0; i<m; i++)
+ {
+ v_[i] = p;
+ p += n;
+ }
+ }
+}
+
+
+
+template <class T>
+Array2D<T>::Array2D(int m, int n, const T &val) : data_(m*n), v_(m),
+ m_(m), n_(n)
+{
+ if (m>0 && n>0)
+ {
+ data_ = val;
+ T* p = &(data_[0]);
+ for (int i=0; i<m; i++)
+ {
+ v_[i] = p;
+ p += n;
+ }
+ }
+}
+
+template <class T>
+Array2D<T>::Array2D(int m, int n, T *a) : data_(m*n, a), v_(m), m_(m), n_(n)
+{
+ if (m>0 && n>0)
+ {
+ T* p = &(data_[0]);
+
+ for (int i=0; i<m; i++)
+ {
+ v_[i] = p;
+ p += n;
+ }
+ }
+}
+
+
+template <class T>
+inline T* Array2D<T>::operator[](int i)
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i >= 0);
+ assert(i < m_);
+#endif
+
+return v_[i];
+
+}
+
+
+template <class T>
+inline const T* Array2D<T>::operator[](int i) const
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i >= 0);
+ assert(i < m_);
+#endif
+
+return v_[i];
+
+}
+
+template <class T>
+Array2D<T> & Array2D<T>::operator=(const T &a)
+{
+ /* non-optimzied, but will work with subarrays in future verions */
+
+ for (int i=0; i<m_; i++)
+ for (int j=0; j<n_; j++)
+ v_[i][j] = a;
+ return *this;
+}
+
+
+
+
+template <class T>
+Array2D<T> Array2D<T>::copy() const
+{
+ Array2D A(m_, n_);
+
+ for (int i=0; i<m_; i++)
+ for (int j=0; j<n_; j++)
+ A[i][j] = v_[i][j];
+
+
+ return A;
+}
+
+
+template <class T>
+Array2D<T> & Array2D<T>::inject(const Array2D &A)
+{
+ if (A.m_ == m_ && A.n_ == n_)
+ {
+ for (int i=0; i<m_; i++)
+ for (int j=0; j<n_; j++)
+ v_[i][j] = A[i][j];
+ }
+ return *this;
+}
+
+
+
+
+template <class T>
+Array2D<T> & Array2D<T>::ref(const Array2D<T> &A)
+{
+ if (this != &A)
+ {
+ v_ = A.v_;
+ data_ = A.data_;
+ m_ = A.m_;
+ n_ = A.n_;
+
+ }
+ return *this;
+}
+
+
+
+template <class T>
+Array2D<T> & Array2D<T>::operator=(const Array2D<T> &A)
+{
+ return ref(A);
+}
+
+template <class T>
+inline int Array2D<T>::dim1() const { return m_; }
+
+template <class T>
+inline int Array2D<T>::dim2() const { return n_; }
+
+
+template <class T>
+Array2D<T>::~Array2D() {}
+
+
+
+
+template <class T>
+inline Array2D<T>::operator T**()
+{
+ return &(v_[0]);
+}
+template <class T>
+inline Array2D<T>::operator const T**()
+{
+ return &(v_[0]);
+}
+
+/* ............... extended interface ............... */
+/**
+ Create a new view to a subarray defined by the boundaries
+ [i0][i0] and [i1][j1]. The size of the subarray is
+ (i1-i0) by (j1-j0). If either of these lengths are zero
+ or negative, the subarray view is null.
+
+*/
+template <class T>
+Array2D<T> Array2D<T>::subarray(int i0, int i1, int j0, int j1)
+{
+ Array2D<T> A;
+ int m = i1-i0+1;
+ int n = j1-j0+1;
+
+ /* if either length is zero or negative, this is an invalide
+ subarray. return a null view.
+ */
+ if (m<1 || n<1)
+ return A;
+
+ A.data_ = data_;
+ A.m_ = m;
+ A.n_ = n;
+ A.v_ = Array1D<T*>(m);
+ T* p = &(data_[0]) + i0 * n_ + j0;
+ for (int i=0; i<m; i++)
+ {
+ A.v_[i] = p + i*n_;
+
+ }
+ return A;
+}
+
+template <class T>
+inline int Array2D<T>::ref_count()
+{
+ return ref_count_data();
+}
+
+
+
+template <class T>
+inline int Array2D<T>::ref_count_data()
+{
+ return data_.ref_count();
+}
+
+template <class T>
+inline int Array2D<T>::ref_count_dim1()
+{
+ return v_.ref_count();
+}
+
+
+
+
+} /* namespace TNT */
+
+#endif
+/* TNT_ARRAY2D_H */
+
diff --git a/lib/include/tnt/tnt_array2d_utils.h b/lib/include/tnt/tnt_array2d_utils.h
new file mode 100644
index 0000000..7041ed3
--- /dev/null
+++ b/lib/include/tnt/tnt_array2d_utils.h
@@ -0,0 +1,287 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+#ifndef TNT_ARRAY2D_UTILS_H
+#define TNT_ARRAY2D_UTILS_H
+
+#include <cstdlib>
+#include <cassert>
+
+namespace TNT
+{
+
+
+template <class T>
+std::ostream& operator<<(std::ostream &s, const Array2D<T> &A)
+{
+ int M=A.dim1();
+ int N=A.dim2();
+
+ s << M << " " << N << "\n";
+
+ for (int i=0; i<M; i++)
+ {
+ for (int j=0; j<N; j++)
+ {
+ s << A[i][j] << " ";
+ }
+ s << "\n";
+ }
+
+
+ return s;
+}
+
+template <class T>
+std::istream& operator>>(std::istream &s, Array2D<T> &A)
+{
+
+ int M, N;
+
+ s >> M >> N;
+
+ Array2D<T> B(M,N);
+
+ for (int i=0; i<M; i++)
+ for (int j=0; j<N; j++)
+ {
+ s >> B[i][j];
+ }
+
+ A = B;
+ return s;
+}
+
+
+template <class T>
+Array2D<T> operator+(const Array2D<T> &A, const Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() != m || B.dim2() != n )
+ return Array2D<T>();
+
+ else
+ {
+ Array2D<T> C(m,n);
+
+ for (int i=0; i<m; i++)
+ {
+ for (int j=0; j<n; j++)
+ C[i][j] = A[i][j] + B[i][j];
+ }
+ return C;
+ }
+}
+
+template <class T>
+Array2D<T> operator-(const Array2D<T> &A, const Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() != m || B.dim2() != n )
+ return Array2D<T>();
+
+ else
+ {
+ Array2D<T> C(m,n);
+
+ for (int i=0; i<m; i++)
+ {
+ for (int j=0; j<n; j++)
+ C[i][j] = A[i][j] - B[i][j];
+ }
+ return C;
+ }
+}
+
+
+template <class T>
+Array2D<T> operator*(const Array2D<T> &A, const Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() != m || B.dim2() != n )
+ return Array2D<T>();
+
+ else
+ {
+ Array2D<T> C(m,n);
+
+ for (int i=0; i<m; i++)
+ {
+ for (int j=0; j<n; j++)
+ C[i][j] = A[i][j] * B[i][j];
+ }
+ return C;
+ }
+}
+
+
+
+
+template <class T>
+Array2D<T> operator/(const Array2D<T> &A, const Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() != m || B.dim2() != n )
+ return Array2D<T>();
+
+ else
+ {
+ Array2D<T> C(m,n);
+
+ for (int i=0; i<m; i++)
+ {
+ for (int j=0; j<n; j++)
+ C[i][j] = A[i][j] / B[i][j];
+ }
+ return C;
+ }
+}
+
+
+
+
+
+template <class T>
+Array2D<T>& operator+=(Array2D<T> &A, const Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() == m || B.dim2() == n )
+ {
+ for (int i=0; i<m; i++)
+ {
+ for (int j=0; j<n; j++)
+ A[i][j] += B[i][j];
+ }
+ }
+ return A;
+}
+
+
+
+template <class T>
+Array2D<T>& operator-=(Array2D<T> &A, const Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() == m || B.dim2() == n )
+ {
+ for (int i=0; i<m; i++)
+ {
+ for (int j=0; j<n; j++)
+ A[i][j] -= B[i][j];
+ }
+ }
+ return A;
+}
+
+
+
+template <class T>
+Array2D<T>& operator*=(Array2D<T> &A, const Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() == m || B.dim2() == n )
+ {
+ for (int i=0; i<m; i++)
+ {
+ for (int j=0; j<n; j++)
+ A[i][j] *= B[i][j];
+ }
+ }
+ return A;
+}
+
+
+
+
+
+template <class T>
+Array2D<T>& operator/=(Array2D<T> &A, const Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() == m || B.dim2() == n )
+ {
+ for (int i=0; i<m; i++)
+ {
+ for (int j=0; j<n; j++)
+ A[i][j] /= B[i][j];
+ }
+ }
+ return A;
+}
+
+/**
+ Matrix Multiply: compute C = A*B, where C[i][j]
+ is the dot-product of row i of A and column j of B.
+
+
+ @param A an (m x n) array
+ @param B an (n x k) array
+ @return the (m x k) array A*B, or a null array (0x0)
+ if the matrices are non-conformant (i.e. the number
+ of columns of A are different than the number of rows of B.)
+
+
+*/
+template <class T>
+Array2D<T> matmult(const Array2D<T> &A, const Array2D<T> &B)
+{
+ if (A.dim2() != B.dim1())
+ return Array2D<T>();
+
+ int M = A.dim1();
+ int N = A.dim2();
+ int K = B.dim2();
+
+ Array2D<T> C(M,K);
+
+ for (int i=0; i<M; i++)
+ for (int j=0; j<K; j++)
+ {
+ T sum = 0;
+
+ for (int k=0; k<N; k++)
+ sum += A[i][k] * B [k][j];
+
+ C[i][j] = sum;
+ }
+
+ return C;
+
+}
+
+} // namespace TNT
+
+#endif
diff --git a/lib/include/tnt/tnt_array3d.h b/lib/include/tnt/tnt_array3d.h
new file mode 100644
index 0000000..c210d2e
--- /dev/null
+++ b/lib/include/tnt/tnt_array3d.h
@@ -0,0 +1,296 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef TNT_ARRAY3D_H
+#define TNT_ARRAY3D_H
+
+#include <cstdlib>
+#include <iostream>
+#ifdef TNT_BOUNDS_CHECK
+#include <assert.h>
+#endif
+
+#include "tnt_array1d.h"
+#include "tnt_array2d.h"
+
+namespace TNT
+{
+
+template <class T>
+class Array3D
+{
+
+
+ private:
+ Array1D<T> data_;
+ Array2D<T*> v_;
+ int m_;
+ int n_;
+ int g_;
+
+
+ public:
+
+ typedef T value_type;
+
+ Array3D();
+ Array3D(int m, int n, int g);
+ Array3D(int m, int n, int g, T val);
+ Array3D(int m, int n, int g, T *a);
+
+ inline operator T***();
+ inline operator const T***();
+ inline Array3D(const Array3D &A);
+ inline Array3D & operator=(const T &a);
+ inline Array3D & operator=(const Array3D &A);
+ inline Array3D & ref(const Array3D &A);
+ Array3D copy() const;
+ Array3D & inject(const Array3D & A);
+
+ inline T** operator[](int i);
+ inline const T* const * operator[](int i) const;
+ inline int dim1() const;
+ inline int dim2() const;
+ inline int dim3() const;
+ ~Array3D();
+
+ /* extended interface */
+
+ inline int ref_count(){ return data_.ref_count(); }
+ Array3D subarray(int i0, int i1, int j0, int j1,
+ int k0, int k1);
+};
+
+template <class T>
+Array3D<T>::Array3D() : data_(), v_(), m_(0), n_(0) {}
+
+template <class T>
+Array3D<T>::Array3D(const Array3D<T> &A) : data_(A.data_),
+ v_(A.v_), m_(A.m_), n_(A.n_), g_(A.g_)
+{
+}
+
+
+
+template <class T>
+Array3D<T>::Array3D(int m, int n, int g) : data_(m*n*g), v_(m,n),
+ m_(m), n_(n), g_(g)
+{
+
+ if (m>0 && n>0 && g>0)
+ {
+ T* p = & (data_[0]);
+ int ng = n_*g_;
+
+ for (int i=0; i<m_; i++)
+ {
+ T* ping = p+ i*ng;
+ for (int j=0; j<n; j++)
+ v_[i][j] = ping + j*g_;
+ }
+ }
+}
+
+
+
+template <class T>
+Array3D<T>::Array3D(int m, int n, int g, T val) : data_(m*n*g, val),
+ v_(m,n), m_(m), n_(n), g_(g)
+{
+ if (m>0 && n>0 && g>0)
+ {
+
+ T* p = & (data_[0]);
+ int ng = n_*g_;
+
+ for (int i=0; i<m_; i++)
+ {
+ T* ping = p+ i*ng;
+ for (int j=0; j<n; j++)
+ v_[i][j] = ping + j*g_;
+ }
+ }
+}
+
+
+
+template <class T>
+Array3D<T>::Array3D(int m, int n, int g, T* a) :
+ data_(m*n*g, a), v_(m,n), m_(m), n_(n), g_(g)
+{
+
+ if (m>0 && n>0 && g>0)
+ {
+ T* p = & (data_[0]);
+ int ng = n_*g_;
+
+ for (int i=0; i<m_; i++)
+ {
+ T* ping = p+ i*ng;
+ for (int j=0; j<n; j++)
+ v_[i][j] = ping + j*g_;
+ }
+ }
+}
+
+
+
+template <class T>
+inline T** Array3D<T>::operator[](int i)
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i >= 0);
+ assert(i < m_);
+#endif
+
+return v_[i];
+
+}
+
+template <class T>
+inline const T* const * Array3D<T>::operator[](int i) const
+{ return v_[i]; }
+
+template <class T>
+Array3D<T> & Array3D<T>::operator=(const T &a)
+{
+ for (int i=0; i<m_; i++)
+ for (int j=0; j<n_; j++)
+ for (int k=0; k<g_; k++)
+ v_[i][j][k] = a;
+
+ return *this;
+}
+
+template <class T>
+Array3D<T> Array3D<T>::copy() const
+{
+ Array3D A(m_, n_, g_);
+ for (int i=0; i<m_; i++)
+ for (int j=0; j<n_; j++)
+ for (int k=0; k<g_; k++)
+ A.v_[i][j][k] = v_[i][j][k];
+
+ return A;
+}
+
+
+template <class T>
+Array3D<T> & Array3D<T>::inject(const Array3D &A)
+{
+ if (A.m_ == m_ && A.n_ == n_ && A.g_ == g_)
+
+ for (int i=0; i<m_; i++)
+ for (int j=0; j<n_; j++)
+ for (int k=0; k<g_; k++)
+ v_[i][j][k] = A.v_[i][j][k];
+
+ return *this;
+}
+
+
+
+template <class T>
+Array3D<T> & Array3D<T>::ref(const Array3D<T> &A)
+{
+ if (this != &A)
+ {
+ m_ = A.m_;
+ n_ = A.n_;
+ g_ = A.g_;
+ v_ = A.v_;
+ data_ = A.data_;
+ }
+ return *this;
+}
+
+template <class T>
+Array3D<T> & Array3D<T>::operator=(const Array3D<T> &A)
+{
+ return ref(A);
+}
+
+
+template <class T>
+inline int Array3D<T>::dim1() const { return m_; }
+
+template <class T>
+inline int Array3D<T>::dim2() const { return n_; }
+
+template <class T>
+inline int Array3D<T>::dim3() const { return g_; }
+
+
+
+template <class T>
+Array3D<T>::~Array3D() {}
+
+template <class T>
+inline Array3D<T>::operator T***()
+{
+ return v_;
+}
+
+
+template <class T>
+inline Array3D<T>::operator const T***()
+{
+ return v_;
+}
+
+/* extended interface */
+template <class T>
+Array3D<T> Array3D<T>::subarray(int i0, int i1, int j0,
+ int j1, int k0, int k1)
+{
+
+ /* check that ranges are valid. */
+ if (!( 0 <= i0 && i0 <= i1 && i1 < m_ &&
+ 0 <= j0 && j0 <= j1 && j1 < n_ &&
+ 0 <= k0 && k0 <= k1 && k1 < g_))
+ return Array3D<T>(); /* null array */
+
+
+ Array3D<T> A;
+ A.data_ = data_;
+ A.m_ = i1-i0+1;
+ A.n_ = j1-j0+1;
+ A.g_ = k1-k0+1;
+ A.v_ = Array2D<T*>(A.m_,A.n_);
+ T* p = &(data_[0]) + i0*n_*g_ + j0*g_ + k0;
+
+ for (int i=0; i<A.m_; i++)
+ {
+ T* ping = p + i*n_*g_;
+ for (int j=0; j<A.n_; j++)
+ A.v_[i][j] = ping + j*g_ ;
+ }
+
+ return A;
+}
+
+
+
+} /* namespace TNT */
+
+#endif
+/* TNT_ARRAY3D_H */
+
diff --git a/lib/include/tnt/tnt_array3d_utils.h b/lib/include/tnt/tnt_array3d_utils.h
new file mode 100644
index 0000000..5acdc1d
--- /dev/null
+++ b/lib/include/tnt/tnt_array3d_utils.h
@@ -0,0 +1,236 @@
+
+
+#ifndef TNT_ARRAY3D_UTILS_H
+#define TNT_ARRAY3D_UTILS_H
+
+#include <cstdlib>
+#include <cassert>
+
+namespace TNT
+{
+
+
+template <class T>
+std::ostream& operator<<(std::ostream &s, const Array3D<T> &A)
+{
+ int M=A.dim1();
+ int N=A.dim2();
+ int K=A.dim3();
+
+ s << M << " " << N << " " << K << "\n";
+
+ for (int i=0; i<M; i++)
+ {
+ for (int j=0; j<N; j++)
+ {
+ for (int k=0; k<K; k++)
+ s << A[i][j][k] << " ";
+ s << "\n";
+ }
+ s << "\n";
+ }
+
+
+ return s;
+}
+
+template <class T>
+std::istream& operator>>(std::istream &s, Array3D<T> &A)
+{
+
+ int M, N, K;
+
+ s >> M >> N >> K;
+
+ Array3D<T> B(M,N,K);
+
+ for (int i=0; i<M; i++)
+ for (int j=0; j<N; j++)
+ for (int k=0; k<K; k++)
+ s >> B[i][j][k];
+
+ A = B;
+ return s;
+}
+
+
+
+template <class T>
+Array3D<T> operator+(const Array3D<T> &A, const Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
+ return Array3D<T>();
+
+ else
+ {
+ Array3D<T> C(m,n,p);
+
+ for (int i=0; i<m; i++)
+ for (int j=0; j<n; j++)
+ for (int k=0; k<p; k++)
+ C[i][j][k] = A[i][j][k] + B[i][j][k];
+
+ return C;
+ }
+}
+
+
+template <class T>
+Array3D<T> operator-(const Array3D<T> &A, const Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
+ return Array3D<T>();
+
+ else
+ {
+ Array3D<T> C(m,n,p);
+
+ for (int i=0; i<m; i++)
+ for (int j=0; j<n; j++)
+ for (int k=0; k<p; k++)
+ C[i][j][k] = A[i][j][k] - B[i][j][k];
+
+ return C;
+ }
+}
+
+
+
+
+template <class T>
+Array3D<T> operator*(const Array3D<T> &A, const Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
+ return Array3D<T>();
+
+ else
+ {
+ Array3D<T> C(m,n,p);
+
+ for (int i=0; i<m; i++)
+ for (int j=0; j<n; j++)
+ for (int k=0; k<p; k++)
+ C[i][j][k] = A[i][j][k] * B[i][j][k];
+
+ return C;
+ }
+}
+
+
+template <class T>
+Array3D<T> operator/(const Array3D<T> &A, const Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
+ return Array3D<T>();
+
+ else
+ {
+ Array3D<T> C(m,n,p);
+
+ for (int i=0; i<m; i++)
+ for (int j=0; j<n; j++)
+ for (int k=0; k<p; k++)
+ C[i][j][k] = A[i][j][k] / B[i][j][k];
+
+ return C;
+ }
+}
+
+
+
+template <class T>
+Array3D<T>& operator+=(Array3D<T> &A, const Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
+ {
+ for (int i=0; i<m; i++)
+ for (int j=0; j<n; j++)
+ for (int k=0; k<p; k++)
+ A[i][j][k] += B[i][j][k];
+ }
+
+ return A;
+}
+
+template <class T>
+Array3D<T>& operator-=(Array3D<T> &A, const Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
+ {
+ for (int i=0; i<m; i++)
+ for (int j=0; j<n; j++)
+ for (int k=0; k<p; k++)
+ A[i][j][k] -= B[i][j][k];
+ }
+
+ return A;
+}
+
+template <class T>
+Array3D<T>& operator*=(Array3D<T> &A, const Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
+ {
+ for (int i=0; i<m; i++)
+ for (int j=0; j<n; j++)
+ for (int k=0; k<p; k++)
+ A[i][j][k] *= B[i][j][k];
+ }
+
+ return A;
+}
+
+
+template <class T>
+Array3D<T>& operator/=(Array3D<T> &A, const Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
+ {
+ for (int i=0; i<m; i++)
+ for (int j=0; j<n; j++)
+ for (int k=0; k<p; k++)
+ A[i][j][k] /= B[i][j][k];
+ }
+
+ return A;
+}
+
+
+
+
+
+} // namespace TNT
+
+#endif
diff --git a/lib/include/tnt/tnt_cmat.h b/lib/include/tnt/tnt_cmat.h
new file mode 100644
index 0000000..5ff4c48
--- /dev/null
+++ b/lib/include/tnt/tnt_cmat.h
@@ -0,0 +1,580 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+// C compatible matrix: row-oriented, 0-based [i][j] and 1-based (i,j) indexing
+//
+
+#ifndef TNT_CMAT_H
+#define TNT_CMAT_H
+
+#include "tnt_subscript.h"
+#include "tnt_vec.h"
+#include <cstdlib>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+
+namespace TNT
+{
+
+
+template <class T>
+class Matrix
+{
+
+
+ public:
+
+ typedef Subscript size_type;
+ typedef T value_type;
+ typedef T element_type;
+ typedef T* pointer;
+ typedef T* iterator;
+ typedef T& reference;
+ typedef const T* const_iterator;
+ typedef const T& const_reference;
+
+ Subscript lbound() const { return 1;}
+
+ protected:
+ Subscript m_;
+ Subscript n_;
+ Subscript mn_; // total size
+ T* v_;
+ T** row_;
+ T* vm1_ ; // these point to the same data, but are 1-based
+ T** rowm1_;
+
+ // internal helper function to create the array
+ // of row pointers
+
+ void initialize(Subscript M, Subscript N)
+ {
+ mn_ = M*N;
+ m_ = M;
+ n_ = N;
+
+ v_ = new T[mn_];
+ row_ = new T*[M];
+ rowm1_ = new T*[M];
+
+ assert(v_ != NULL);
+ assert(row_ != NULL);
+ assert(rowm1_ != NULL);
+
+ T* p = v_;
+ vm1_ = v_ - 1;
+ for (Subscript i=0; i<M; i++)
+ {
+ row_[i] = p;
+ rowm1_[i] = p-1;
+ p += N ;
+
+ }
+
+ rowm1_ -- ; // compensate for 1-based offset
+ }
+
+ void copy(const T* v)
+ {
+ Subscript N = m_ * n_;
+ Subscript i;
+
+#ifdef TNT_UNROLL_LOOPS
+ Subscript Nmod4 = N & 3;
+ Subscript N4 = N - Nmod4;
+
+ for (i=0; i<N4; i+=4)
+ {
+ v_[i] = v[i];
+ v_[i+1] = v[i+1];
+ v_[i+2] = v[i+2];
+ v_[i+3] = v[i+3];
+ }
+
+ for (i=N4; i< N; i++)
+ v_[i] = v[i];
+#else
+
+ for (i=0; i< N; i++)
+ v_[i] = v[i];
+#endif
+ }
+
+ void set(const T& val)
+ {
+ Subscript N = m_ * n_;
+ Subscript i;
+
+#ifdef TNT_UNROLL_LOOPS
+ Subscript Nmod4 = N & 3;
+ Subscript N4 = N - Nmod4;
+
+ for (i=0; i<N4; i+=4)
+ {
+ v_[i] = val;
+ v_[i+1] = val;
+ v_[i+2] = val;
+ v_[i+3] = val;
+ }
+
+ for (i=N4; i< N; i++)
+ v_[i] = val;
+#else
+
+ for (i=0; i< N; i++)
+ v_[i] = val;
+
+#endif
+ }
+
+
+
+ void destroy()
+ {
+ /* do nothing, if no memory has been previously allocated */
+ if (v_ == NULL) return ;
+
+ /* if we are here, then matrix was previously allocated */
+ if (v_ != NULL) delete [] (v_);
+ if (row_ != NULL) delete [] (row_);
+
+ /* return rowm1_ back to original value */
+ rowm1_ ++;
+ if (rowm1_ != NULL ) delete [] (rowm1_);
+ }
+
+
+ public:
+
+ operator T**(){ return row_; }
+ operator T**() const { return row_; }
+
+
+ Subscript size() const { return mn_; }
+
+ // constructors
+
+ Matrix() : m_(0), n_(0), mn_(0), v_(0), row_(0), vm1_(0), rowm1_(0) {};
+
+ Matrix(const Matrix<T> &A)
+ {
+ initialize(A.m_, A.n_);
+ copy(A.v_);
+ }
+
+ Matrix(Subscript M, Subscript N, const T& value = T())
+ {
+ initialize(M,N);
+ set(value);
+ }
+
+ Matrix(Subscript M, Subscript N, const T* v)
+ {
+ initialize(M,N);
+ copy(v);
+ }
+
+ Matrix(Subscript M, Subscript N, const char *s)
+ {
+ initialize(M,N);
+ //std::istrstream ins(s);
+ std::istringstream ins(s);
+
+ Subscript i, j;
+
+ for (i=0; i<M; i++)
+ for (j=0; j<N; j++)
+ ins >> row_[i][j];
+ }
+
+ // destructor
+ //
+ ~Matrix()
+ {
+ destroy();
+ }
+
+
+ // reallocating
+ //
+ Matrix<T>& newsize(Subscript M, Subscript N)
+ {
+ if (num_rows() == M && num_cols() == N)
+ return *this;
+
+ destroy();
+ initialize(M,N);
+
+ return *this;
+ }
+
+
+
+
+ // assignments
+ //
+ Matrix<T>& operator=(const Matrix<T> &A)
+ {
+ if (v_ == A.v_)
+ return *this;
+
+ if (m_ == A.m_ && n_ == A.n_) // no need to re-alloc
+ copy(A.v_);
+
+ else
+ {
+ destroy();
+ initialize(A.m_, A.n_);
+ copy(A.v_);
+ }
+
+ return *this;
+ }
+
+ Matrix<T>& operator=(const T& scalar)
+ {
+ set(scalar);
+ return *this;
+ }
+
+
+ Subscript dim(Subscript d) const
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert( d >= 1);
+ assert( d <= 2);
+#endif
+ return (d==1) ? m_ : ((d==2) ? n_ : 0);
+ }
+
+ Subscript num_rows() const { return m_; }
+ Subscript num_cols() const { return n_; }
+
+
+
+
+ inline T* operator[](Subscript i)
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(0<=i);
+ assert(i < m_) ;
+#endif
+ return row_[i];
+ }
+
+ inline const T* operator[](Subscript i) const
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(0<=i);
+ assert(i < m_) ;
+#endif
+ return row_[i];
+ }
+
+ inline reference operator()(Subscript i)
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(1<=i);
+ assert(i <= mn_) ;
+#endif
+ return vm1_[i];
+ }
+
+ inline const_reference operator()(Subscript i) const
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(1<=i);
+ assert(i <= mn_) ;
+#endif
+ return vm1_[i];
+ }
+
+
+
+ inline reference operator()(Subscript i, Subscript j)
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(1<=i);
+ assert(i <= m_) ;
+ assert(1<=j);
+ assert(j <= n_);
+#endif
+ return rowm1_[i][j];
+ }
+
+
+
+ inline const_reference operator() (Subscript i, Subscript j) const
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(1<=i);
+ assert(i <= m_) ;
+ assert(1<=j);
+ assert(j <= n_);
+#endif
+ return rowm1_[i][j];
+ }
+
+
+
+
+};
+
+
+/* *************************** I/O ********************************/
+
+template <class T>
+std::ostream& operator<<(std::ostream &s, const Matrix<T> &A)
+{
+ Subscript M=A.num_rows();
+ Subscript N=A.num_cols();
+
+ s << M << " " << N << "\n";
+
+ for (Subscript i=0; i<M; i++)
+ {
+ for (Subscript j=0; j<N; j++)
+ {
+ s << A[i][j] << " ";
+ }
+ s << "\n";
+ }
+
+
+ return s;
+}
+
+template <class T>
+std::istream& operator>>(std::istream &s, Matrix<T> &A)
+{
+
+ Subscript M, N;
+
+ s >> M >> N;
+
+ if ( !(M == A.num_rows() && N == A.num_cols() ))
+ {
+ A.newsize(M,N);
+ }
+
+
+ for (Subscript i=0; i<M; i++)
+ for (Subscript j=0; j<N; j++)
+ {
+ s >> A[i][j];
+ }
+
+
+ return s;
+}
+
+// *******************[ basic matrix algorithms ]***************************
+
+
+template <class T>
+Matrix<T> operator+(const Matrix<T> &A,
+ const Matrix<T> &B)
+{
+ Subscript M = A.num_rows();
+ Subscript N = A.num_cols();
+
+ assert(M==B.num_rows());
+ assert(N==B.num_cols());
+
+ Matrix<T> tmp(M,N);
+ Subscript i,j;
+
+ for (i=0; i<M; i++)
+ for (j=0; j<N; j++)
+ tmp[i][j] = A[i][j] + B[i][j];
+
+ return tmp;
+}
+
+template <class T>
+Matrix<T> operator-(const Matrix<T> &A,
+ const Matrix<T> &B)
+{
+ Subscript M = A.num_rows();
+ Subscript N = A.num_cols();
+
+ assert(M==B.num_rows());
+ assert(N==B.num_cols());
+
+ Matrix<T> tmp(M,N);
+ Subscript i,j;
+
+ for (i=0; i<M; i++)
+ for (j=0; j<N; j++)
+ tmp[i][j] = A[i][j] - B[i][j];
+
+ return tmp;
+}
+
+template <class T>
+Matrix<T> mult_element(const Matrix<T> &A,
+ const Matrix<T> &B)
+{
+ Subscript M = A.num_rows();
+ Subscript N = A.num_cols();
+
+ assert(M==B.num_rows());
+ assert(N==B.num_cols());
+
+ Matrix<T> tmp(M,N);
+ Subscript i,j;
+
+ for (i=0; i<M; i++)
+ for (j=0; j<N; j++)
+ tmp[i][j] = A[i][j] * B[i][j];
+
+ return tmp;
+}
+
+
+template <class T>
+Matrix<T> transpose(const Matrix<T> &A)
+{
+ Subscript M = A.num_rows();
+ Subscript N = A.num_cols();
+
+ Matrix<T> S(N,M);
+ Subscript i, j;
+
+ for (i=0; i<M; i++)
+ for (j=0; j<N; j++)
+ S[j][i] = A[i][j];
+
+ return S;
+}
+
+
+
+template <class T>
+inline Matrix<T> matmult(const Matrix<T> &A,
+ const Matrix<T> &B)
+{
+
+#ifdef TNT_BOUNDS_CHECK
+ assert(A.num_cols() == B.num_rows());
+#endif
+
+ Subscript M = A.num_rows();
+ Subscript N = A.num_cols();
+ Subscript K = B.num_cols();
+
+ Matrix<T> tmp(M,K);
+ T sum;
+
+ for (Subscript i=0; i<M; i++)
+ for (Subscript k=0; k<K; k++)
+ {
+ sum = 0;
+ for (Subscript j=0; j<N; j++)
+ sum = sum + A[i][j] * B[j][k];
+
+ tmp[i][k] = sum;
+ }
+
+ return tmp;
+}
+
+template <class T>
+inline Matrix<T> operator*(const Matrix<T> &A,
+ const Matrix<T> &B)
+{
+ return matmult(A,B);
+}
+
+template <class T>
+inline int matmult(Matrix<T>& C, const Matrix<T> &A,
+ const Matrix<T> &B)
+{
+
+ assert(A.num_cols() == B.num_rows());
+
+ Subscript M = A.num_rows();
+ Subscript N = A.num_cols();
+ Subscript K = B.num_cols();
+
+ C.newsize(M,K);
+
+ T sum;
+
+ const T* row_i;
+ const T* col_k;
+
+ for (Subscript i=0; i<M; i++)
+ for (Subscript k=0; k<K; k++)
+ {
+ row_i = &(A[i][0]);
+ col_k = &(B[0][k]);
+ sum = 0;
+ for (Subscript j=0; j<N; j++)
+ {
+ sum += *row_i * *col_k;
+ row_i++;
+ col_k += K;
+ }
+ C[i][k] = sum;
+ }
+
+ return 0;
+}
+
+
+template <class T>
+Vector<T> matmult(const Matrix<T> &A, const Vector<T> &x)
+{
+
+#ifdef TNT_BOUNDS_CHECK
+ assert(A.num_cols() == x.dim());
+#endif
+
+ Subscript M = A.num_rows();
+ Subscript N = A.num_cols();
+
+ Vector<T> tmp(M);
+ T sum;
+
+ for (Subscript i=0; i<M; i++)
+ {
+ sum = 0;
+ const T* rowi = A[i];
+ for (Subscript j=0; j<N; j++)
+ sum = sum + rowi[j] * x[j];
+
+ tmp[i] = sum;
+ }
+
+ return tmp;
+}
+
+template <class T>
+inline Vector<T> operator*(const Matrix<T> &A, const Vector<T> &x)
+{
+ return matmult(A,x);
+}
+
+} // namespace TNT
+
+#endif
+// CMAT_H
diff --git a/lib/include/tnt/tnt_fortran_array1d.h b/lib/include/tnt/tnt_fortran_array1d.h
new file mode 100644
index 0000000..ad3bba0
--- /dev/null
+++ b/lib/include/tnt/tnt_fortran_array1d.h
@@ -0,0 +1,267 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef TNT_FORTRAN_ARRAY1D_H
+#define TNT_FORTRAN_ARRAY1D_H
+
+#include <cstdlib>
+#include <iostream>
+
+#ifdef TNT_BOUNDS_CHECK
+#include <assert.h>
+#endif
+
+
+#include "tnt_i_refvec.h"
+
+namespace TNT
+{
+
+template <class T>
+class Fortran_Array1D
+{
+
+ private:
+
+ i_refvec<T> v_;
+ int n_;
+ T* data_; /* this normally points to v_.begin(), but
+ * could also point to a portion (subvector)
+ * of v_.
+ */
+
+ void initialize_(int n);
+ void copy_(T* p, const T* q, int len) const;
+ void set_(T* begin, T* end, const T& val);
+
+
+ public:
+
+ typedef T value_type;
+
+
+ Fortran_Array1D();
+ explicit Fortran_Array1D(int n);
+ Fortran_Array1D(int n, const T &a);
+ Fortran_Array1D(int n, T *a);
+ inline Fortran_Array1D(const Fortran_Array1D &A);
+ inline Fortran_Array1D & operator=(const T &a);
+ inline Fortran_Array1D & operator=(const Fortran_Array1D &A);
+ inline Fortran_Array1D & ref(const Fortran_Array1D &A);
+ Fortran_Array1D copy() const;
+ Fortran_Array1D & inject(const Fortran_Array1D & A);
+ inline T& operator()(int i);
+ inline const T& operator()(int i) const;
+ inline int dim1() const;
+ inline int dim() const;
+ ~Fortran_Array1D();
+
+
+ /* ... extended interface ... */
+
+ inline int ref_count() const;
+ inline Fortran_Array1D<T> subarray(int i0, int i1);
+
+};
+
+
+
+
+template <class T>
+Fortran_Array1D<T>::Fortran_Array1D() : v_(), n_(0), data_(0) {}
+
+template <class T>
+Fortran_Array1D<T>::Fortran_Array1D(const Fortran_Array1D<T> &A) : v_(A.v_), n_(A.n_),
+ data_(A.data_)
+{
+#ifdef TNT_DEBUG
+ std::cout << "Created Fortran_Array1D(const Fortran_Array1D<T> &A) \n";
+#endif
+
+}
+
+
+template <class T>
+Fortran_Array1D<T>::Fortran_Array1D(int n) : v_(n), n_(n), data_(v_.begin())
+{
+#ifdef TNT_DEBUG
+ std::cout << "Created Fortran_Array1D(int n) \n";
+#endif
+}
+
+template <class T>
+Fortran_Array1D<T>::Fortran_Array1D(int n, const T &val) : v_(n), n_(n), data_(v_.begin())
+{
+#ifdef TNT_DEBUG
+ std::cout << "Created Fortran_Array1D(int n, const T& val) \n";
+#endif
+ set_(data_, data_+ n, val);
+
+}
+
+template <class T>
+Fortran_Array1D<T>::Fortran_Array1D(int n, T *a) : v_(a), n_(n) , data_(v_.begin())
+{
+#ifdef TNT_DEBUG
+ std::cout << "Created Fortran_Array1D(int n, T* a) \n";
+#endif
+}
+
+template <class T>
+inline T& Fortran_Array1D<T>::operator()(int i)
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i>= 1);
+ assert(i <= n_);
+#endif
+ return data_[i-1];
+}
+
+template <class T>
+inline const T& Fortran_Array1D<T>::operator()(int i) const
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i>= 1);
+ assert(i <= n_);
+#endif
+ return data_[i-1];
+}
+
+
+
+
+template <class T>
+Fortran_Array1D<T> & Fortran_Array1D<T>::operator=(const T &a)
+{
+ set_(data_, data_+n_, a);
+ return *this;
+}
+
+template <class T>
+Fortran_Array1D<T> Fortran_Array1D<T>::copy() const
+{
+ Fortran_Array1D A( n_);
+ copy_(A.data_, data_, n_);
+
+ return A;
+}
+
+
+template <class T>
+Fortran_Array1D<T> & Fortran_Array1D<T>::inject(const Fortran_Array1D &A)
+{
+ if (A.n_ == n_)
+ copy_(data_, A.data_, n_);
+
+ return *this;
+}
+
+
+
+
+
+template <class T>
+Fortran_Array1D<T> & Fortran_Array1D<T>::ref(const Fortran_Array1D<T> &A)
+{
+ if (this != &A)
+ {
+ v_ = A.v_; /* operator= handles the reference counting. */
+ n_ = A.n_;
+ data_ = A.data_;
+
+ }
+ return *this;
+}
+
+template <class T>
+Fortran_Array1D<T> & Fortran_Array1D<T>::operator=(const Fortran_Array1D<T> &A)
+{
+ return ref(A);
+}
+
+template <class T>
+inline int Fortran_Array1D<T>::dim1() const { return n_; }
+
+template <class T>
+inline int Fortran_Array1D<T>::dim() const { return n_; }
+
+template <class T>
+Fortran_Array1D<T>::~Fortran_Array1D() {}
+
+
+/* ............................ exented interface ......................*/
+
+template <class T>
+inline int Fortran_Array1D<T>::ref_count() const
+{
+ return v_.ref_count();
+}
+
+template <class T>
+inline Fortran_Array1D<T> Fortran_Array1D<T>::subarray(int i0, int i1)
+{
+#ifdef TNT_DEBUG
+ std::cout << "entered subarray. \n";
+#endif
+ if ((i0 > 0) && (i1 < n_) || (i0 <= i1))
+ {
+ Fortran_Array1D<T> X(*this); /* create a new instance of this array. */
+ X.n_ = i1-i0+1;
+ X.data_ += i0;
+
+ return X;
+ }
+ else
+ {
+#ifdef TNT_DEBUG
+ std::cout << "subarray: null return.\n";
+#endif
+ return Fortran_Array1D<T>();
+ }
+}
+
+
+/* private internal functions */
+
+
+template <class T>
+void Fortran_Array1D<T>::set_(T* begin, T* end, const T& a)
+{
+ for (T* p=begin; p<end; p++)
+ *p = a;
+
+}
+
+template <class T>
+void Fortran_Array1D<T>::copy_(T* p, const T* q, int len) const
+{
+ T *end = p + len;
+ while (p<end )
+ *p++ = *q++;
+
+}
+
+
+} /* namespace TNT */
+
+#endif
+/* TNT_FORTRAN_ARRAY1D_H */
+
diff --git a/lib/include/tnt/tnt_fortran_array1d_utils.h b/lib/include/tnt/tnt_fortran_array1d_utils.h
new file mode 100644
index 0000000..b037b17
--- /dev/null
+++ b/lib/include/tnt/tnt_fortran_array1d_utils.h
@@ -0,0 +1,242 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+#ifndef TNT_FORTRAN_ARRAY1D_UTILS_H
+#define TNT_FORTRAN_ARRAY1D_UTILS_H
+
+#include <iostream>
+
+namespace TNT
+{
+
+
+/**
+ Write an array to a character outstream. Output format is one that can
+ be read back in via the in-stream operator: one integer
+ denoting the array dimension (n), followed by n elements,
+ one per line.
+
+*/
+template <class T>
+std::ostream& operator<<(std::ostream &s, const Fortran_Array1D<T> &A)
+{
+ int N=A.dim1();
+
+ s << N << "\n";
+ for (int j=1; j<=N; j++)
+ {
+ s << A(j) << "\n";
+ }
+ s << "\n";
+
+ return s;
+}
+
+/**
+ Read an array from a character stream. Input format
+ is one integer, denoting the dimension (n), followed
+ by n whitespace-separated elments. Newlines are ignored
+
+ <p>
+ Note: the array being read into references new memory
+ storage. If the intent is to fill an existing conformant
+ array, use <code> cin >> B; A.inject(B) ); </code>
+ instead or read the elements in one-a-time by hand.
+
+ @param s the charater to read from (typically <code>std::in</code>)
+ @param A the array to read into.
+*/
+template <class T>
+std::istream& operator>>(std::istream &s, Fortran_Array1D<T> &A)
+{
+ int N;
+ s >> N;
+
+ Fortran_Array1D<T> B(N);
+ for (int i=1; i<=N; i++)
+ s >> B(i);
+ A = B;
+ return s;
+}
+
+
+template <class T>
+Fortran_Array1D<T> operator+(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() != n )
+ return Fortran_Array1D<T>();
+
+ else
+ {
+ Fortran_Array1D<T> C(n);
+
+ for (int i=1; i<=n; i++)
+ {
+ C(i) = A(i) + B(i);
+ }
+ return C;
+ }
+}
+
+
+
+template <class T>
+Fortran_Array1D<T> operator-(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() != n )
+ return Fortran_Array1D<T>();
+
+ else
+ {
+ Fortran_Array1D<T> C(n);
+
+ for (int i=1; i<=n; i++)
+ {
+ C(i) = A(i) - B(i);
+ }
+ return C;
+ }
+}
+
+
+template <class T>
+Fortran_Array1D<T> operator*(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() != n )
+ return Fortran_Array1D<T>();
+
+ else
+ {
+ Fortran_Array1D<T> C(n);
+
+ for (int i=1; i<=n; i++)
+ {
+ C(i) = A(i) * B(i);
+ }
+ return C;
+ }
+}
+
+
+template <class T>
+Fortran_Array1D<T> operator/(const Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() != n )
+ return Fortran_Array1D<T>();
+
+ else
+ {
+ Fortran_Array1D<T> C(n);
+
+ for (int i=1; i<=n; i++)
+ {
+ C(i) = A(i) / B(i);
+ }
+ return C;
+ }
+}
+
+
+
+
+
+
+
+
+
+template <class T>
+Fortran_Array1D<T>& operator+=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() == n)
+ {
+ for (int i=1; i<=n; i++)
+ {
+ A(i) += B(i);
+ }
+ }
+ return A;
+}
+
+
+
+
+template <class T>
+Fortran_Array1D<T>& operator-=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() == n)
+ {
+ for (int i=1; i<=n; i++)
+ {
+ A(i) -= B(i);
+ }
+ }
+ return A;
+}
+
+
+
+template <class T>
+Fortran_Array1D<T>& operator*=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() == n)
+ {
+ for (int i=1; i<=n; i++)
+ {
+ A(i) *= B(i);
+ }
+ }
+ return A;
+}
+
+
+
+
+template <class T>
+Fortran_Array1D<T>& operator/=(Fortran_Array1D<T> &A, const Fortran_Array1D<T> &B)
+{
+ int n = A.dim1();
+
+ if (B.dim1() == n)
+ {
+ for (int i=1; i<=n; i++)
+ {
+ A(i) /= B(i);
+ }
+ }
+ return A;
+}
+
+
+} // namespace TNT
+
+#endif
diff --git a/lib/include/tnt/tnt_fortran_array2d.h b/lib/include/tnt/tnt_fortran_array2d.h
new file mode 100644
index 0000000..f307536
--- /dev/null
+++ b/lib/include/tnt/tnt_fortran_array2d.h
@@ -0,0 +1,225 @@
+/*
+*
+* Template Numerical Toolkit (TNT): Two-dimensional Fortran numerical array
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef TNT_FORTRAN_ARRAY2D_H
+#define TNT_FORTRAN_ARRAY2D_H
+
+#include <cstdlib>
+#include <iostream>
+
+#ifdef TNT_BOUNDS_CHECK
+#include <assert.h>
+#endif
+
+#include "tnt_i_refvec.h"
+
+namespace TNT
+{
+
+template <class T>
+class Fortran_Array2D
+{
+
+
+ private:
+ i_refvec<T> v_;
+ int m_;
+ int n_;
+ T* data_;
+
+
+ void initialize_(int n);
+ void copy_(T* p, const T* q, int len);
+ void set_(T* begin, T* end, const T& val);
+
+ public:
+
+ typedef T value_type;
+
+ Fortran_Array2D();
+ Fortran_Array2D(int m, int n);
+ Fortran_Array2D(int m, int n, T *a);
+ Fortran_Array2D(int m, int n, const T &a);
+ inline Fortran_Array2D(const Fortran_Array2D &A);
+ inline Fortran_Array2D & operator=(const T &a);
+ inline Fortran_Array2D & operator=(const Fortran_Array2D &A);
+ inline Fortran_Array2D & ref(const Fortran_Array2D &A);
+ Fortran_Array2D copy() const;
+ Fortran_Array2D & inject(const Fortran_Array2D & A);
+ inline T& operator()(int i, int j);
+ inline const T& operator()(int i, int j) const ;
+ inline int dim1() const;
+ inline int dim2() const;
+ ~Fortran_Array2D();
+
+ /* extended interface */
+
+ inline int ref_count() const;
+
+};
+
+template <class T>
+Fortran_Array2D<T>::Fortran_Array2D() : v_(), m_(0), n_(0), data_(0) {}
+
+
+template <class T>
+Fortran_Array2D<T>::Fortran_Array2D(const Fortran_Array2D<T> &A) : v_(A.v_),
+ m_(A.m_), n_(A.n_), data_(A.data_) {}
+
+
+
+template <class T>
+Fortran_Array2D<T>::Fortran_Array2D(int m, int n) : v_(m*n), m_(m), n_(n),
+ data_(v_.begin()) {}
+
+template <class T>
+Fortran_Array2D<T>::Fortran_Array2D(int m, int n, const T &val) :
+ v_(m*n), m_(m), n_(n), data_(v_.begin())
+{
+ set_(data_, data_+m*n, val);
+}
+
+
+template <class T>
+Fortran_Array2D<T>::Fortran_Array2D(int m, int n, T *a) : v_(a),
+ m_(m), n_(n), data_(v_.begin()) {}
+
+
+
+
+template <class T>
+inline T& Fortran_Array2D<T>::operator()(int i, int j)
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i >= 1);
+ assert(i <= m_);
+ assert(j >= 1);
+ assert(j <= n_);
+#endif
+
+ return v_[ (j-1)*m_ + (i-1) ];
+
+}
+
+template <class T>
+inline const T& Fortran_Array2D<T>::operator()(int i, int j) const
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i >= 1);
+ assert(i <= m_);
+ assert(j >= 1);
+ assert(j <= n_);
+#endif
+
+ return v_[ (j-1)*m_ + (i-1) ];
+
+}
+
+
+template <class T>
+Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const T &a)
+{
+ set_(data_, data_+m_*n_, a);
+ return *this;
+}
+
+template <class T>
+Fortran_Array2D<T> Fortran_Array2D<T>::copy() const
+{
+
+ Fortran_Array2D B(m_,n_);
+
+ B.inject(*this);
+ return B;
+}
+
+
+template <class T>
+Fortran_Array2D<T> & Fortran_Array2D<T>::inject(const Fortran_Array2D &A)
+{
+ if (m_ == A.m_ && n_ == A.n_)
+ copy_(data_, A.data_, m_*n_);
+
+ return *this;
+}
+
+
+
+template <class T>
+Fortran_Array2D<T> & Fortran_Array2D<T>::ref(const Fortran_Array2D<T> &A)
+{
+ if (this != &A)
+ {
+ v_ = A.v_;
+ m_ = A.m_;
+ n_ = A.n_;
+ data_ = A.data_;
+ }
+ return *this;
+}
+
+template <class T>
+Fortran_Array2D<T> & Fortran_Array2D<T>::operator=(const Fortran_Array2D<T> &A)
+{
+ return ref(A);
+}
+
+template <class T>
+inline int Fortran_Array2D<T>::dim1() const { return m_; }
+
+template <class T>
+inline int Fortran_Array2D<T>::dim2() const { return n_; }
+
+
+template <class T>
+Fortran_Array2D<T>::~Fortran_Array2D()
+{
+}
+
+template <class T>
+inline int Fortran_Array2D<T>::ref_count() const { return v_.ref_count(); }
+
+
+
+
+template <class T>
+void Fortran_Array2D<T>::set_(T* begin, T* end, const T& a)
+{
+ for (T* p=begin; p<end; p++)
+ *p = a;
+
+}
+
+template <class T>
+void Fortran_Array2D<T>::copy_(T* p, const T* q, int len)
+{
+ T *end = p + len;
+ while (p<end )
+ *p++ = *q++;
+
+}
+
+
+} /* namespace TNT */
+
+#endif
+/* TNT_FORTRAN_ARRAY2D_H */
+
diff --git a/lib/include/tnt/tnt_fortran_array2d_utils.h b/lib/include/tnt/tnt_fortran_array2d_utils.h
new file mode 100644
index 0000000..bb68673
--- /dev/null
+++ b/lib/include/tnt/tnt_fortran_array2d_utils.h
@@ -0,0 +1,236 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+#ifndef TNT_FORTRAN_ARRAY2D_UTILS_H
+#define TNT_FORTRAN_ARRAY2D_UTILS_H
+
+#include <iostream>
+
+namespace TNT
+{
+
+
+template <class T>
+std::ostream& operator<<(std::ostream &s, const Fortran_Array2D<T> &A)
+{
+ int M=A.dim1();
+ int N=A.dim2();
+
+ s << M << " " << N << "\n";
+
+ for (int i=1; i<=M; i++)
+ {
+ for (int j=1; j<=N; j++)
+ {
+ s << A(i,j) << " ";
+ }
+ s << "\n";
+ }
+
+
+ return s;
+}
+
+template <class T>
+std::istream& operator>>(std::istream &s, Fortran_Array2D<T> &A)
+{
+
+ int M, N;
+
+ s >> M >> N;
+
+ Fortran_Array2D<T> B(M,N);
+
+ for (int i=1; i<=M; i++)
+ for (int j=1; j<=N; j++)
+ {
+ s >> B(i,j);
+ }
+
+ A = B;
+ return s;
+}
+
+
+
+
+template <class T>
+Fortran_Array2D<T> operator+(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() != m || B.dim2() != n )
+ return Fortran_Array2D<T>();
+
+ else
+ {
+ Fortran_Array2D<T> C(m,n);
+
+ for (int i=1; i<=m; i++)
+ {
+ for (int j=1; j<=n; j++)
+ C(i,j) = A(i,j) + B(i,j);
+ }
+ return C;
+ }
+}
+
+template <class T>
+Fortran_Array2D<T> operator-(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() != m || B.dim2() != n )
+ return Fortran_Array2D<T>();
+
+ else
+ {
+ Fortran_Array2D<T> C(m,n);
+
+ for (int i=1; i<=m; i++)
+ {
+ for (int j=1; j<=n; j++)
+ C(i,j) = A(i,j) - B(i,j);
+ }
+ return C;
+ }
+}
+
+
+template <class T>
+Fortran_Array2D<T> operator*(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() != m || B.dim2() != n )
+ return Fortran_Array2D<T>();
+
+ else
+ {
+ Fortran_Array2D<T> C(m,n);
+
+ for (int i=1; i<=m; i++)
+ {
+ for (int j=1; j<=n; j++)
+ C(i,j) = A(i,j) * B(i,j);
+ }
+ return C;
+ }
+}
+
+
+template <class T>
+Fortran_Array2D<T> operator/(const Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() != m || B.dim2() != n )
+ return Fortran_Array2D<T>();
+
+ else
+ {
+ Fortran_Array2D<T> C(m,n);
+
+ for (int i=1; i<=m; i++)
+ {
+ for (int j=1; j<=n; j++)
+ C(i,j) = A(i,j) / B(i,j);
+ }
+ return C;
+ }
+}
+
+
+
+template <class T>
+Fortran_Array2D<T>& operator+=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() == m || B.dim2() == n )
+ {
+ for (int i=1; i<=m; i++)
+ {
+ for (int j=1; j<=n; j++)
+ A(i,j) += B(i,j);
+ }
+ }
+ return A;
+}
+
+template <class T>
+Fortran_Array2D<T>& operator-=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() == m || B.dim2() == n )
+ {
+ for (int i=1; i<=m; i++)
+ {
+ for (int j=1; j<=n; j++)
+ A(i,j) -= B(i,j);
+ }
+ }
+ return A;
+}
+
+template <class T>
+Fortran_Array2D<T>& operator*=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() == m || B.dim2() == n )
+ {
+ for (int i=1; i<=m; i++)
+ {
+ for (int j=1; j<=n; j++)
+ A(i,j) *= B(i,j);
+ }
+ }
+ return A;
+}
+
+template <class T>
+Fortran_Array2D<T>& operator/=(Fortran_Array2D<T> &A, const Fortran_Array2D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+
+ if (B.dim1() == m || B.dim2() == n )
+ {
+ for (int i=1; i<=m; i++)
+ {
+ for (int j=1; j<=n; j++)
+ A(i,j) /= B(i,j);
+ }
+ }
+ return A;
+}
+
+} // namespace TNT
+
+#endif
diff --git a/lib/include/tnt/tnt_fortran_array3d.h b/lib/include/tnt/tnt_fortran_array3d.h
new file mode 100644
index 0000000..e51affb
--- /dev/null
+++ b/lib/include/tnt/tnt_fortran_array3d.h
@@ -0,0 +1,223 @@
+/*
+*
+* Template Numerical Toolkit (TNT): Three-dimensional Fortran numerical array
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef TNT_FORTRAN_ARRAY3D_H
+#define TNT_FORTRAN_ARRAY3D_H
+
+#include <cstdlib>
+#include <iostream>
+#ifdef TNT_BOUNDS_CHECK
+#include <assert.h>
+#endif
+#include "tnt_i_refvec.h"
+
+namespace TNT
+{
+
+template <class T>
+class Fortran_Array3D
+{
+
+
+ private:
+
+
+ i_refvec<T> v_;
+ int m_;
+ int n_;
+ int k_;
+ T* data_;
+
+ public:
+
+ typedef T value_type;
+
+ Fortran_Array3D();
+ Fortran_Array3D(int m, int n, int k);
+ Fortran_Array3D(int m, int n, int k, T *a);
+ Fortran_Array3D(int m, int n, int k, const T &a);
+ inline Fortran_Array3D(const Fortran_Array3D &A);
+ inline Fortran_Array3D & operator=(const T &a);
+ inline Fortran_Array3D & operator=(const Fortran_Array3D &A);
+ inline Fortran_Array3D & ref(const Fortran_Array3D &A);
+ Fortran_Array3D copy() const;
+ Fortran_Array3D & inject(const Fortran_Array3D & A);
+ inline T& operator()(int i, int j, int k);
+ inline const T& operator()(int i, int j, int k) const ;
+ inline int dim1() const;
+ inline int dim2() const;
+ inline int dim3() const;
+ inline int ref_count() const;
+ ~Fortran_Array3D();
+
+
+};
+
+template <class T>
+Fortran_Array3D<T>::Fortran_Array3D() : v_(), m_(0), n_(0), k_(0), data_(0) {}
+
+
+template <class T>
+Fortran_Array3D<T>::Fortran_Array3D(const Fortran_Array3D<T> &A) :
+ v_(A.v_), m_(A.m_), n_(A.n_), k_(A.k_), data_(A.data_) {}
+
+
+
+template <class T>
+Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k) :
+ v_(m*n*k), m_(m), n_(n), k_(k), data_(v_.begin()) {}
+
+
+
+template <class T>
+Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k, const T &val) :
+ v_(m*n*k), m_(m), n_(n), k_(k), data_(v_.begin())
+{
+ for (T* p = data_; p < data_ + m*n*k; p++)
+ *p = val;
+}
+
+template <class T>
+Fortran_Array3D<T>::Fortran_Array3D(int m, int n, int k, T *a) :
+ v_(a), m_(m), n_(n), k_(k), data_(v_.begin()) {}
+
+
+
+
+template <class T>
+inline T& Fortran_Array3D<T>::operator()(int i, int j, int k)
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i >= 1);
+ assert(i <= m_);
+ assert(j >= 1);
+ assert(j <= n_);
+ assert(k >= 1);
+ assert(k <= k_);
+#endif
+
+ return data_[(k-1)*m_*n_ + (j-1) * m_ + i-1];
+
+}
+
+template <class T>
+inline const T& Fortran_Array3D<T>::operator()(int i, int j, int k) const
+{
+#ifdef TNT_BOUNDS_CHECK
+ assert(i >= 1);
+ assert(i <= m_);
+ assert(j >= 1);
+ assert(j <= n_);
+ assert(k >= 1);
+ assert(k <= k_);
+#endif
+
+ return data_[(k-1)*m_*n_ + (j-1) * m_ + i-1];
+}
+
+
+template <class T>
+Fortran_Array3D<T> & Fortran_Array3D<T>::operator=(const T &a)
+{
+
+ T *end = data_ + m_*n_*k_;
+
+ for (T *p=data_; p != end; *p++ = a);
+
+ return *this;
+}
+
+template <class T>
+Fortran_Array3D<T> Fortran_Array3D<T>::copy() const
+{
+
+ Fortran_Array3D B(m_, n_, k_);
+ B.inject(*this);
+ return B;
+
+}
+
+
+template <class T>
+Fortran_Array3D<T> & Fortran_Array3D<T>::inject(const Fortran_Array3D &A)
+{
+
+ if (m_ == A.m_ && n_ == A.n_ && k_ == A.k_)
+ {
+ T *p = data_;
+ T *end = data_ + m_*n_*k_;
+ const T* q = A.data_;
+ for (; p < end; *p++ = *q++);
+ }
+ return *this;
+}
+
+
+
+
+template <class T>
+Fortran_Array3D<T> & Fortran_Array3D<T>::ref(const Fortran_Array3D<T> &A)
+{
+
+ if (this != &A)
+ {
+ v_ = A.v_;
+ m_ = A.m_;
+ n_ = A.n_;
+ k_ = A.k_;
+ data_ = A.data_;
+ }
+ return *this;
+}
+
+template <class T>
+Fortran_Array3D<T> & Fortran_Array3D<T>::operator=(const Fortran_Array3D<T> &A)
+{
+ return ref(A);
+}
+
+template <class T>
+inline int Fortran_Array3D<T>::dim1() const { return m_; }
+
+template <class T>
+inline int Fortran_Array3D<T>::dim2() const { return n_; }
+
+template <class T>
+inline int Fortran_Array3D<T>::dim3() const { return k_; }
+
+
+template <class T>
+inline int Fortran_Array3D<T>::ref_count() const
+{
+ return v_.ref_count();
+}
+
+template <class T>
+Fortran_Array3D<T>::~Fortran_Array3D()
+{
+}
+
+
+} /* namespace TNT */
+
+#endif
+/* TNT_FORTRAN_ARRAY3D_H */
+
diff --git a/lib/include/tnt/tnt_fortran_array3d_utils.h b/lib/include/tnt/tnt_fortran_array3d_utils.h
new file mode 100644
index 0000000..a13a275
--- /dev/null
+++ b/lib/include/tnt/tnt_fortran_array3d_utils.h
@@ -0,0 +1,249 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+#ifndef TNT_FORTRAN_ARRAY3D_UTILS_H
+#define TNT_FORTRAN_ARRAY3D_UTILS_H
+
+#include <cstdlib>
+#include <cassert>
+
+namespace TNT
+{
+
+
+template <class T>
+std::ostream& operator<<(std::ostream &s, const Fortran_Array3D<T> &A)
+{
+ int M=A.dim1();
+ int N=A.dim2();
+ int K=A.dim3();
+
+ s << M << " " << N << " " << K << "\n";
+
+ for (int i=1; i<=M; i++)
+ {
+ for (int j=1; j<=N; j++)
+ {
+ for (int k=1; k<=K; k++)
+ s << A(i,j,k) << " ";
+ s << "\n";
+ }
+ s << "\n";
+ }
+
+
+ return s;
+}
+
+template <class T>
+std::istream& operator>>(std::istream &s, Fortran_Array3D<T> &A)
+{
+
+ int M, N, K;
+
+ s >> M >> N >> K;
+
+ Fortran_Array3D<T> B(M,N,K);
+
+ for (int i=1; i<=M; i++)
+ for (int j=1; j<=N; j++)
+ for (int k=1; k<=K; k++)
+ s >> B(i,j,k);
+
+ A = B;
+ return s;
+}
+
+
+template <class T>
+Fortran_Array3D<T> operator+(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
+ return Fortran_Array3D<T>();
+
+ else
+ {
+ Fortran_Array3D<T> C(m,n,p);
+
+ for (int i=1; i<=m; i++)
+ for (int j=1; j<=n; j++)
+ for (int k=1; k<=p; k++)
+ C(i,j,k) = A(i,j,k)+ B(i,j,k);
+
+ return C;
+ }
+}
+
+
+template <class T>
+Fortran_Array3D<T> operator-(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
+ return Fortran_Array3D<T>();
+
+ else
+ {
+ Fortran_Array3D<T> C(m,n,p);
+
+ for (int i=1; i<=m; i++)
+ for (int j=1; j<=n; j++)
+ for (int k=1; k<=p; k++)
+ C(i,j,k) = A(i,j,k)- B(i,j,k);
+
+ return C;
+ }
+}
+
+
+template <class T>
+Fortran_Array3D<T> operator*(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
+ return Fortran_Array3D<T>();
+
+ else
+ {
+ Fortran_Array3D<T> C(m,n,p);
+
+ for (int i=1; i<=m; i++)
+ for (int j=1; j<=n; j++)
+ for (int k=1; k<=p; k++)
+ C(i,j,k) = A(i,j,k)* B(i,j,k);
+
+ return C;
+ }
+}
+
+
+template <class T>
+Fortran_Array3D<T> operator/(const Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() != m || B.dim2() != n || B.dim3() != p )
+ return Fortran_Array3D<T>();
+
+ else
+ {
+ Fortran_Array3D<T> C(m,n,p);
+
+ for (int i=1; i<=m; i++)
+ for (int j=1; j<=n; j++)
+ for (int k=1; k<=p; k++)
+ C(i,j,k) = A(i,j,k)/ B(i,j,k);
+
+ return C;
+ }
+}
+
+
+template <class T>
+Fortran_Array3D<T>& operator+=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
+ {
+ for (int i=1; i<=m; i++)
+ for (int j=1; j<=n; j++)
+ for (int k=1; k<=p; k++)
+ A(i,j,k) += B(i,j,k);
+ }
+
+ return A;
+}
+
+
+template <class T>
+Fortran_Array3D<T>& operator-=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
+ {
+ for (int i=1; i<=m; i++)
+ for (int j=1; j<=n; j++)
+ for (int k=1; k<=p; k++)
+ A(i,j,k) -= B(i,j,k);
+ }
+
+ return A;
+}
+
+
+template <class T>
+Fortran_Array3D<T>& operator*=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
+ {
+ for (int i=1; i<=m; i++)
+ for (int j=1; j<=n; j++)
+ for (int k=1; k<=p; k++)
+ A(i,j,k) *= B(i,j,k);
+ }
+
+ return A;
+}
+
+
+template <class T>
+Fortran_Array3D<T>& operator/=(Fortran_Array3D<T> &A, const Fortran_Array3D<T> &B)
+{
+ int m = A.dim1();
+ int n = A.dim2();
+ int p = A.dim3();
+
+ if (B.dim1() == m && B.dim2() == n && B.dim3() == p )
+ {
+ for (int i=1; i<=m; i++)
+ for (int j=1; j<=n; j++)
+ for (int k=1; k<=p; k++)
+ A(i,j,k) /= B(i,j,k);
+ }
+
+ return A;
+}
+
+
+} // namespace TNT
+
+#endif
diff --git a/lib/include/tnt/tnt_i_refvec.h b/lib/include/tnt/tnt_i_refvec.h
new file mode 100644
index 0000000..5a67eb5
--- /dev/null
+++ b/lib/include/tnt/tnt_i_refvec.h
@@ -0,0 +1,243 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef TNT_I_REFVEC_H
+#define TNT_I_REFVEC_H
+
+#include <cstdlib>
+#include <iostream>
+
+#ifdef TNT_BOUNDS_CHECK
+#include <assert.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+namespace TNT
+{
+/*
+ Internal representation of ref-counted array. The TNT
+ arrays all use this building block.
+
+ <p>
+ If an array block is created by TNT, then every time
+ an assignment is made, the left-hand-side reference
+ is decreased by one, and the right-hand-side refernce
+ count is increased by one. If the array block was
+ external to TNT, the refernce count is a NULL pointer
+ regardless of how many references are made, since the
+ memory is not freed by TNT.
+
+
+
+*/
+template <class T>
+class i_refvec
+{
+
+
+ private:
+ T* data_;
+ int *ref_count_;
+
+
+ public:
+
+ i_refvec();
+ explicit i_refvec(int n);
+ inline i_refvec(T* data);
+ inline i_refvec(const i_refvec &v);
+ inline T* begin();
+ inline const T* begin() const;
+ inline T& operator[](int i);
+ inline const T& operator[](int i) const;
+ inline i_refvec<T> & operator=(const i_refvec<T> &V);
+ void copy_(T* p, const T* q, const T* e);
+ void set_(T* p, const T* b, const T* e);
+ inline int ref_count() const;
+ inline int is_null() const;
+ inline void destroy();
+ ~i_refvec();
+
+};
+
+template <class T>
+void i_refvec<T>::copy_(T* p, const T* q, const T* e)
+{
+ for (T* t=p; q<e; t++, q++)
+ *t= *q;
+}
+
+template <class T>
+i_refvec<T>::i_refvec() : data_(NULL), ref_count_(NULL) {}
+
+/**
+ In case n is 0 or negative, it does NOT call new.
+*/
+template <class T>
+i_refvec<T>::i_refvec(int n) : data_(NULL), ref_count_(NULL)
+{
+ if (n >= 1)
+ {
+#ifdef TNT_DEBUG
+ std::cout << "new data storage.\n";
+#endif
+ data_ = new T[n];
+ ref_count_ = new int;
+ *ref_count_ = 1;
+ }
+}
+
+template <class T>
+inline i_refvec<T>::i_refvec(const i_refvec<T> &V): data_(V.data_),
+ ref_count_(V.ref_count_)
+{
+ if (V.ref_count_ != NULL)
+ (*(V.ref_count_))++;
+}
+
+
+template <class T>
+i_refvec<T>::i_refvec(T* data) : data_(data), ref_count_(NULL) {}
+
+template <class T>
+inline T* i_refvec<T>::begin()
+{
+ return data_;
+}
+
+template <class T>
+inline const T& i_refvec<T>::operator[](int i) const
+{
+ return data_[i];
+}
+
+template <class T>
+inline T& i_refvec<T>::operator[](int i)
+{
+ return data_[i];
+}
+
+
+template <class T>
+inline const T* i_refvec<T>::begin() const
+{
+ return data_;
+}
+
+
+
+template <class T>
+i_refvec<T> & i_refvec<T>::operator=(const i_refvec<T> &V)
+{
+ if (this == &V)
+ return *this;
+
+
+ if (ref_count_ != NULL)
+ {
+ (*ref_count_) --;
+ if ((*ref_count_) == 0)
+ destroy();
+ }
+
+ data_ = V.data_;
+ ref_count_ = V.ref_count_;
+
+ if (V.ref_count_ != NULL)
+ (*(V.ref_count_))++;
+
+ return *this;
+}
+
+template <class T>
+void i_refvec<T>::destroy()
+{
+ if (ref_count_ != NULL)
+ {
+#ifdef TNT_DEBUG
+ std::cout << "destorying data... \n";
+#endif
+ delete ref_count_;
+
+#ifdef TNT_DEBUG
+ std::cout << "deleted ref_count_ ...\n";
+#endif
+ if (data_ != NULL)
+ delete []data_;
+#ifdef TNT_DEBUG
+ std::cout << "deleted data_[] ...\n";
+#endif
+ data_ = NULL;
+ }
+}
+
+/*
+* return 1 is vector is empty, 0 otherwise
+*
+* if is_null() is false and ref_count() is 0, then
+*
+*/
+template<class T>
+int i_refvec<T>::is_null() const
+{
+ return (data_ == NULL ? 1 : 0);
+}
+
+/*
+* returns -1 if data is external,
+* returns 0 if a is NULL array,
+* otherwise returns the positive number of vectors sharing
+* this data space.
+*/
+template <class T>
+int i_refvec<T>::ref_count() const
+{
+ if (data_ == NULL)
+ return 0;
+ else
+ return (ref_count_ != NULL ? *ref_count_ : -1) ;
+}
+
+template <class T>
+i_refvec<T>::~i_refvec()
+{
+ if (ref_count_ != NULL)
+ {
+ (*ref_count_)--;
+
+ if (*ref_count_ == 0)
+ destroy();
+ }
+}
+
+
+} /* namespace TNT */
+
+
+
+
+
+#endif
+/* TNT_I_REFVEC_H */
+
diff --git a/lib/include/tnt/tnt_math_utils.h b/lib/include/tnt/tnt_math_utils.h
new file mode 100644
index 0000000..f9c1c91
--- /dev/null
+++ b/lib/include/tnt/tnt_math_utils.h
@@ -0,0 +1,34 @@
+#ifndef MATH_UTILS_H
+#define MATH_UTILS_H
+
+/* needed for fabs, sqrt() below */
+#include <cmath>
+
+
+
+namespace TNT
+{
+/**
+ @returns hypotenuse of real (non-complex) scalars a and b by
+ avoiding underflow/overflow
+ using (a * sqrt( 1 + (b/a) * (b/a))), rather than
+ sqrt(a*a + b*b).
+*/
+template <class Real>
+Real hypot(const Real &a, const Real &b)
+{
+
+ if (a== 0)
+ return abs(b);
+ else
+ {
+ Real c = b/a;
+ return fabs(a) * sqrt(1 + c*c);
+ }
+}
+} /* TNT namespace */
+
+
+
+#endif
+/* MATH_UTILS_H */
diff --git a/lib/include/tnt/tnt_sparse_matrix_csr.h b/lib/include/tnt/tnt_sparse_matrix_csr.h
new file mode 100644
index 0000000..0d4fde1
--- /dev/null
+++ b/lib/include/tnt/tnt_sparse_matrix_csr.h
@@ -0,0 +1,103 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+#ifndef TNT_SPARSE_MATRIX_CSR_H
+#define TNT_SPARSE_MATRIX_CSR_H
+
+#include "tnt_array1d.h"
+
+namespace TNT
+{
+
+
+/**
+ Read-only view of a sparse matrix in compressed-row storage
+ format. Neither array elements (nonzeros) nor sparsity
+ structure can be modified. If modifications are required,
+ create a new view.
+
+ <p>
+ Index values begin at 0.
+
+ <p>
+ <b>Storage requirements:</b> An (m x n) matrix with
+ nz nonzeros requires no more than ((T+I)*nz + M*I)
+ bytes, where T is the size of data elements and
+ I is the size of integers.
+
+
+*/
+template <class T>
+class Sparse_Matrix_CompRow {
+
+private:
+ Array1D<T> val_; // data values (nz_ elements)
+ Array1D<int> rowptr_; // row_ptr (dim_[0]+1 elements)
+ Array1D<int> colind_; // col_ind (nz_ elements)
+
+ int dim1_; // number of rows
+ int dim2_; // number of cols
+
+public:
+
+ Sparse_Matrix_CompRow(const Sparse_Matrix_CompRow &S);
+ Sparse_Matrix_CompRow(int M, int N, int nz, const T *val,
+ const int *r, const int *c);
+
+
+
+ inline const T& val(int i) const { return val_[i]; }
+ inline const int& row_ptr(int i) const { return rowptr_[i]; }
+ inline const int& col_ind(int i) const { return colind_[i];}
+
+ inline int dim1() const {return dim1_;}
+ inline int dim2() const {return dim2_;}
+ int NumNonzeros() const {return val_.dim1();}
+
+
+ Sparse_Matrix_CompRow& operator=(
+ const Sparse_Matrix_CompRow &R);
+
+
+
+};
+
+/**
+ Construct a read-only view of existing sparse matrix in
+ compressed-row storage format.
+
+ @param M the number of rows of sparse matrix
+ @param N the number of columns of sparse matrix
+ @param nz the number of nonzeros
+ @param val a contiguous list of nonzero values
+ @param r row-pointers: r[i] denotes the begining position of row i
+ (i.e. the ith row begins at val[row[i]]).
+ @param c column-indices: c[i] denotes the column location of val[i]
+*/
+template <class T>
+Sparse_Matrix_CompRow<T>::Sparse_Matrix_CompRow(int M, int N, int nz,
+ const T *val, const int *r, const int *c) : val_(nz,val),
+ rowptr_(M, r), colind_(nz, c), dim1_(M), dim2_(N) {}
+
+
+}
+// namespace TNT
+
+#endif
diff --git a/lib/include/tnt/tnt_stopwatch.h b/lib/include/tnt/tnt_stopwatch.h
new file mode 100644
index 0000000..8dc5d23
--- /dev/null
+++ b/lib/include/tnt/tnt_stopwatch.h
@@ -0,0 +1,95 @@
+/*
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef STOPWATCH_H
+#define STOPWATCH_H
+
+// for clock() and CLOCKS_PER_SEC
+#include <time.h>
+
+
+namespace TNT
+{
+
+inline static double seconds(void)
+{
+ const double secs_per_tick = 1.0 / CLOCKS_PER_SEC;
+ return ( (double) clock() ) * secs_per_tick;
+}
+
+class Stopwatch {
+ private:
+ int running_;
+ double start_time_;
+ double total_;
+
+ public:
+ inline Stopwatch();
+ inline void start();
+ inline double stop();
+ inline double read();
+ inline void resume();
+ inline int running();
+};
+
+inline Stopwatch::Stopwatch() : running_(0), start_time_(0.0), total_(0.0) {}
+
+void Stopwatch::start()
+{
+ running_ = 1;
+ total_ = 0.0;
+ start_time_ = seconds();
+}
+
+double Stopwatch::stop()
+{
+ if (running_)
+ {
+ total_ += (seconds() - start_time_);
+ running_ = 0;
+ }
+ return total_;
+}
+
+inline void Stopwatch::resume()
+{
+ if (!running_)
+ {
+ start_time_ = seconds();
+ running_ = 1;
+ }
+}
+
+
+inline double Stopwatch::read()
+{
+ if (running_)
+ {
+ stop();
+ resume();
+ }
+ return total_;
+}
+
+
+} /* TNT namespace */
+#endif
+
+
+
diff --git a/lib/include/tnt/tnt_subscript.h b/lib/include/tnt/tnt_subscript.h
new file mode 100644
index 0000000..d8fe120
--- /dev/null
+++ b/lib/include/tnt/tnt_subscript.h
@@ -0,0 +1,54 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+#ifndef TNT_SUBSCRPT_H
+#define TNT_SUBSCRPT_H
+
+
+//---------------------------------------------------------------------
+// This definition describes the default TNT data type used for
+// indexing into TNT matrices and vectors. The data type should
+// be wide enough to index into large arrays. It defaults to an
+// "int", but can be overriden at compile time redefining TNT_SUBSCRIPT_TYPE,
+// e.g.
+//
+// c++ -DTNT_SUBSCRIPT_TYPE='unsigned int' ...
+//
+//---------------------------------------------------------------------
+//
+
+#ifndef TNT_SUBSCRIPT_TYPE
+#define TNT_SUBSCRIPT_TYPE int
+#endif
+
+namespace TNT
+{
+ typedef TNT_SUBSCRIPT_TYPE Subscript;
+} /* namespace TNT */
+
+
+// () indexing in TNT means 1-offset, i.e. x(1) and A(1,1) are the
+// first elements. This offset is left as a macro for future
+// purposes, but should not be changed in the current release.
+//
+//
+#define TNT_BASE_OFFSET (1)
+
+#endif
diff --git a/lib/include/tnt/tnt_vec.h b/lib/include/tnt/tnt_vec.h
new file mode 100644
index 0000000..3455d79
--- /dev/null
+++ b/lib/include/tnt/tnt_vec.h
@@ -0,0 +1,404 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+
+
+#ifndef TNT_VEC_H
+#define TNT_VEC_H
+
+#include "tnt_subscript.h"
+#include <cstdlib>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+
+namespace TNT
+{
+
+/**
+ <b>[Deprecatred]</b> Value-based vector class from pre-1.0
+ TNT version. Kept here for backward compatiblity, but should
+ use the newer TNT::Array1D classes instead.
+
+*/
+
+template <class T>
+class Vector
+{
+
+
+ public:
+
+ typedef Subscript size_type;
+ typedef T value_type;
+ typedef T element_type;
+ typedef T* pointer;
+ typedef T* iterator;
+ typedef T& reference;
+ typedef const T* const_iterator;
+ typedef const T& const_reference;
+
+ Subscript lbound() const { return 1;}
+
+ protected:
+ T* v_;
+ T* vm1_; // pointer adjustment for optimzied 1-offset indexing
+ Subscript n_;
+
+ // internal helper function to create the array
+ // of row pointers
+
+ void initialize(Subscript N)
+ {
+ // adjust pointers so that they are 1-offset:
+ // v_[] is the internal contiguous array, it is still 0-offset
+ //
+ assert(v_ == NULL);
+ v_ = new T[N];
+ assert(v_ != NULL);
+ vm1_ = v_-1;
+ n_ = N;
+ }
+
+ void copy(const T* v)
+ {
+ Subscript N = n_;
+ Subscript i;
+
+#ifdef TNT_UNROLL_LOOPS
+ Subscript Nmod4 = N & 3;
+ Subscript N4 = N - Nmod4;
+
+ for (i=0; i<N4; i+=4)
+ {
+ v_[i] = v[i];
+ v_[i+1] = v[i+1];
+ v_[i+2] = v[i+2];
+ v_[i+3] = v[i+3];
+ }
+
+ for (i=N4; i< N; i++)
+ v_[i] = v[i];
+#else
+
+ for (i=0; i< N; i++)
+ v_[i] = v[i];
+#endif
+ }
+
+ void set(const T& val)
+ {
+ Subscript N = n_;
+ Subscript i;
+
+#ifdef TNT_UNROLL_LOOPS
+ Subscript Nmod4 = N & 3;
+ Subscript N4 = N - Nmod4;
+
+ for (i=0; i<N4; i+=4)
+ {
+ v_[i] = val;
+ v_[i+1] = val;
+ v_[i+2] = val;
+ v_[i+3] = val;
+ }
+
+ for (i=N4; i< N; i++)
+ v_[i] = val;
+#else
+
+ for (i=0; i< N; i++)
+ v_[i] = val;
+
+#endif
+ }
+
+
+
+ void destroy()
+ {
+ /* do nothing, if no memory has been previously allocated */
+ if (v_ == NULL) return ;
+
+ /* if we are here, then matrix was previously allocated */
+ delete [] (v_);
+
+ v_ = NULL;
+ vm1_ = NULL;
+ }
+
+
+ public:
+
+ // access
+
+ iterator begin() { return v_;}
+ iterator end() { return v_ + n_; }
+ const iterator begin() const { return v_;}
+ const iterator end() const { return v_ + n_; }
+
+ // destructor
+
+ ~Vector()
+ {
+ destroy();
+ }
+
+ // constructors
+
+ Vector() : v_(0), vm1_(0), n_(0) {};
+
+ Vector(const Vector<T> &A) : v_(0), vm1_(0), n_(0)
+ {
+ initialize(A.n_);
+ copy(A.v_);
+ }
+
+ Vector(Subscript N, const T& value = T()) : v_(0), vm1_(0), n_(0)
+ {
+ initialize(N);
+ set(value);
+ }
+
+ Vector(Subscript N, const T* v) : v_(0), vm1_(0), n_(0)
+ {
+ initialize(N);
+ copy(v);
+ }
+
+ Vector(Subscript N, char *s) : v_(0), vm1_(0), n_(0)
+ {
+ initialize(N);
+ std::istringstream ins(s);
+
+ Subscript i;
+
+ for (i=0; i<N; i++)
+ ins >> v_[i];
+ }
+
+
+ // methods
+ //
+ Vector<T>& newsize(Subscript N)
+ {
+ if (n_ == N) return *this;
+
+ destroy();
+ initialize(N);
+
+ return *this;
+ }
+
+
+ // assignments
+ //
+ Vector<T>& operator=(const Vector<T> &A)
+ {
+ if (v_ == A.v_)
+ return *this;
+
+ if (n_ == A.n_) // no need to re-alloc
+ copy(A.v_);
+
+ else
+ {
+ destroy();
+ initialize(A.n_);
+ copy(A.v_);
+ }
+
+ return *this;
+ }
+
+ Vector<T>& operator=(const T& scalar)
+ {
+ set(scalar);
+ return *this;
+ }
+
+ inline Subscript dim() const
+ {
+ return n_;
+ }
+
+ inline Subscript size() const
+ {
+ return n_;
+ }
+
+
+ inline reference operator()(Subscript i)
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(1<=i);
+ assert(i <= n_) ;
+#endif
+ return vm1_[i];
+ }
+
+ inline const_reference operator() (Subscript i) const
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(1<=i);
+ assert(i <= n_) ;
+#endif
+ return vm1_[i];
+ }
+
+ inline reference operator[](Subscript i)
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(0<=i);
+ assert(i < n_) ;
+#endif
+ return v_[i];
+ }
+
+ inline const_reference operator[](Subscript i) const
+ {
+#ifdef TNT_BOUNDS_CHECK
+ assert(0<=i);
+
+
+
+
+
+
+ assert(i < n_) ;
+#endif
+ return v_[i];
+ }
+
+
+
+};
+
+
+/* *************************** I/O ********************************/
+
+template <class T>
+std::ostream& operator<<(std::ostream &s, const Vector<T> &A)
+{
+ Subscript N=A.dim();
+
+ s << N << "\n";
+
+ for (Subscript i=0; i<N; i++)
+ s << A[i] << " " << "\n";
+ s << "\n";
+
+ return s;
+}
+
+template <class T>
+std::istream & operator>>(std::istream &s, Vector<T> &A)
+{
+
+ Subscript N;
+
+ s >> N;
+
+ if ( !(N == A.size() ))
+ {
+ A.newsize(N);
+ }
+
+
+ for (Subscript i=0; i<N; i++)
+ s >> A[i];
+
+
+ return s;
+}
+
+// *******************[ basic matrix algorithms ]***************************
+
+
+template <class T>
+Vector<T> operator+(const Vector<T> &A,
+ const Vector<T> &B)
+{
+ Subscript N = A.dim();
+
+ assert(N==B.dim());
+
+ Vector<T> tmp(N);
+ Subscript i;
+
+ for (i=0; i<N; i++)
+ tmp[i] = A[i] + B[i];
+
+ return tmp;
+}
+
+template <class T>
+Vector<T> operator-(const Vector<T> &A,
+ const Vector<T> &B)
+{
+ Subscript N = A.dim();
+
+ assert(N==B.dim());
+
+ Vector<T> tmp(N);
+ Subscript i;
+
+ for (i=0; i<N; i++)
+ tmp[i] = A[i] - B[i];
+
+ return tmp;
+}
+
+template <class T>
+Vector<T> operator*(const Vector<T> &A,
+ const Vector<T> &B)
+{
+ Subscript N = A.dim();
+
+ assert(N==B.dim());
+
+ Vector<T> tmp(N);
+ Subscript i;
+
+ for (i=0; i<N; i++)
+ tmp[i] = A[i] * B[i];
+
+ return tmp;
+}
+
+
+template <class T>
+T dot_prod(const Vector<T> &A, const Vector<T> &B)
+{
+ Subscript N = A.dim();
+ assert(N == B.dim());
+
+ Subscript i;
+ T sum = 0;
+
+ for (i=0; i<N; i++)
+ sum += A[i] * B[i];
+
+ return sum;
+}
+
+} /* namespace TNT */
+
+#endif
+// TNT_VEC_H
diff --git a/lib/include/tnt/tnt_version.h b/lib/include/tnt/tnt_version.h
new file mode 100644
index 0000000..047e7d3
--- /dev/null
+++ b/lib/include/tnt/tnt_version.h
@@ -0,0 +1,39 @@
+/*
+*
+* Template Numerical Toolkit (TNT)
+*
+* Mathematical and Computational Sciences Division
+* National Institute of Technology,
+* Gaithersburg, MD USA
+*
+*
+* This software was developed at the National Institute of Standards and
+* Technology (NIST) by employees of the Federal Government in the course
+* of their official duties. Pursuant to title 17 Section 105 of the
+* United States Code, this software is not subject to copyright protection
+* and is in the public domain. NIST assumes no responsibility whatsoever for
+* its use by other parties, and makes no guarantees, expressed or implied,
+* about its quality, reliability, or any other characteristic.
+*
+*/
+
+#ifndef TNT_VERSION_H
+#define TNT_VERSION_H
+
+
+//---------------------------------------------------------------------
+// current version
+//---------------------------------------------------------------------
+
+
+#define TNT_MAJOR_VERSION '1'
+#define TNT_MINOR_VERSION '2'
+#define TNT_SUBMINOR_VERSION '6'
+#define TNT_VERSION_STRING "1.2.6"
+
+
+
+
+
+#endif
+// TNT_VERSION_H
diff --git a/lib/licenses/rapidxml.txt b/lib/licenses/rapidxml.txt
new file mode 100644
index 0000000..1409831
--- /dev/null
+++ b/lib/licenses/rapidxml.txt
@@ -0,0 +1,52 @@
+Use of this software is granted under one of the following two licenses,
+to be chosen freely by the user.
+
+1. Boost Software License - Version 1.0 - August 17th, 2003
+===============================================================================
+
+Copyright (c) 2006, 2007 Marcin Kalicinski
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+2. The MIT License
+===============================================================================
+
+Copyright (c) 2006, 2007 Marcin Kalicinski
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
diff --git a/lib/licenses/tnt.txt b/lib/licenses/tnt.txt
new file mode 100644
index 0000000..3dafbe0
--- /dev/null
+++ b/lib/licenses/tnt.txt
@@ -0,0 +1,14 @@
+Template Numerical Toolkit (TNT): Linear Algebra Module
+
+Mathematical and Computational Sciences Division
+National Institute of Technology,
+Gaithersburg, MD USA
+
+
+This software was developed at the National Institute of Standards and
+Technology (NIST) by employees of the Federal Government in the course
+of their official duties. Pursuant to title 17 Section 105 of the
+United States Code, this software is not subject to copyright protection
+and is in the public domain. NIST assumes no responsibility whatsoever for
+its use by other parties, and makes no guarantees, expressed or implied,
+about its quality, reliability, or any other characteristic.
diff --git a/matlab/algorithms/DART/DARTalgorithm.m b/matlab/algorithms/DART/DARTalgorithm.m
new file mode 100644
index 0000000..b7e63b5
--- /dev/null
+++ b/matlab/algorithms/DART/DARTalgorithm.m
@@ -0,0 +1,229 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef DARTalgorithm < matlab.mixin.Copyable
+
+ % Algorithm class for Discrete Algebraic Reconstruction Technique (DART).
+
+ % todo: reset()
+ % todo: fixed random seed
+ % todo: initialize from settings (?)
+
+ %----------------------------------------------------------------------
+ properties (GetAccess=public, SetAccess=public)
+
+ tomography = TomographyDefault(); % POLICY: Tomography object.
+ segmentation = SegmentationDefault(); % POLICY: Segmentation object.
+ smoothing = SmoothingDefault(); % POLICY: Smoothing object.
+ masking = MaskingDefault(); % POLICY: Masking object.
+ output = OutputDefault(); % POLICY: Output object.
+ statistics = StatisticsDefault(); % POLICY: Statistics object.
+
+ base = struct(); % DATA(set): base structure, should contain: 'sinogram', 'proj_geom', 'phantom' (optional).
+
+ memory = 'yes'; % SETTING: reduce memory usage? (disables some features)
+
+ testdata = struct();
+
+ end
+ %----------------------------------------------------------------------
+ properties (GetAccess=public, SetAccess=private)
+ V0 = []; % DATA(get): Initial reconstruction.
+ V = []; % DATA(get): Reconstruction.
+ S = []; % DATA(get): Segmentation.
+ R = []; % DATA(get): Residual projection data.
+ Mask = []; % DATA(get): Reconstruction Mask.
+ stats = struct(); % Structure containing various statistics.
+ iterationcount = 0; % Number of performed iterations.
+ start_tic = 0;
+ initialized = 0; % Is initialized?
+ end
+ %----------------------------------------------------------------------
+ properties (Access=private)
+ adaptparam_name = {};
+ adaptparam_values = {};
+ adaptparam_iters = {};
+ end
+
+ %----------------------------------------------------------------------
+ methods
+
+ %------------------------------------------------------------------
+ function this = DARTalgorithm(base)
+ % Constructor
+ % >> D = DARTalgorithm(base); base is a matlab struct (or the path towards one)
+ % that should contain 'sinogram', 'proj_geom'.
+
+ if ischar(base)
+ this.base = load(base);
+ else
+ this.base = base;
+ end
+ end
+
+
+ %------------------------------------------------------------------
+ function D = deepcopy(this)
+ % Create a deep copy of this object.
+ % >> D2 = D.deepcopy();
+
+ D = copy(this);
+ props = properties(this);
+ for i = 1:length(props)
+ if isa(this.(props{i}), 'handle')
+ D.(props{i}) = copy(this.(props{i}));
+ end
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ function this = initialize(this)
+ % Initializes this object.
+ % >> D.initialize();
+
+ % Initialize tomography part
+ this.tomography.initialize(this);
+
+ % Create an Initial Reconstruction
+ if isfield(this.base, 'V0')
+ this.V0 = this.base.V0;
+ else
+ this.output.pre_initial_iteration(this);
+ this.V0 = this.tomography.createInitialReconstruction(this, this.base.sinogram);
+ this.output.post_initial_iteration(this);
+ end
+ this.V = this.V0;
+ if strcmp(this.memory,'yes')
+ this.base.V0 = [];
+ this.V0 = [];
+ end
+ this.initialized = 1;
+ end
+
+ %------------------------------------------------------------------
+ % iterate
+ function this = iterate(this, iters)
+ % Perform several iterations of the DART algorithm.
+ % >> D.iterate(iterations);
+
+ this.start_tic = tic;
+
+ for iteration = 1:iters
+
+ this.iterationcount = this.iterationcount + 1;
+
+ %----------------------------------------------------------
+ % Initial Output
+ this.output.pre_iteration(this);
+
+ %----------------------------------------------------------
+ % Update Adaptive Parameters
+ for i = 1:numel(this.adaptparam_name)
+
+ for j = 1:numel(this.adaptparam_iters{i})
+ if this.iterationcount == this.adaptparam_iters{i}(j)
+ new_value = this.adaptparam_values{i}(j);
+ eval(['this.' this.adaptparam_name{i} ' = ' num2str(new_value) ';']);
+ disp(['value ' this.adaptparam_name{i} ' changed to ' num2str(new_value) ]);
+ end
+ end
+
+ end
+
+ %----------------------------------------------------------
+ % Segmentation
+ this.segmentation.estimate_grey_levels(this, this.V);
+ this.S = this.segmentation.apply(this, this.V);
+
+ %----------------------------------------------------------
+ % Select Update and Fixed Pixels
+ this.Mask = this.masking.apply(this, this.S);
+
+ this.V = (this.V .* this.Mask) + (this.S .* (1 - this.Mask));
+ %this.V(this.Mask == 0) = this.S(this.Mask == 0);
+
+ F = this.V;
+ F(this.Mask == 1) = 0;
+
+ %----------------------------------------------------------
+ % Create Residual Projection Difference
+ %this.testdata.F{iteration} = F;
+ this.R = this.base.sinogram - this.tomography.createForwardProjection(this, F);
+ %this.testdata.R{iteration} = this.R;
+
+ %----------------------------------------------------------
+ % ART Loose Part
+ %this.testdata.V1{iteration} = this.V;
+ %this.testdata.Mask{iteration} = this.Mask;
+
+ %X = zeros(size(this.V));
+ %Y = this.tomography.createReconstruction(this, this.R, X, this.Mask);
+ %this.V(this.Mask) = Y(this.Mask);
+ this.V = this.tomography.createReconstruction(this, this.R, this.V, this.Mask);
+
+ %this.testdata.V2{iteration} = this.V;
+
+ %----------------------------------------------------------
+ % Blur
+ this.V = this.smoothing.apply(this, this.V);
+ %this.testdata.V3{iteration} = this.V;
+
+ %----------------------------------------------------------
+ % Calculate Statistics
+ this.stats = this.statistics.apply(this);
+
+ %----------------------------------------------------------
+ % Output
+ this.output.post_iteration(this);
+
+ end % end iteration loop
+
+ %test = this.testdata;
+ %save('testdata.mat','test');
+
+ end
+
+ %------------------------------------------------------------------
+ % get data
+ function data = getdata(this, string)
+ if numel(this.(string)) == 1
+ data = astra_mex_data2d('get',this.(string));
+ else
+ data = this.(string);
+ end
+ end
+
+ %------------------------------------------------------------------
+ % add adaptive parameter
+ function this = adaptiveparameter(this, name, values, iterations)
+ this.adaptparam_name{end+1} = name;
+ this.adaptparam_values{end+1} = values;
+ this.adaptparam_iters{end+1} = iterations;
+ end
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = tomography.getsettings();
+
+ settings.tomography = this.tomography.getsettings();
+ settings.smoothing = this.smoothing.getsettings();
+ settings.masking = this.masking.getsettings();
+ settings.segmentation = this.segmentation.getsettings();
+ end
+ %------------------------------------------------------------------
+
+ end % methods
+
+end % class
+
+
diff --git a/matlab/algorithms/DART/IterativeTomography.m b/matlab/algorithms/DART/IterativeTomography.m
new file mode 100644
index 0000000..b30640e
--- /dev/null
+++ b/matlab/algorithms/DART/IterativeTomography.m
@@ -0,0 +1,455 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef IterativeTomography < matlab.mixin.Copyable
+
+ % Algorithm class for 2D Iterative Tomography.
+
+ %----------------------------------------------------------------------
+ properties (SetAccess=public, GetAccess=public)
+ superresolution = 1; % SETTING: Volume upsampling factor.
+ proj_type = 'linear'; % SETTING: Projector type, only when gpu='no'.
+ method = 'SIRT_CUDA'; % SETTING: Iterative method (see ASTRA toolbox documentation).
+ gpu = 'yes'; % SETTING: Use gpu? {'yes', 'no'}
+ gpu_core = 0; % SETTING: Which gpu core to use? Only when gpu='yes'.
+ inner_circle = 'yes'; % SETTING: Do roi only? {'yes', 'no'}
+ image_size = []; % SETTING: Overwrite default reconstruction size. Only if no vol_geom is specified.
+ use_minc = 'no'; % SETTING: Use minimum constraint. {'no', 'yes'}
+ end
+ %----------------------------------------------------------------------
+ properties (SetAccess=public, GetAccess=public)
+ sinogram = []; % DATA: Projection data.
+ proj_geom = []; % DATA: Projection geometry.
+ V = []; % DATA: Volume data. Also used to set initial estimate (optional).
+ vol_geom = []; % DATA: Volume geometry.
+ end
+ %----------------------------------------------------------------------
+ properties (SetAccess=private, GetAccess=public)
+ initialized = 0; % Is this object initialized?
+ end
+ %----------------------------------------------------------------------
+ properties (SetAccess=protected, GetAccess=protected)
+ proj_geom_sr = []; % PROTECTED: geometry of sinogram (with super-resolution)
+ proj_id = []; % PROTECTED: astra id of projector (when gpu='no')
+ proj_id_sr = []; % PROTECTED: astra id of super-resolution projector (when gpu='no')
+ cfg_base = struct(); % PROTECTED: base configuration structure for the reconstruction algorithm.
+ end
+ %----------------------------------------------------------------------
+
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function this = IterativeTomography(varargin)
+ % Constructor
+ % >> tomography = IterativeTomography();
+ % >> tomography = IterativeTomography(base); base struct should contain fields 'sinogram' and 'proj_geom'.
+ % >> tomography = IterativeTomography(base_filename); mat-file should contain 'sinogram' and 'proj_geom'.
+ % >> tomography = IterativeTomography(proj_geom, vol_geom);
+ % >> tomography = IterativeTomography(sinogram, proj_geom);
+
+ % Input: IterativeTomography(base)
+ if nargin == 1
+ if ischar(varargin{1})
+ this.sinogram = load(varargin{1},'sinogram');
+ this.proj_geom = load(varargin{1},'proj_geom');
+ else
+ this.sinogram = varargin{1}.sinogram;
+ this.proj_geom = varargin{1}.proj_geom;
+ end
+ end
+ % Input: IterativeTomography(proj_geom, vol_geom)
+ if nargin == 2 && isstruct(varargin{1}) && isstruct(varargin{2})
+ this.proj_geom = varargin{1};
+ this.vol_geom = varargin{2};
+ % Input: IterativeTomography(sinogram, proj_geom)
+ elseif nargin == 2
+ this.sinogram = varargin{1};
+ this.proj_geom = varargin{2};
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ function delete(this)
+ % Destructor
+ % >> clear tomography;
+ if strcmp(this.gpu,'no') && numel(this.proj_id) > 0
+ astra_mex_projector('delete', this.proj_id, this.proj_id_sr);
+ end
+ end
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = tomography.getsettings();
+ settings.superresolution = this.superresolution;
+ settings.proj_type = this.proj_type;
+ settings.method = this.method;
+ settings.gpu = this.gpu;
+ settings.gpu_core = this.gpu_core;
+ settings.inner_circle = this.inner_circle;
+ settings.image_size = this.image_size;
+ settings.use_minc = this.use_minc;
+ end
+
+ %------------------------------------------------------------------
+ function ok = initialize(this)
+ % Initialize this object. Returns 1 if succesful.
+ % >> tomography.initialize();
+
+ % create projection geometry with super-resolution
+ this.proj_geom_sr = astra_geom_superresolution(this.proj_geom, this.superresolution);
+
+ % if no volume geometry is specified by the user: create volume geometry
+ if numel(this.vol_geom) == 0
+ if numel(this.image_size) < 2
+ this.image_size(1) = this.proj_geom.DetectorCount;
+ this.image_size(2) = this.proj_geom.DetectorCount;
+ end
+ this.vol_geom = astra_create_vol_geom(this.image_size(1) * this.superresolution, this.image_size(2) * this.superresolution, ...
+ -this.image_size(1)/2, this.image_size(1)/2, -this.image_size(2)/2, this.image_size(2)/2);
+ else
+ this.image_size(1) = this.vol_geom.GridRowCount;
+ this.image_size(2) = this.vol_geom.GridColCount;
+ end
+
+ % create projector
+ if strcmp(this.gpu, 'no')
+ this.proj_id = astra_create_projector(this.proj_type, this.proj_geom, this.vol_geom);
+ this.proj_id_sr = astra_create_projector(this.proj_type, this.proj_geom_sr, this.vol_geom);
+ end
+
+ % create reconstruction configuration
+ this.cfg_base = astra_struct(upper(this.method));
+ if strcmp(this.gpu,'no')
+ this.cfg_base.ProjectorId = this.proj_id;
+ this.cfg_base.ProjectionGeometry = this.proj_geom;
+ this.cfg_base.ReconstructionGeometry = this.vol_geom;
+ this.cfg_base.option.ProjectionOrder = 'random';
+ end
+ this.cfg_base.option.DetectorSuperSampling = this.superresolution;
+ %this.cfg_base.option.DetectorSuperSampling = 8;
+ if strcmp(this.gpu,'yes')
+ this.cfg_base.option.GPUindex = this.gpu_core;
+ end
+ this.cfg_base.option.UseMinConstraint = this.use_minc;
+
+ this.initialized = 1;
+ ok = this.initialized;
+ end
+
+ %------------------------------------------------------------------
+ function P = project(this, volume)
+ % Compute forward projection.
+ % Stores sinogram in tomography.sinogram if it is still empty.
+ % >> P = tomography.project(); projects 'tomography.V'.
+ % >> P = tomography.project(volume); projects 'volume'.
+
+ if ~this.initialized
+ this.initialize();
+ end
+
+ if nargin == 1 % tomography.project();
+ P = this.project_c(this.V);
+
+ elseif nargin == 2 % tomography.project(volume);
+ P = this.project_c(volume);
+ end
+
+ % store
+ if numel(this.sinogram) == 0
+ this.sinogram = P;
+ end
+ end
+
+ %------------------------------------------------------------------
+ function V = reconstruct(this, iterations)
+ % Compute reconstruction.
+ % Uses tomography.sinogram
+ % Initial solution (if available) should be stored in tomography.V
+ % >> V = tomography.reconstruct(iterations);
+
+ if ~this.initialized
+ this.initialize();
+ end
+
+ this.V = this.reconstruct_c(this.sinogram, this.V, [], iterations);
+ if strcmp(this.inner_circle,'yes')
+ this.V = this.selectROI(this.V);
+ end
+ V = this.V;
+ end
+
+ %------------------------------------------------------------------
+ function I = reconstructMask(this, mask, iterations)
+ % Compute reconstruction with mask.
+ % Uses tomography.sinogram
+ % Initial solution (if available) should be stored in tomography.V
+ % >> V = tomography.reconstructMask(mask, iterations);
+
+ if ~this.initialized
+ this.initialize();
+ end
+
+ if strcmp(this.inner_circle,'yes')
+ mask = this.selectROI(mask);
+ end
+ I = this.reconstruct_c(this.sinogram, this.V, mask, iterations);
+ end
+ %------------------------------------------------------------------
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access = protected)
+
+ %------------------------------------------------------------------
+ % Protected function: create FP
+ function sinogram = project_c(this, volume)
+
+ if this.initialized == 0
+ error('IterativeTomography not initialized');
+ end
+
+ % data is stored in astra memory
+ if numel(volume) == 1
+
+ if strcmp(this.gpu, 'yes')
+ sinogram_tmp = astra_create_sino_cuda(volume, this.proj_geom_sr, this.vol_geom, this.gpu_core);
+ else
+ sinogram_tmp = astra_create_sino(volume, this.proj_id);
+ end
+
+ % sinogram downsampling
+ if this.superresolution > 1
+ sinogram_data = astra_mex_data2d('get', sinogram_tmp);
+ astra_mex_data2d('delete', sinogram_tmp);
+ sinogram_data = downsample_sinogram(sinogram_data, this.superresolution);
+ %if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat')
+ % sinogram = sinogram / this.superresolution;
+ %end
+ sinogram = astra_mex_data2d('create','sino', this.proj_geom, sinogram_data);
+ else
+ sinogram = sinogram_tmp;
+ end
+
+ % data is stored in matlab memory
+ else
+
+ % 2D and 3D slice by slice
+ sinogram_tmp = zeros([astra_geom_size(this.proj_geom_sr), size(volume,3)]);
+ sinogram_tmp2 = zeros([astra_geom_size(this.proj_geom), size(volume,3)]);
+ for slice = 1:size(volume,3)
+
+ if strcmp(this.gpu, 'yes')
+ [tmp_id, sinogram_tmp2(:,:,slice)] = astra_create_sino_sampling(volume(:,:,slice), this.proj_geom, this.vol_geom, this.gpu_core, this.superresolution);
+ astra_mex_data2d('delete', tmp_id);
+ else
+ [tmp_id, tmp] = astra_create_sino(volume(:,:,slice), this.proj_id_sr);
+ sinogram_tmp2(:,:,slice) = downsample_sinogram(tmp, this.superresolution) * (this.superresolution^2);
+ astra_mex_data2d('delete', tmp_id);
+ end
+
+ end
+
+ % sinogram downsampling
+ if strcmp(this.gpu, 'yes')
+ %sinogram = downsample_sinogram(sinogram_tmp, this.superresolution);
+ sinogram2 = sinogram_tmp2;
+ if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat')
+ sinogram2 = sinogram2 / this.superresolution;
+ elseif strcmp(this.proj_geom.type,'parallel')
+ sinogram2 = sinogram2 / (this.superresolution * this.superresolution);
+ end
+ sinogram = sinogram2;
+ else
+ sinogram = sinogram_tmp2;
+ end
+
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ % Protected function: reconstruct
+ function V = reconstruct_c(this, sinogram, V0, mask, iterations)
+
+ if this.initialized == 0
+ error('IterativeTomography not initialized');
+ end
+
+ % data is stored in astra memory
+ if numel(sinogram) == 1
+ V = this.reconstruct_c_astra(sinogram, V0, mask, iterations);
+
+ % data is stored in matlab memory
+ else
+ V = this.reconstruct_c_matlab(sinogram, V0, mask, iterations);
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ % Protected function: reconstruct (data in matlab)
+ function V = reconstruct_c_matlab(this, sinogram, V0, mask, iterations)
+
+ if this.initialized == 0
+ error('IterativeTomography not initialized');
+ end
+
+ % parse method
+ method2 = upper(this.method);
+ if strcmp(method2, 'SART') || strcmp(method2, 'SART_CUDA')
+ iterations = iterations * size(sinogram,1);
+ elseif strcmp(method2, 'ART')
+ iterations = iterations * numel(sinogram);
+ end
+
+ % create data objects
+ V = zeros(this.vol_geom.GridRowCount, this.vol_geom.GridColCount, size(sinogram,3));
+ reconstruction_id = astra_mex_data2d('create', '-vol', this.vol_geom);
+ sinogram_id = astra_mex_data2d('create', '-sino', this.proj_geom);
+ if numel(mask) > 0
+ mask_id = astra_mex_data2d('create', '-vol', this.vol_geom);
+ end
+
+ % algorithm configuration
+ cfg = this.cfg_base;
+ cfg.ProjectionDataId = sinogram_id;
+ cfg.ReconstructionDataId = reconstruction_id;
+ if numel(mask) > 0
+ cfg.option.ReconstructionMaskId = mask_id;
+ end
+ alg_id = astra_mex_algorithm('create', cfg);
+
+ % loop slices
+ for slice = 1:size(sinogram,3)
+
+ % fetch slice of initial reconstruction
+ if numel(V0) > 0
+ astra_mex_data2d('store', reconstruction_id, V0(:,:,slice));
+ else
+ astra_mex_data2d('store', reconstruction_id, 0);
+ end
+
+ % fetch slice of sinogram
+ astra_mex_data2d('store', sinogram_id, sinogram(:,:,slice));
+
+ % fecth slice of mask
+ if numel(mask) > 0
+ astra_mex_data2d('store', mask_id, mask(:,:,slice));
+ end
+
+ % iterate
+ astra_mex_algorithm('iterate', alg_id, iterations);
+
+ % fetch data
+ V(:,:,slice) = astra_mex_data2d('get', reconstruction_id);
+
+ end
+
+ % correct attenuation factors for super-resolution
+ if this.superresolution > 1 && strcmp(this.gpu,'yes')
+ if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat')
+ if numel(mask) > 0
+ V(mask > 0) = V(mask > 0) ./ this.superresolution;
+ else
+ V = V ./ this.superresolution;
+ end
+ end
+ end
+
+ % garbage collection
+ astra_mex_algorithm('delete', alg_id);
+ astra_mex_data2d('delete', sinogram_id, reconstruction_id);
+ if numel(mask) > 0
+ astra_mex_data2d('delete', mask_id);
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ % Protected function: reconstruct (data in astra)
+ function V = reconstruct_c_astra(this, sinogram, V0, mask, iterations)
+
+ if this.initialized == 0
+ error('IterativeTomography not initialized');
+ end
+
+ if numel(V0) > 1 || numel(mask) > 1 || numel(sinogram) > 1
+ error('Not all required data is stored in the astra memory');
+ end
+
+ if numel(V0) == 0
+ V0 = astra_mex_data2d('create', '-vol', this.vol_geom, 0);
+ end
+
+ % parse method
+ method2 = upper(this.method);
+ if strcmp(method2, 'SART') || strcmp(method2, 'SART_CUDA')
+ iterations = iterations * astra_geom_size(this.proj_geom, 1);
+ elseif strcmp(method2, 'ART')
+ s = astra_geom_size(this.proj_geom);
+ iterations = iterations * s(1) * s(2);
+ end
+
+ % algorithm configuration
+ cfg = this.cfg_base;
+ cfg.ProjectionDataId = sinogram;
+ cfg.ReconstructionDataId = V0;
+ if numel(mask) > 0
+ cfg.option.ReconstructionMaskId = mask;
+ end
+ alg_id = astra_mex_algorithm('create', cfg);
+
+ % iterate
+ astra_mex_algorithm('iterate', alg_id, iterations);
+
+ % fetch data
+ V = V0;
+
+ % correct attenuation factors for super-resolution
+ if this.superresolution > 1
+ if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat')
+ if numel(mask) > 0
+ astra_data_op_masked('$1./s1', [V V], [this.superresolution this.superresolution], mask, this.gpu_core);
+ else
+ astra_data_op('$1./s1', [V V], [this.superresolution this.superresolution], this.gpu_core);
+ end
+ end
+ end
+
+ % garbage collection
+ astra_mex_algorithm('delete', alg_id);
+
+ end
+
+ %------------------------------------------------------------------
+ function V_out = selectROI(~, V_in)
+
+ if numel(V_in) == 1
+ cfg = astra_struct('RoiSelect_CUDA');
+ cfg.DataId = V_in;
+ alg_id = astra_mex_algorithm('create',cfg);
+ astra_mex_algorithm('run', alg_id);
+ astra_mex_algorithm('delete', alg_id);
+ V_out = V_in;
+ else
+ V_out = ROIselectfull(V_in, min([size(V_in,1), size(V_in,2)]));
+ end
+
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/IterativeTomography3D.m b/matlab/algorithms/DART/IterativeTomography3D.m
new file mode 100644
index 0000000..3f89457
--- /dev/null
+++ b/matlab/algorithms/DART/IterativeTomography3D.m
@@ -0,0 +1,433 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef IterativeTomography3D < matlab.mixin.Copyable
+
+ % Algorithm class for 3D Iterative Tomography.
+
+ %----------------------------------------------------------------------
+ properties (SetAccess=public, GetAccess=public)
+ superresolution = 1; % SETTING: Volume upsampling factor.
+ proj_type = 'linear'; % SETTING: Projector type, only when gpu='no'.
+ method = 'SIRT3D_CUDA'; % SETTING: Iterative method (see ASTRA toolbox documentation).
+ gpu = 'yes'; % SETTING: Use gpu? {'yes', 'no'}
+ gpu_core = 0; % SETTING: Which gpu core to use? Only when gpu='yes'.
+ inner_circle = 'yes'; % SETTING: Do roi only? {'yes', 'no'}
+ image_size = []; % SETTING: Overwrite default reconstruction size. Only if no vol_geom is specified.
+ use_minc = 'no'; % SETTING: Use minimum constraint. {'no', 'yes'}
+ maxc = +Inf; % SETTING: Maximum constraint. +Inf means off.
+ end
+ %----------------------------------------------------------------------
+ properties (SetAccess=public, GetAccess=public)
+ sinogram = []; % DATA: Projection data.
+ proj_geom = []; % DATA: Projection geometry.
+ V = []; % DATA: Volume data. Also used to set initial estimate (optional).
+ vol_geom = []; % DATA: Volume geometry.
+ end
+ %----------------------------------------------------------------------
+ properties (SetAccess=private, GetAccess=public)
+ initialized = 0; % Is this object initialized?
+ end
+ %----------------------------------------------------------------------
+ properties (SetAccess=protected, GetAccess=protected)
+ proj_geom_sr = []; % PROTECTED: geometry of sinogram (with super-resolution)
+ proj_id = []; % PROTECTED: astra id of projector (when gpu='no')
+ proj_id_sr = []; % PROTECTED: astra id of super-resolution projector (when gpu='no')
+ cfg_base = struct(); % PROTECTED: base configuration structure for the reconstruction algorithm.
+ end
+ %----------------------------------------------------------------------
+
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function this = IterativeTomography(varargin)
+ % Constructor
+ % >> tomography = IterativeTomography();
+ % >> tomography = IterativeTomography(base); base struct should contain fields 'sinogram' and 'proj_geom'.
+ % >> tomography = IterativeTomography(base_filename); mat-file should contain 'sinogram' and 'proj_geom'.
+ % >> tomography = IterativeTomography(proj_geom, vol_geom);
+ % >> tomography = IterativeTomography(sinogram, proj_geom);
+
+ % Input: IterativeTomography(base)
+ if nargin == 1
+ if ischar(varargin{1})
+ this.sinogram = load(varargin{1},'sinogram');
+ this.proj_geom = load(varargin{1},'proj_geom');
+ else
+ this.sinogram = varargin{1}.sinogram;
+ this.proj_geom = varargin{1}.proj_geom;
+ end
+ end
+ % Input: IterativeTomography(proj_geom, vol_geom)
+ if nargin == 2 && isstruct(varargin{1}) && isstruct(varargin{2})
+ this.proj_geom = varargin{1};
+ this.vol_geom = varargin{2};
+ % Input: IterativeTomography(sinogram, proj_geom)
+ elseif nargin == 2
+ this.sinogram = varargin{1};
+ this.proj_geom = varargin{2};
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ function delete(this)
+ % Destructor
+ % >> clear tomography;
+ if strcmp(this.gpu,'no') && numel(this.proj_id) > 0
+ astra_mex_projector('delete', this.proj_id, this.proj_id_sr);
+ end
+ end
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = tomography.getsettings();
+ settings.superresolution = this.superresolution;
+ settings.proj_type = this.proj_type;
+ settings.method = this.method;
+ settings.gpu = this.gpu;
+ settings.gpu_core = this.gpu_core;
+ settings.inner_circle = this.inner_circle;
+ settings.image_size = this.image_size;
+ settings.use_minc = this.use_minc;
+ settings.maxc = this.maxc;
+ end
+
+ %------------------------------------------------------------------
+ function ok = initialize(this)
+ % Initialize this object. Returns 1 if succesful.
+ % >> tomography.initialize();
+
+% % create projection geometry with super-resolution
+% this.proj_geom_sr = astra_geom_superresolution(this.proj_geom, this.superresolution);
+
+ % if no volume geometry is specified by the user: create volume geometry
+ if numel(this.vol_geom) == 0
+ if numel(this.image_size) < 2
+ this.image_size(1) = this.proj_geom.DetectorRowCount;
+ this.image_size(2) = this.proj_geom.DetectorColCount;
+ end
+ this.vol_geom = astra_create_vol_geom(this.proj_geom.DetectorColCount, this.proj_geom.DetectorColCount, this.proj_geom.DetectorRowCount);
+ else
+ this.image_size(1) = this.vol_geom.GridRowCount;
+ this.image_size(2) = this.vol_geom.GridColCount;
+ end
+
+ % create projector
+ if strcmp(this.gpu, 'no')
+ this.proj_id = astra_create_projector(this.proj_type, this.proj_geom, this.vol_geom);
+ this.proj_id_sr = astra_create_projector(this.proj_type, this.proj_geom_sr, this.vol_geom);
+ end
+
+ % create reconstruction configuration
+ this.cfg_base = astra_struct(upper(this.method));
+ if strcmp(this.gpu,'no')
+ this.cfg_base.ProjectorId = this.proj_id;
+ this.cfg_base.ProjectionGeometry = this.proj_geom;
+ this.cfg_base.ReconstructionGeometry = this.vol_geom;
+ this.cfg_base.option.ProjectionOrder = 'random';
+ end
+ this.cfg_base.option.DetectorSuperSampling = this.superresolution;
+ %this.cfg_base.option.DetectorSuperSampling = 8;
+ if strcmp(this.gpu,'yes')
+ this.cfg_base.option.GPUindex = this.gpu_core;
+ end
+ this.cfg_base.option.UseMinConstraint = this.use_minc;
+ if ~isinf(this.maxc)
+ this.cfg_base.option.UseMaxConstraint = 'yes';
+ this.cfg_base.option.MaxConstraintValue = this.maxc;
+ end
+
+ this.initialized = 1;
+ ok = this.initialized;
+ end
+
+ %------------------------------------------------------------------
+ function P = project(this, volume)
+ % Compute forward projection.
+ % Stores sinogram in tomography.sinogram if it is still empty.
+ % >> P = tomography.project(); projects 'tomography.V'.
+ % >> P = tomography.project(volume); projects 'volume'.
+
+ if ~this.initialized
+ this.initialize();
+ end
+
+ if nargin == 1 % tomography.project();
+ P = this.project_c(this.V);
+
+ elseif nargin == 2 % tomography.project(volume);
+ P = this.project_c(volume);
+ end
+
+ % store
+ if numel(this.sinogram) == 0
+ this.sinogram = P;
+ end
+ end
+
+ %------------------------------------------------------------------
+ function V = reconstruct(this, iterations)
+ % Compute reconstruction.
+ % Uses tomography.sinogram
+ % Initial solution (if available) should be stored in tomography.V
+ % >> V = tomography.reconstruct(iterations);
+
+ if ~this.initialized
+ this.initialize();
+ end
+
+ this.V = this.reconstruct_c(this.sinogram, this.V, [], iterations);
+ if strcmp(this.inner_circle,'yes')
+ this.V = this.selectROI(this.V);
+ end
+ V = this.V;
+ end
+
+ %------------------------------------------------------------------
+ function I = reconstructMask(this, mask, iterations)
+ % Compute reconstruction with mask.
+ % Uses tomography.sinogram
+ % Initial solution (if available) should be stored in tomography.V
+ % >> V = tomography.reconstructMask(mask, iterations);
+
+ if ~this.initialized
+ this.initialize();
+ end
+
+ if strcmp(this.inner_circle,'yes')
+ mask = this.selectROI(mask);
+ end
+ I = this.reconstruct_c(this.sinogram, this.V, mask, iterations);
+ end
+ %------------------------------------------------------------------
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access = protected)
+
+ %------------------------------------------------------------------
+ % Protected function: create FP
+ function sinogram = project_c(this, volume)
+
+ if this.initialized == 0
+ error('IterativeTomography not initialized');
+ end
+
+ % data is stored in astra memory
+ if numel(volume) == 1
+
+ if strcmp(this.gpu, 'yes')
+ sinogram_tmp = astra_create_sino_cuda(volume, this.proj_geom_sr, this.vol_geom, this.gpu_core);
+ else
+ sinogram_tmp = astra_create_sino(volume, this.proj_id);
+ end
+
+ % sinogram downsampling
+ if this.superresolution > 1
+ sinogram_data = astra_mex_data2d('get', sinogram_tmp);
+ astra_mex_data2d('delete', sinogram_tmp);
+ sinogram_data = downsample_sinogram(sinogram_data, this.superresolution);
+ %if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat')
+ % sinogram = sinogram / this.superresolution;
+ %end
+ sinogram = astra_mex_data2d('create','sino', this.proj_geom, sinogram_data);
+ else
+ sinogram = sinogram_tmp;
+ end
+
+ % data is stored in matlab memory
+ else
+
+ [tmp_id, sinogram] = astra_create_sino3d_cuda(volume, this.proj_geom, this.vol_geom);
+ astra_mex_data3d('delete', tmp_id);
+
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ % Protected function: reconstruct
+ function V = reconstruct_c(this, sinogram, V0, mask, iterations)
+
+ if this.initialized == 0
+ error('IterativeTomography not initialized');
+ end
+
+ % data is stored in astra memory
+ if numel(sinogram) == 1
+ V = this.reconstruct_c_astra(sinogram, V0, mask, iterations);
+
+ % data is stored in matlab memory
+ else
+ V = this.reconstruct_c_matlab(sinogram, V0, mask, iterations);
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ % Protected function: reconstruct (data in matlab)
+ function V = reconstruct_c_matlab(this, sinogram, V0, mask, iterations)
+
+ if this.initialized == 0
+ error('IterativeTomography not initialized');
+ end
+
+ % parse method
+ method2 = upper(this.method);
+ if strcmp(method2, 'SART') || strcmp(method2, 'SART_CUDA')
+ iterations = iterations * size(sinogram,1);
+ elseif strcmp(method2, 'ART')
+ iterations = iterations * numel(sinogram);
+ end
+
+ % create data objects
+% V = zeros(this.vol_geom.GridRowCount, this.vol_geom.GridColCount, size(sinogram,3));
+ reconstruction_id = astra_mex_data3d('create', '-vol', this.vol_geom);
+ sinogram_id = astra_mex_data3d('create', '-proj3d', this.proj_geom);
+ if numel(mask) > 0
+ mask_id = astra_mex_data3d('create', '-vol', this.vol_geom);
+ end
+
+ % algorithm configuration
+ cfg = this.cfg_base;
+ cfg.ProjectionDataId = sinogram_id;
+ cfg.ReconstructionDataId = reconstruction_id;
+ if numel(mask) > 0
+ cfg.option.ReconstructionMaskId = mask_id;
+ end
+ alg_id = astra_mex_algorithm('create', cfg);
+
+% % loop slices
+% for slice = 1:size(sinogram,3)
+
+ % fetch slice of initial reconstruction
+ if numel(V0) > 0
+ astra_mex_data3d('store', reconstruction_id, V0);
+ else
+ astra_mex_data3d('store', reconstruction_id, 0);
+ end
+
+ % fetch slice of sinogram
+ astra_mex_data3d('store', sinogram_id, sinogram);
+
+ % fecth slice of mask
+ if numel(mask) > 0
+ astra_mex_data3d('store', mask_id, mask);
+ end
+
+ % iterate
+ astra_mex_algorithm('iterate', alg_id, iterations);
+
+ % fetch data
+ V = astra_mex_data3d('get', reconstruction_id);
+
+% end
+
+ % correct attenuation factors for super-resolution
+ if this.superresolution > 1 && strcmp(this.gpu,'yes')
+ if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat')
+ if numel(mask) > 0
+ V(mask > 0) = V(mask > 0) ./ this.superresolution;
+ else
+ V = V ./ this.superresolution;
+ end
+ end
+ end
+
+ % garbage collection
+ astra_mex_algorithm('delete', alg_id);
+ astra_mex_data3d('delete', sinogram_id, reconstruction_id);
+ if numel(mask) > 0
+ astra_mex_data3d('delete', mask_id);
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ % Protected function: reconstruct (data in astra)
+ function V = reconstruct_c_astra(this, sinogram, V0, mask, iterations)
+
+ if this.initialized == 0
+ error('IterativeTomography not initialized');
+ end
+
+ if numel(V0) > 1 || numel(mask) > 1 || numel(sinogram) > 1
+ error('Not all required data is stored in the astra memory');
+ end
+
+ if numel(V0) == 0
+ V0 = astra_mex_data2d('create', '-vol', this.vol_geom, 0);
+ end
+
+ % parse method
+ method2 = upper(this.method);
+ if strcmp(method2, 'SART') || strcmp(method2, 'SART_CUDA')
+ iterations = iterations * astra_geom_size(this.proj_geom, 1);
+ elseif strcmp(method2, 'ART')
+ s = astra_geom_size(this.proj_geom);
+ iterations = iterations * s(1) * s(2);
+ end
+
+ % algorithm configuration
+ cfg = this.cfg_base;
+ cfg.ProjectionDataId = sinogram;
+ cfg.ReconstructionDataId = V0;
+ if numel(mask) > 0
+ cfg.option.ReconstructionMaskId = mask;
+ end
+ alg_id = astra_mex_algorithm('create', cfg);
+
+ % iterate
+ astra_mex_algorithm('iterate', alg_id, iterations);
+
+ % fetch data
+ V = V0;
+
+ % correct attenuation factors for super-resolution
+ if this.superresolution > 1
+ if strcmp(this.proj_geom.type,'fanflat_vec') || strcmp(this.proj_geom.type,'fanflat')
+ if numel(mask) > 0
+ astra_data_op_masked('$1./s1', [V V], [this.superresolution this.superresolution], mask, this.gpu_core);
+ else
+ astra_data_op('$1./s1', [V V], [this.superresolution this.superresolution], this.gpu_core);
+ end
+ end
+ end
+
+ % garbage collection
+ astra_mex_algorithm('delete', alg_id);
+
+ end
+
+ %------------------------------------------------------------------
+ function V_out = selectROI(~, V_in)
+
+ if numel(V_in) == 1
+ cfg = astra_struct('RoiSelect_CUDA');
+ cfg.DataId = V_in;
+ alg_id = astra_mex_algorithm('create',cfg);
+ astra_mex_algorithm('run', alg_id);
+ astra_mex_algorithm('delete', alg_id);
+ V_out = V_in;
+ else
+ V_out = ROIselectfull(V_in, min([size(V_in,1), size(V_in,2)]));
+ end
+
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/Kernels.m b/matlab/algorithms/DART/Kernels.m
new file mode 100644
index 0000000..b5e3134
--- /dev/null
+++ b/matlab/algorithms/DART/Kernels.m
@@ -0,0 +1,68 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef Kernels
+ %KERNELS Summary of this class goes here
+ % Detailed explanation goes here
+
+ properties
+
+ end
+
+ methods(Static)
+
+ function K = BinaryPixelKernel(radius, conn)
+
+ if nargin < 2
+ conn = 8;
+ end
+
+ % 2D, 4conn
+ if conn == 4
+ K = [0 1 0; 1 1 1; 0 1 0];
+ for i = 2:radius
+ K = conv2(K,K);
+ end
+ K = double(K >= 1);
+
+ % 2D, 8conn
+ elseif conn == 8
+ K = ones(2*radius+1, 2*radius+1);
+
+ % 3D, 6conn
+ elseif conn == 6
+ K = zeros(3,3,3);
+ K(:,:,1) = [0 0 0; 0 1 0; 0 0 0];
+ K(:,:,2) = [0 1 0; 1 1 1; 0 1 0];
+ K(:,:,3) = [0 0 0; 0 1 0; 0 0 0];
+ for i = 2:radius
+ K = convn(K,K);
+ end
+ K = double(K >= 1);
+
+ % 2D, 27conn
+ elseif conn == 26
+ K = ones(2*radius+1, 2*radius+1, 2*radius+1);
+
+ else
+ disp('Invalid conn')
+ end
+ end
+
+
+
+
+
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/MaskingDefault.m b/matlab/algorithms/DART/MaskingDefault.m
new file mode 100644
index 0000000..6bd25a5
--- /dev/null
+++ b/matlab/algorithms/DART/MaskingDefault.m
@@ -0,0 +1,212 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef MaskingDefault < matlab.mixin.Copyable
+
+ % Default policy class for masking for DART.
+
+ %----------------------------------------------------------------------
+ properties (Access=public)
+
+ radius = 1; % SETTING: Radius of masking kernel.
+ conn = 8; % SETTING: Connectivity window. For 2D: 4 or 8. For 3D: 6 or 26.
+ edge_threshold = 1; % SETTING: Number of pixels in the window that should be different.
+ random = 0.1; % SETTING: Percentage of random points. Between 0 and 1.
+ gpu = 'yes'; % SETTING: Use gpu? {'yes', 'no'}
+ gpu_core = 0; % SETTING: Which gpu core to use, only when gpu='yes'.
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = DART.masking.getsettings();
+ settings.radius = this.radius;
+ settings.conn = this.conn;
+ settings.edge_threshold = this.edge_threshold;
+ settings.random = this.random;
+ end
+
+ %------------------------------------------------------------------
+ function Mask = apply(this, ~, S)
+ % Applies masking.
+ % >> Mask = DART.segmentation.apply(DART, S);
+
+ % 2D, one slice
+ if size(S,3) == 1
+ if strcmp(this.gpu,'yes')
+ Mask = this.apply_2D_gpu(S);
+ else
+ Mask = this.apply_2D(S);
+ end
+
+ % 3D, slice by slice
+ elseif this.conn == 4 || this.conn == 8
+ Mask = zeros(size(S));
+ for slice = 1:size(S,3)
+ if strcmp(this.gpu,'yes')
+ Mask(:,:,slice) = this.apply_2D_gpu(S(:,:,slice));
+ else
+ Mask(:,:,slice) = this.apply_2D(S(:,:,slice));
+ end
+ end
+
+ % 3D, full
+ else
+ if strcmp(this.gpu,'yes')
+ Mask = this.apply_3D_gpu(S);
+ else
+ Mask = this.apply_3D(S);
+ end
+ end
+
+ end
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access=protected)
+
+ %------------------------------------------------------------------
+ function Mask = apply_2D_gpu(this, S)
+
+ vol_geom = astra_create_vol_geom(size(S));
+ data_id = astra_mex_data2d('create', '-vol', vol_geom, S);
+ mask_id = astra_mex_data2d('create', '-vol', vol_geom, 0);
+
+ cfg = astra_struct('DARTMASK_CUDA');
+ cfg.SegmentationDataId = data_id;
+ cfg.MaskDataId = mask_id;
+ cfg.option.GPUindex = this.gpu_core;
+ cfg.option.Connectivity = this.conn;
+ cfg.option.Threshold = this.edge_threshold;
+ cfg.option.Radius = this.radius;
+
+ alg_id = astra_mex_algorithm('create',cfg);
+ astra_mex_algorithm('iterate',alg_id,1);
+ Mask = astra_mex_data2d('get', mask_id);
+
+ astra_mex_algorithm('delete', alg_id);
+ astra_mex_data2d('delete', data_id, mask_id);
+
+ % random
+ RandomField = double(rand(size(S)) < this.random);
+
+ % combine
+ Mask = or(Mask, RandomField);
+
+ end
+
+ %------------------------------------------------------------------
+ function Mask = apply_2D(this, S)
+
+ r = this.radius;
+ w = 2 * r + 1;
+
+ kernel = Kernels.BinaryPixelKernel(r, this.conn);
+
+ % edges
+ Xlarge = zeros(size(S,1)+w-1, size(S,2)+w-1);
+ Xlarge(1+r:end-r, 1+r:end-r) = S;
+
+ Edges = zeros(size(S));
+ for s = -r:r
+ for t = -r:r
+ if kernel(s+r+1, t+r+1) == 0
+ continue
+ end
+ Temp = abs(Xlarge(1+r:end-r, 1+r:end-r) - Xlarge(1+r+s:end-r+s, 1+r+t:end-r+t));
+ Edges(Temp > eps) = Edges(Temp > eps) + 1;
+ end
+ end
+
+ Edges = Edges > this.edge_threshold;
+
+ % random
+ RandomField = double(rand(size(S)) < this.random);
+
+ % combine
+ Mask = or(Edges, RandomField);
+
+ end
+
+ %------------------------------------------------------------------
+ function Mask = apply_3D(this, S)
+
+ r = this.radius;
+ w = 2 * r + 1;
+
+ kernel = Kernels.BinaryPixelKernel(r, this.conn);
+
+ % edges
+ Xlarge = zeros(size(S,1)+w-1, size(S,2)+w-1, size(S,3)+w-1);
+ Xlarge(1+r:end-r, 1+r:end-r, 1+r:end-r) = S;
+
+ Edges = zeros(size(S));
+ for s = -r:r
+ for t = -r:r
+ for u = -r:r
+ if kernel(s+r+1, t+r+1, u+r+1) == 0
+ continue
+ end
+ Temp = abs(Xlarge(1+r:end-r, 1+r:end-r, 1+r:end-r) - Xlarge(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u));
+ Edges(Temp > eps) = 1;
+ end
+ end
+ end
+
+ clear Xlarge;
+
+ % random
+ RandomField = double(rand(size(S)) < this.random);
+
+ % combine
+ Mask = or(Edges, RandomField);
+
+ end
+
+ %------------------------------------------------------------------
+ function Mask = apply_3D_gpu(this, S)
+
+ vol_geom = astra_create_vol_geom(size(S));
+ data_id = astra_mex_data3d('create', '-vol', vol_geom, S);
+
+ cfg = astra_struct('DARTMASK3D_CUDA');
+ cfg.SegmentationDataId = data_id;
+ cfg.MaskDataId = data_id;
+ cfg.option.GPUindex = this.gpu_core;
+ cfg.option.Connectivity = this.conn;
+ cfg.option.Threshold = this.edge_threshold;
+ cfg.option.Radius = this.radius;
+
+ alg_id = astra_mex_algorithm('create',cfg);
+ astra_mex_algorithm('iterate',alg_id,1);
+ Mask = astra_mex_data3d('get', data_id);
+
+ astra_mex_algorithm('delete', alg_id);
+ astra_mex_data3d('delete', data_id);
+
+ % random
+ RandomField = double(rand(size(S)) < this.random);
+
+ % combine
+ Mask = or(Mask, RandomField);
+
+ end
+
+ %------------------------------------------------------------------
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/MaskingGPU.m b/matlab/algorithms/DART/MaskingGPU.m
new file mode 100644
index 0000000..c4ef2b7
--- /dev/null
+++ b/matlab/algorithms/DART/MaskingGPU.m
@@ -0,0 +1,94 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef MaskingGPU < matlab.mixin.Copyable
+
+ % Policy class for masking for DART with GPU accelerated code (deprecated).
+
+ %----------------------------------------------------------------------
+ properties (Access=public)
+
+ radius = 1; % SETTING: Radius of masking kernel.
+ conn = 8; % SETTING: Connectivity window. For 2D: 4 or 8. For 3D: 6 or 26.
+ edge_threshold = 1; % SETTING: Number of pixels in the window that should be different.
+ gpu_core = 0; % SETTING:
+ random = 0.1; % SETTING: Percentage of random points. Between 0 and 1.
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = DART.masking.getsettings();
+ settings.radius = this.radius;
+ settings.conn = this.conn;
+ settings.edge_threshold = this.edge_threshold;
+ settings.random = this.random;
+ end
+
+ %------------------------------------------------------------------
+ function Mask = apply(this, ~, V_in)
+ % Applies masking.
+ % >> Mask = DART.segmentation.apply(DART, V_in);
+
+ % 2D, one slice
+ if size(V_in,3) == 1
+ Mask = this.apply_2D(V_in);
+
+ % 3D, slice by slice
+ elseif this.conn == 4 || this.conn == 8
+ Mask = zeros(size(V_in));
+ for slice = 1:size(V_in,3)
+ Mask(:,:,slice) = this.apply_2D(V_in(:,:,slice));
+ end
+
+ % 3D, full
+ else
+ error('Full 3D masking on GPU not implemented.')
+ end
+
+ end
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access=protected)
+
+ %------------------------------------------------------------------
+ function Mask = apply_2D(this, S)
+
+ vol_geom = astra_create_vol_geom(size(S));
+ data_id = astra_mex_data2d('create', '-vol', vol_geom, S);
+ mask_id = astra_mex_data2d('create', '-vol', vol_geom, 0);
+
+ cfg = astra_struct('DARTMASK_CUDA');
+ cfg.SegmentationDataId = data_id;
+ cfg.MaskDataId = mask_id;
+ cfg.option.GPUindex = this.gpu_core;
+ %cfg.option.Connectivity = this.conn;
+
+ alg_id = astra_mex_algorithm('create',cfg);
+ astra_mex_algorithm('iterate',alg_id,1);
+ Mask = astra_mex_data2d('get', mask_id);
+
+ astra_mex_algorithm('delete', alg_id);
+ astra_mex_data2d('delete', data_id, mask_id);
+
+ end
+ end
+
+
+
+end
+
diff --git a/matlab/algorithms/DART/OutputDefault.m b/matlab/algorithms/DART/OutputDefault.m
new file mode 100644
index 0000000..a34a430
--- /dev/null
+++ b/matlab/algorithms/DART/OutputDefault.m
@@ -0,0 +1,173 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef OutputDefault < matlab.mixin.Copyable
+
+ % Default policy class for output for DART.
+
+ properties (Access=public)
+
+ directory = ''; % SETTING: Directory to save output.
+ pre = ''; % SETTING: Prefix of output.
+
+ save_images = 'no'; % SETTING: Save the images. 'no', 'yes' (='S') OR {'S', 'I', 'Mask', 'P'}
+ save_results = 'no'; % SETTING: Save the results. 'yes', 'no' OR {'base', 'stats', 'settings', 'S', 'V', 'V0'}
+ save_object = 'no'; % SETTING: Save the DART object. {'no','yes'}
+
+ save_interval = 1; % SETTING: # DART iteration between saves.
+ save_images_interval = []; % SETTING: Overwrite interval for save_images.
+ save_results_interval = []; % SETTING: Overwrite interval for save_results.
+ save_object_interval = []; % SETTING: Overwrite interval for save_object.
+
+ slices = 1; % SETTING: In case of 3D, which slices to save?
+
+ verbose = 'no'; % SETTING: Verbose? {'no','yes'}
+
+ end
+
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function pre_initial_iteration(this, ~)
+ if strcmp(this.verbose,'yes')
+ tic
+ fprintf(1, 'initial iteration...');
+ end
+ end
+
+ %------------------------------------------------------------------
+ function post_initial_iteration(this, ~)
+ if strcmp(this.verbose,'yes')
+ t = toc;
+ fprintf(1, 'done in %f s.\n', t);
+ end
+ end
+
+ %------------------------------------------------------------------
+ function pre_iteration(this, DART)
+ if strcmp(this.verbose,'yes')
+ tic;
+ fprintf(1, '%s dart iteration %d...', this.pre, DART.iterationcount);
+ end
+ end
+
+ %------------------------------------------------------------------
+ function post_iteration(this, DART)
+
+ % print output
+ if strcmp(this.verbose,'yes')
+ t = toc;
+ s = DART.statistics.tostring(DART.stats);
+ fprintf(1, 'done in %0.2fs %s.\n', t, s);
+ end
+
+ % save DART object
+ if do_object(this, DART)
+ save(sprintf('%s%sobject_%i.mat', this.directory, this.pre, DART.iterationcount), '-v7.3', 'DART');
+ end
+
+ % save .mat
+ if do_results(this, DART)
+ base = DART.base;
+ stats = DART.stats;
+ S = DART.S;
+ V = DART.V;
+ V0 = DART.V0;
+ settings = DART.getsettings();
+ if ~iscell(this.save_results)
+ save(sprintf('%s%sresults_%i.mat', this.directory, this.pre, DART.iterationcount), '-v7.3', 'base', 'stats', 'S', 'V', 'V0', 'settings');
+ else
+ string = [];
+ for i = 1:numel(this.save_results)
+ string = [string this.save_results{i} '|'];
+ end
+ save(sprintf('%s%sresults_%i.mat', this.directory, this.pre, DART.iterationcount), '-v7.3', '-regexp', string(1:end-1));
+ end
+ end
+
+ % save images
+ if do_images(this, DART)
+
+ if ~iscell(this.save_images) && strcmp(this.save_images, 'yes')
+ output_image(this, DART, 'S')
+ elseif iscell(this.save_images)
+ for i = 1:numel(this.save_images)
+ output_image(this, DART, this.save_images{i});
+ end
+ end
+
+ end
+
+ end
+ %------------------------------------------------------------------
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access=private)
+
+ function output_image(this, DART, data)
+ % 2D
+ if numel(size(DART.S)) == 2
+ eval(['imwritesc(DART.' data ', sprintf(''%s%s' data '_%i.png'', this.directory, this.pre, DART.iterationcount))']);
+ % 3D
+ elseif numel(size(DART.S)) == 3
+ for slice = this.slices
+ eval(['imwritesc(DART.' data '(:,:,slice), sprintf(''%s%s' data '_%i_slice%i.png'', this.directory, this.pre, DART.iterationcount, slice))']);
+ end
+ end
+ end
+
+ %------------------------------------------------------------------
+ function out = do_object(this, DART)
+ if strcmp(this.save_object,'no')
+ out = 0;
+ return
+ end
+ if numel(this.save_object_interval) == 0 && mod(DART.iterationcount, this.save_interval) == 0
+ out = 1;
+ elseif mod(DART.iterationcount, this.save_object_interval) == 0
+ out = 1;
+ else
+ out = 0;
+ end
+ end
+ %------------------------------------------------------------------
+ function out = do_results(this, DART)
+ if strcmp(this.save_results,'no')
+ out = 0;
+ return
+ end
+ if numel(this.save_results_interval) == 0 && mod(DART.iterationcount, this.save_interval) == 0
+ out = 1;
+ elseif mod(DART.iterationcount, this.save_results_interval) == 0
+ out = 1;
+ else
+ out = 0;
+ end
+ end
+
+ %------------------------------------------------------------------
+ function out = do_images(this, DART)
+ if numel(this.save_images_interval) == 0 && mod(DART.iterationcount, this.save_interval) == 0
+ out = 1;
+ elseif mod(DART.iterationcount, this.save_images_interval) == 0
+ out = 1;
+ else
+ out = 0;
+ end
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/SegmentationDefault.m b/matlab/algorithms/DART/SegmentationDefault.m
new file mode 100644
index 0000000..c1d7d99
--- /dev/null
+++ b/matlab/algorithms/DART/SegmentationDefault.m
@@ -0,0 +1,55 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef SegmentationDefault < matlab.mixin.Copyable
+
+ % Default policy class for segmentation for DART.
+
+ %----------------------------------------------------------------------
+ properties (Access=public)
+ rho = []; % SETTING: Grey levels.
+ tau = []; % SETTING: Threshold values.
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = DART.segmentation.getsettings();
+ settings.rho = this.rho;
+ settings.tau = this.tau;
+ end
+
+ %------------------------------------------------------------------
+ function this = estimate_grey_levels(this, ~, ~)
+ % Estimates grey levels
+ % >> DART.segmentation.estimate_grey_levels();
+ end
+
+ %------------------------------------------------------------------
+ function V_out = apply(this, ~, V_in)
+ % Applies segmentation.
+ % >> V_out = DART.segmentation.apply(DART, V_in);
+
+ V_out = ones(size(V_in)) * this.rho(1);
+ for n = 2:length(this.rho)
+ V_out(this.tau(n-1) < V_in) = this.rho(n);
+ end
+
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/SmoothingDefault.m b/matlab/algorithms/DART/SmoothingDefault.m
new file mode 100644
index 0000000..58a8baa
--- /dev/null
+++ b/matlab/algorithms/DART/SmoothingDefault.m
@@ -0,0 +1,179 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef SmoothingDefault < matlab.mixin.Copyable
+
+ % Default policy class for smoothing for DART.
+
+ %----------------------------------------------------------------------
+ properties (Access=public)
+ radius = 1; % SETTING: Radius of smoothing kernel.
+ b = 0.1; % SETTING: Intensity of smoothing. Between 0 and 1.
+ full3d = 'yes'; % SETTING: smooth in 3D? {'yes','no'}
+ gpu = 'yes'; % SETTING: Use gpu? {'yes', 'no'}
+ gpu_core = 0; % SETTING: Which gpu core to use, only when gpu='yes'.
+ end
+
+
+ %----------------------------------------------------------------------
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = DART.smoothing.getsettings();
+ settings.radius = this.radius;
+ settings.b = this.b;
+ settings.full3d = this.full3d;
+ end
+
+ %------------------------------------------------------------------
+ function V_out = apply(this, ~, V_in)
+ % Applies smoothing.
+ % >> V_out = DART.smoothing.apply(DART, V_in);
+
+ % 2D, one slice
+ if size(V_in,3) == 1
+ if strcmp(this.gpu,'yes')
+ V_out = this.apply_2D_gpu(V_in);
+ else
+ V_out = this.apply_2D(V_in);
+ end
+
+ % 3D, slice by slice
+ elseif ~strcmp(this.full3d,'yes')
+ V_out = zeros(size(V_in));
+ for slice = 1:size(V_in,3)
+ if strcmp(this.gpu,'yes')
+ V_out(:,:,slice) = this.apply_2D_gpu(V_in(:,:,slice));
+ else
+ V_out(:,:,slice) = this.apply_2D(V_in(:,:,slice));
+ end
+ end
+
+ % 3D, full
+ else
+ if strcmp(this.gpu,'yes')
+ V_out = this.apply_3D_gpu(V_in);
+ else
+ V_out = this.apply_3D(V_in);
+ end
+ end
+
+ end
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access=protected)
+
+ %------------------------------------------------------------------
+ function V_out = apply_2D(this, V_in)
+
+ r = this.radius;
+ w = 2 * r + 1;
+
+ % Set Kernel
+ K = ones(w) * this.b / (w.^2-1); % edges
+ K(r+1,r+1) = 1 - this.b; % center
+
+ % output window
+ V_out = zeros(size(V_in,1) + w-1, size(V_in,2) + w - 1);
+
+ % blur convolution
+ for s = -r:r
+ for t = -r:r
+ V_out(1+r+s:end-r+s, 1+r+t:end-r+t) = V_out(1+r+s:end-r+s, 1+r+t:end-r+t) + K(r+1+s, r+1+t) * V_in;
+ end
+ end
+
+ % shrink output window
+ V_out = V_out(1+r:end-r, 1+r:end-r);
+
+ end
+
+ %------------------------------------------------------------------
+ function V_out = apply_2D_gpu(this, V_in)
+
+ vol_geom = astra_create_vol_geom(size(V_in));
+ in_id = astra_mex_data2d('create', '-vol', vol_geom, V_in);
+ out_id = astra_mex_data2d('create', '-vol', vol_geom, 0);
+
+ cfg = astra_struct('DARTSMOOTHING_CUDA');
+ cfg.InDataId = in_id;
+ cfg.OutDataId = out_id;
+ cfg.option.Intensity = this.b;
+ cfg.option.Radius = this.radius;
+ cfg.option.GPUindex = this.gpu_core;
+
+ alg_id = astra_mex_algorithm('create',cfg);
+ astra_mex_algorithm('iterate',alg_id,1);
+ V_out = astra_mex_data2d('get', out_id);
+
+ astra_mex_algorithm('delete', alg_id);
+ astra_mex_data2d('delete', in_id, out_id);
+
+ end
+
+ %------------------------------------------------------------------
+ function I_out = apply_3D(this, I_in)
+
+ r = this.radius;
+ w = 2 * r + 1;
+
+ % Set Kernel
+ K = ones(w,w,w) * this.b / (w.^3-1); % edges
+ K(r+1,r+1,r+1) = 1 - this.b; % center
+
+ % output window
+ I_out = zeros(size(I_in,1)+w-1, size(I_in,2)+w-1, size(I_in,3)+w-1);
+
+ % blur convolution
+ for s = -r:r
+ for t = -r:r
+ for u = -r:r
+ I_out(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u) = I_out(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u) + K(r+1+s, r+1+t, r+1+u) * I_in;
+ end
+ end
+ end
+
+ % shrink output window
+ I_out = I_out(1+r:end-r, 1+r:end-r, 1+r:end-r);
+
+ end
+
+ %------------------------------------------------------------------
+ function V_out = apply_3D_gpu(this, V_in)
+
+ vol_geom = astra_create_vol_geom(size(V_in));
+ data_id = astra_mex_data3d('create', '-vol', vol_geom, V_in);
+
+ cfg = astra_struct('DARTSMOOTHING3D_CUDA');
+ cfg.InDataId = data_id;
+ cfg.OutDataId = data_id;
+ cfg.option.Intensity = this.b;
+ cfg.option.Radius = this.radius;
+ cfg.option.GPUindex = this.gpu_core;
+
+ alg_id = astra_mex_algorithm('create',cfg);
+ astra_mex_algorithm('iterate', alg_id, 1);
+ V_out = astra_mex_data3d('get', data_id);
+
+ astra_mex_algorithm('delete', alg_id);
+ astra_mex_data3d('delete', data_id);
+
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/SmoothingGPU.m b/matlab/algorithms/DART/SmoothingGPU.m
new file mode 100644
index 0000000..857da37
--- /dev/null
+++ b/matlab/algorithms/DART/SmoothingGPU.m
@@ -0,0 +1,119 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef SmoothingGPU < matlab.mixin.Copyable
+
+ % Default policy class for smoothing for DART.
+
+ %----------------------------------------------------------------------
+ properties (Access=public)
+ radius = 1; % SETTING: Radius of smoothing kernel.
+ b = 0.1; % SETTING: Intensity of smoothing. Between 0 and 1.
+ full3d = 'yes'; % SETTING: smooth in 3D? {'yes','no'}
+ gpu_core = 0; % SETTING:
+ end
+
+
+ %----------------------------------------------------------------------
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = DART.smoothing.getsettings();
+ settings.radius = this.radius;
+ settings.b = this.b;
+ settings.full3d = this.full3d;
+ end
+
+ %------------------------------------------------------------------
+ function V_out = apply(this, ~, V_in)
+ % Applies smoothing.
+ % >> V_out = DART.smoothing.apply(DART, V_in);
+
+ % 2D, one slice
+ if size(V_in,3) == 1
+ V_out = this.apply_2D(V_in);
+
+ % 3D, slice by slice
+ elseif ~strcmp(this.full3d,'yes')
+ V_out = zeros(size(V_in));
+ for slice = 1:size(V_in,3)
+ V_out(:,:,slice) = this.apply_2D(V_in(:,:,slice));
+ end
+
+ % 3D, full
+ else
+ V_out = this.apply_3D(V_in);
+ end
+
+ end
+
+ end
+
+ %----------------------------------------------------------------------
+ methods (Access=protected)
+
+ %------------------------------------------------------------------
+ function V_out = apply_2D(this, V_in)
+
+ vol_geom = astra_create_vol_geom(size(V_in));
+ in_id = astra_mex_data2d('create', '-vol', vol_geom, V_in);
+ out_id = astra_mex_data2d('create', '-vol', vol_geom, 0);
+
+ cfg = astra_struct('DARTSMOOTHING_CUDA');
+ cfg.InDataId = in_id;
+ cfg.OutDataId = out_id;
+ cfg.Intensity = this.b;
+ cfg.option.GPUindex = this.gpu_core;
+
+ alg_id = astra_mex_algorithm('create',cfg);
+ astra_mex_algorithm('iterate',alg_id,1);
+ V_out = astra_mex_data2d('get', out_id);
+
+ astra_mex_algorithm('delete', alg_id);
+ astra_mex_data2d('delete', in_id, out_id);
+
+
+ end
+
+ %------------------------------------------------------------------
+ function I_out = apply_3D(this, I_in)
+
+ r = this.radius;
+ w = 2 * r + 1;
+
+ % Set Kernel
+ K = ones(w,w,w) * this.b / (w.^3-1); % edges
+ K(r+1,r+1,r+1) = 1 - this.b; % center
+
+ % output window
+ I_out = zeros(size(I_in,1)+w-1, size(I_in,2)+w-1, size(I_in,3)+w-1);
+
+ % blur convolution
+ for s = -r:r
+ for t = -r:r
+ for u = -r:r
+ I_out(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u) = I_out(1+r+s:end-r+s, 1+r+t:end-r+t, 1+r+u:end-r+u) + K(r+1+s, r+1+t, r+1+u) * I_in;
+ end
+ end
+ end
+
+ % shrink output window
+ I_out = I_out(1+r:end-r, 1+r:end-r, 1+r:end-r);
+
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/StatisticsDefault.m b/matlab/algorithms/DART/StatisticsDefault.m
new file mode 100644
index 0000000..7822c5f
--- /dev/null
+++ b/matlab/algorithms/DART/StatisticsDefault.m
@@ -0,0 +1,72 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef StatisticsDefault < matlab.mixin.Copyable
+
+ % Default policy class for statistics for DART.
+
+ properties (Access=public)
+ pixel_error = 'yes'; % SETTING: Store pixel error? {'yes','no'}
+ proj_diff = 'yes'; % SETTING: Store projection difference? {'yes','no'}
+ timing = 'yes'; % SETTING: Store timings? {'yes','no'}
+ end
+
+
+ methods (Access=public)
+
+ %------------------------------------------------------------------
+ function stats = apply(this, DART)
+ % Applies statistics.
+ % >> stats = DART.statistics.apply(DART);
+
+ stats = DART.stats;
+
+ % timing
+ if strcmp(this.timing, 'yes')
+ stats.timing(DART.iterationcount) = toc(DART.start_tic);
+ end
+
+ % pixel error
+ if strcmp(this.pixel_error, 'yes') && isfield(DART.base,'phantom')
+ [stats.rnmp, stats.nmp] = compute_rnmp(DART.base.phantom, DART.S);
+ stats.rnmp_hist(DART.iterationcount) = stats.rnmp;
+ stats.nmp_hist(DART.iterationcount) = stats.nmp;
+ end
+
+ % projection difference
+ if strcmp(this.proj_diff, 'yes')
+ new_sino = DART.tomography.createForwardProjection(DART, DART.S);
+ stats.proj_diff = sum((new_sino(:) - DART.base.sinogram(:)) .^2 ) ./ (sum(DART.base.sinogram(:)) );
+ stats.proj_diff_hist(DART.iterationcount) = stats.proj_diff;
+ end
+
+ end
+
+ %------------------------------------------------------------------
+ function s = tostring(~, stats)
+ % To string.
+ % >> stats = DART.statistics.apply(stats);
+
+ s = '';
+ if isfield(stats, 'nmp')
+ s = sprintf('%s [%d]', s, stats.nmp);
+ end
+ if isfield(stats, 'proj_diff')
+ s = sprintf('%s {%0.2d}', s, stats.proj_diff);
+ end
+
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/TomographyDefault.m b/matlab/algorithms/DART/TomographyDefault.m
new file mode 100644
index 0000000..4db3905
--- /dev/null
+++ b/matlab/algorithms/DART/TomographyDefault.m
@@ -0,0 +1,73 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef TomographyDefault < IterativeTomography
+
+ % Policy class for tomography for DART.
+
+ %----------------------------------------------------------------------
+ properties (Access=public)
+ t = 5; % SETTING: # ARMiterations, each DART iteration.
+ t0 = 100; % SETTING: # ARM iterations at DART initialization.
+ end
+ %----------------------------------------------------------------------
+
+ methods
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = DART.tomography.getsettings();
+% settings = getsettings@IterativeTomography();
+ settings.t = this.t;
+ settings.t0 = this.t0;
+ end
+
+ %------------------------------------------------------------------
+ function initialize(this, DART)
+ % Initializes this object.
+ % >> DART.tomography.initialize();
+ this.proj_geom = DART.base.proj_geom;
+ this.initialize@IterativeTomography();
+ end
+
+ %------------------------------------------------------------------
+ function P = createForwardProjection(this, ~, volume)
+ % Compute forward projection.
+ % >> DART.tomography.createForwardProjection(DART, volume);
+ P = this.project_c(volume);
+ end
+
+ %------------------------------------------------------------------
+ function I = createReconstruction(this, ~, sinogram, V0, mask)
+ % Compute reconstruction (with mask).
+ % >> DART.tomography.createReconstruction(DART, sinogram, V0, mask);
+ if strcmp(this.inner_circle,'yes')
+ mask = ROIselectfull(mask, size(mask,1));
+ end
+ I = this.reconstruct_c(sinogram, V0, mask, this.t);
+ end
+
+ %------------------------------------------------------------------
+ function I = createInitialReconstruction(this, ~, sinogram)
+ % Compute reconstruction (initial).
+ % >> DART.tomography.createInitialReconstruction(DART, sinogram);
+ I = this.reconstruct_c(sinogram, [], [], this.t0);
+ if strcmp(this.inner_circle,'yes')
+ I = ROIselectfull(I, size(I,1));
+ end
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/TomographyDefault3D.m b/matlab/algorithms/DART/TomographyDefault3D.m
new file mode 100644
index 0000000..2be1b17
--- /dev/null
+++ b/matlab/algorithms/DART/TomographyDefault3D.m
@@ -0,0 +1,73 @@
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%
+% Author of this DART Algorithm: Wim van Aarle
+
+
+classdef TomographyDefault3D < IterativeTomography3D
+
+ % Policy class for 3D tomography for DART.
+
+ %----------------------------------------------------------------------
+ properties (Access=public)
+ t = 5; % SETTING: # ARMiterations, each DART iteration.
+ t0 = 100; % SETTING: # ARM iterations at DART initialization.
+ end
+ %----------------------------------------------------------------------
+
+ methods
+
+ %------------------------------------------------------------------
+ function settings = getsettings(this)
+ % Returns a structure containing all settings of this object.
+ % >> settings = DART.tomography.getsettings();
+% settings = getsettings@IterativeTomography();
+ settings.t = this.t;
+ settings.t0 = this.t0;
+ end
+
+ %------------------------------------------------------------------
+ function initialize(this, DART)
+ % Initializes this object.
+ % >> DART.tomography.initialize();
+ this.proj_geom = DART.base.proj_geom;
+ this.initialize@IterativeTomography3D();
+ end
+
+ %------------------------------------------------------------------
+ function P = createForwardProjection(this, ~, volume)
+ % Compute forward projection.
+ % >> DART.tomography.createForwardProjection(DART, volume);
+ P = this.project_c(volume);
+ end
+
+ %------------------------------------------------------------------
+ function I = createReconstruction(this, ~, sinogram, V0, mask)
+ % Compute reconstruction (with mask).
+ % >> DART.tomography.createReconstruction(DART, sinogram, V0, mask);
+ if strcmp(this.inner_circle,'yes')
+ mask = ROIselectfull(mask, size(mask,1));
+ end
+ I = this.reconstruct_c(sinogram, V0, mask, this.t);
+ end
+
+ %------------------------------------------------------------------
+ function I = createInitialReconstruction(this, ~, sinogram)
+ % Compute reconstruction (initial).
+ % >> DART.tomography.createInitialReconstruction(DART, sinogram);
+ I = this.reconstruct_c(sinogram, [], [], this.t0);
+ if strcmp(this.inner_circle,'yes')
+ I = ROIselectfull(I, size(I,1));
+ end
+ end
+ %------------------------------------------------------------------
+
+ end
+
+end
+
diff --git a/matlab/algorithms/DART/examples/cylinders.png b/matlab/algorithms/DART/examples/cylinders.png
new file mode 100644
index 0000000..8d1c0b2
--- /dev/null
+++ b/matlab/algorithms/DART/examples/cylinders.png
Binary files differ
diff --git a/matlab/algorithms/DART/examples/example1.m b/matlab/algorithms/DART/examples/example1.m
new file mode 100644
index 0000000..daa3ce8
--- /dev/null
+++ b/matlab/algorithms/DART/examples/example1.m
@@ -0,0 +1,79 @@
+clear all;
+
+addpath('..');
+
+%
+% Example 1: parallel beam, three slices.
+%
+
+% Configuration
+proj_count = 20;
+slice_count = 3;
+dart_iterations = 20;
+filename = 'cylinders.png';
+outdir = './';
+prefix = 'example1';
+rho = [0, 1];
+tau = 0.5;
+gpu_core = 0;
+
+% Load phantom.
+I = double(imread(filename)) / 255;
+
+% Create projection and volume geometries.
+det_count = size(I, 1);
+angles = linspace(0, pi - pi / proj_count, proj_count);
+proj_geom = astra_create_proj_geom('parallel3d', 1, 1, slice_count, det_count, angles);
+vol_geom = astra_create_vol_geom(det_count, det_count, 1);
+
+% Create sinogram.
+[sinogram_id, sinogram] = astra_create_sino3d_cuda(I, proj_geom, vol_geom);
+astra_mex_data3d('delete', sinogram_id);
+
+%
+% DART
+%
+
+base.sinogram = sinogram;
+base.proj_geom = proj_geom;
+
+D = DARTalgorithm(base);
+
+D.tomography = TomographyDefault3D();
+D.tomography.t0 = 100;
+D.tomography.t = 10;
+D.tomography.method = 'SIRT3D_CUDA';
+D.tomography.gpu_core = gpu_core;
+D.tomography.use_minc = 'yes';
+% D.tomography.maxc = 0.003; % Not a sensible value, just for demonstration.
+
+D.segmentation.rho = rho;
+D.segmentation.tau = tau;
+
+D.smoothing.b = 0.1;
+D.smoothing.full3d = 'yes';
+D.smoothing.gpu_core = gpu_core;
+
+D.masking.random = 0.1;
+D.masking.conn = 6;
+D.masking.gpu_core = gpu_core;
+
+D.output.directory = outdir;
+D.output.pre = [prefix '_'];
+D.output.save_images = 'no';
+D.output.save_results = {'stats', 'settings', 'S', 'V'};
+D.output.save_interval = dart_iterations;
+D.output.verbose = 'yes';
+
+D.statistics.proj_diff = 'no';
+
+D.initialize();
+
+disp([D.output.directory D.output.pre]);
+
+D.iterate(dart_iterations);
+
+% Convert middle slice of final iteration to png.
+load([outdir '/' prefix '_results_' num2str(dart_iterations) '.mat']);
+imwritesc(D.S(:, :, round(slice_count / 2)), [outdir '/' prefix '_slice_2_S.png']);
+imwritesc(D.V(:, :, round(slice_count / 2)), [outdir '/' prefix '_slice_2_V.png']);
diff --git a/matlab/algorithms/DART/examples/example2.m b/matlab/algorithms/DART/examples/example2.m
new file mode 100644
index 0000000..8ee8cba
--- /dev/null
+++ b/matlab/algorithms/DART/examples/example2.m
@@ -0,0 +1,80 @@
+clear all;
+
+addpath('..');
+
+%
+% Example 2: cone beam, full cube.
+%
+
+% Configuration
+det_count = 128;
+proj_count = 45;
+slice_count = det_count;
+dart_iterations = 20;
+outdir = './';
+prefix = 'example2';
+rho = [0 0.5 1];
+tau = [0.25 0.75];
+gpu_core = 0;
+
+% Create phantom.
+% I = phantom3d([1 0.9 0.9 0.9 0 0 0 0 0 0; -0.5 0.8 0.8 0.8 0 0 0 0 0 0; -0.5 0.3 0.3 0.3 0 0 0 0 0 0], det_count);
+% save('phantom3d', 'I');
+load('phantom3d'); % Loads I.
+
+% Create projection and volume geometries.
+angles = linspace(0, pi - pi / proj_count, proj_count);
+proj_geom = astra_create_proj_geom('cone', 1, 1, slice_count, det_count, angles, 500, 0);
+vol_geom = astra_create_vol_geom(det_count, det_count, slice_count);
+
+% Create sinogram.
+[sinogram_id, sinogram] = astra_create_sino3d_cuda(I, proj_geom, vol_geom);
+astra_mex_data3d('delete', sinogram_id);
+
+%
+% DART
+%
+
+base.sinogram = sinogram;
+base.proj_geom = proj_geom;
+
+D = DARTalgorithm(base);
+
+D.tomography = TomographyDefault3D();
+D.tomography.t0 = 100;
+D.tomography.t = 10;
+D.tomography.method = 'SIRT3D_CUDA';
+D.tomography.gpu_core = gpu_core;
+D.tomography.use_minc = 'yes';
+% D.tomography.maxc = 0.003; % Not a sensible value, just for demonstration.
+
+D.segmentation.rho = rho;
+D.segmentation.tau = tau;
+
+D.smoothing.b = 0.1;
+D.smoothing.full3d = 'yes';
+D.smoothing.gpu_core = gpu_core;
+
+D.masking.random = 0.1;
+D.masking.conn = 6;
+D.masking.gpu_core = gpu_core;
+
+D.output.directory = outdir;
+D.output.pre = [prefix '_'];
+D.output.save_images = 'no';
+D.output.save_results = {'stats', 'settings', 'S', 'V'};
+D.output.save_interval = dart_iterations;
+D.output.verbose = 'yes';
+
+D.statistics.proj_diff = 'no';
+
+D.initialize();
+
+disp([D.output.directory D.output.pre]);
+
+D.iterate(dart_iterations);
+
+% Convert middle slice of final iteration to png.
+load([outdir '/' prefix '_results_' num2str(dart_iterations) '.mat']);
+imwritesc(D.S(:, :, round(slice_count / 2)), [outdir '/' prefix '_slice_2_S.png']);
+imwritesc(D.V(:, :, round(slice_count / 2)), [outdir '/' prefix '_slice_2_V.png']);
diff --git a/matlab/algorithms/DART/examples/example3.m b/matlab/algorithms/DART/examples/example3.m
new file mode 100644
index 0000000..f6e360e
--- /dev/null
+++ b/matlab/algorithms/DART/examples/example3.m
@@ -0,0 +1,79 @@
+clear all;
+
+addpath('..');
+
+%
+% Example 3: parallel beam, 2D
+%
+
+% Configuration
+proj_count = 30;
+dart_iterations = 20;
+filename = 'cylinders.png';
+outdir = './';
+prefix = 'example3';
+rho = [0, 1];
+tau = 0.5;
+gpu_core = 0;
+
+% Load phantom.
+I = double(imread(filename)) / 255;
+
+% Create projection and volume geometries.
+det_count = size(I, 1);
+angles = linspace(0, pi - pi / proj_count, proj_count);
+proj_geom = astra_create_proj_geom('parallel', 1, det_count, angles);
+vol_geom = astra_create_vol_geom(det_count, det_count);
+
+% Create sinogram.
+[sinogram_id, sinogram] = astra_create_sino_cuda(I, proj_geom, vol_geom);
+astra_mex_data2d('delete', sinogram_id);
+
+%
+% DART
+%
+
+base.sinogram = sinogram;
+base.proj_geom = proj_geom;
+
+D = DARTalgorithm(base);
+
+%D.tomography = TomographyDefault3D();
+D.tomography.t0 = 100;
+D.tomography.t = 10;
+D.tomography.method = 'SIRT_CUDA';
+D.tomography.proj_type = 'strip';
+D.tomography.gpu_core = gpu_core;
+D.tomography.use_minc = 'yes';
+% D.tomography.maxc = 0.003; % Not a sensible value, just for demonstration.
+
+D.segmentation.rho = rho;
+D.segmentation.tau = tau;
+
+D.smoothing.b = 0.1;
+D.smoothing.full3d = 'yes';
+D.smoothing.gpu_core = gpu_core;
+
+D.masking.random = 0.1;
+D.masking.conn = 6;
+D.masking.gpu_core = gpu_core;
+
+D.output.directory = outdir;
+D.output.pre = [prefix '_'];
+D.output.save_images = 'no';
+D.output.save_results = {'stats', 'settings', 'S', 'V'};
+D.output.save_interval = dart_iterations;
+D.output.verbose = 'yes';
+
+D.statistics.proj_diff = 'no';
+
+D.initialize();
+
+disp([D.output.directory D.output.pre]);
+
+D.iterate(dart_iterations);
+
+% Convert output of final iteration to png.
+load([outdir '/' prefix '_results_' num2str(dart_iterations) '.mat']);
+imwritesc(D.S, [outdir '/' prefix '_S.png']);
+imwritesc(D.V, [outdir '/' prefix '_V.png']);
diff --git a/matlab/algorithms/DART/examples/phantom3d.mat b/matlab/algorithms/DART/examples/phantom3d.mat
new file mode 100644
index 0000000..6d70c16
--- /dev/null
+++ b/matlab/algorithms/DART/examples/phantom3d.mat
Binary files differ
diff --git a/matlab/mex/astra_mex.cpp b/matlab/mex/astra_mex.cpp
new file mode 100644
index 0000000..4b77f76
--- /dev/null
+++ b/matlab/mex/astra_mex.cpp
@@ -0,0 +1,121 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <mex.h>
+#include "mexHelpFunctions.h"
+
+#include "astra/Globals.h"
+
+using namespace std;
+using namespace astra;
+
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex('credits');
+ *
+ * Print Credits
+ */
+void astra_mex_credits(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ cout << "All Scale Tomographic Reconstruction Antwerp Toolbox (ASTRA-Toolbox) was developed at the University of Antwerp by" << endl;
+ cout << " * Joost Batenburg, PhD" << endl;
+ cout << " * Gert Merckx" << endl;
+ cout << " * Willem Jan Palenstijn" << endl;
+ cout << " * Tom Roelandts" << endl;
+ cout << " * Prof. Dr. Jan Sijbers" << endl;
+ cout << " * Wim van Aarle" << endl;
+ cout << " * Sander van der Maar" << endl;
+ cout << " * Gert Van Gompel, PhD" << endl;
+}
+
+//-----------------------------------------------------------------------------------------
+/** use_cuda = astra_mex('use_cuda');
+ *
+ * Is CUDA enabled?
+ */
+void astra_mex_use_cuda(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(astra::cudaEnabled() ? 1 : 0);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** version_number = astra_mex('version');
+ *
+ * Fetch the version number of the toolbox.
+ */
+void astra_mex_version(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(astra::getVersion());
+ } else {
+ cout << "astra toolbox version " << astra::getVersionString() << endl;
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+
+static void printHelp()
+{
+ mexPrintf("Please specify a mode of operation.\n");
+ mexPrintf(" Valid modes: version, use_cuda, credits\n");
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * ... = astra_mex(type,...);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+ int nrhs, const mxArray* prhs[])
+{
+
+ // INPUT0: Mode
+ string sMode = "";
+ if (1 <= nrhs) {
+ sMode = mex_util_get_string(prhs[0]);
+ } else {
+ printHelp();
+ return;
+ }
+
+ // SWITCH (MODE)
+ if (sMode == std::string("version")) {
+ astra_mex_version(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("use_cuda")) {
+ astra_mex_use_cuda(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("credits")) {
+ astra_mex_credits(nlhs, plhs, nrhs, prhs);
+ } else {
+ printHelp();
+ }
+
+ return;
+}
+
+
diff --git a/matlab/mex/astra_mex_algorithm_c.cpp b/matlab/mex/astra_mex_algorithm_c.cpp
new file mode 100644
index 0000000..7476ba4
--- /dev/null
+++ b/matlab/mex/astra_mex_algorithm_c.cpp
@@ -0,0 +1,348 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file astra_mex_algorithm_c.cpp
+ *
+ * \brief Creates and manages algorithms (reconstruction,projection,...).
+ */
+#include <mex.h>
+#include "mexHelpFunctions.h"
+
+#define USE_MATLAB_UNDOCUMENTED
+
+#ifdef USE_MATLAB_UNDOCUMENTED
+extern "C" { bool utIsInterruptPending(); }
+
+#ifdef __linux__
+#define USE_PTHREADS_CTRLC
+#include <pthread.h>
+#else
+#include <boost/thread.hpp>
+#endif
+
+#endif
+
+
+
+#include "astra/Globals.h"
+
+#include "astra/AstraObjectManager.h"
+#include "astra/AstraObjectFactory.h"
+
+#include "astra/XMLNode.h"
+#include "astra/XMLDocument.h"
+
+using namespace std;
+using namespace astra;
+//-----------------------------------------------------------------------------------------
+/** id = astra_mex_algorithm('create', cfg);
+ *
+ * Create and configure a new algorithm object.
+ * cfg: MATLAB struct containing the configuration parameters, see doxygen documentation for details.
+ * id: identifier of the algorithm object as it is now stored in the astra-library.
+ */
+void astra_mex_algorithm_create(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ if (!mxIsStruct(prhs[1])) {
+ mexErrMsgTxt("Argument 1 not a valid MATLAB struct. \n");
+ }
+
+ // turn MATLAB struct to an XML-based Config object
+ XMLDocument* xml = struct2XML("Algorithm", prhs[1]);
+ Config cfg;
+ cfg.self = xml->getRootNode();
+
+ CAlgorithm* pAlg = CAlgorithmFactory::getSingleton().create(cfg.self->getAttribute("type"));
+ if (!pAlg) {
+ delete xml;
+ mexErrMsgTxt("Unknown algorithm. \n");
+ return;
+ }
+
+ // create algorithm
+ if (!pAlg->initialize(cfg)) {
+ delete xml;
+ delete pAlg;
+ mexErrMsgTxt("Algorithm not initialized. \n");
+ return;
+ }
+
+ delete xml;
+
+ // store algorithm
+ int iIndex = CAlgorithmManager::getSingleton().store(pAlg);
+
+ // step4: set output
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(iIndex);
+ }
+
+}
+
+#ifdef USE_MATLAB_UNDOCUMENTED
+
+#ifndef USE_PTHREADS_CTRLC
+
+// boost version
+void waitForInterrupt_boost(CAlgorithm* _pAlg)
+{
+ boost::posix_time::milliseconds rel(2000);
+
+ while (!utIsInterruptPending()) {
+
+ // This is an interruption point. If the main thread calls
+ // interrupt(), this thread will terminate here.
+ boost::this_thread::sleep(rel);
+ }
+
+ //mexPrintf("Aborting. Please wait.\n");
+
+ // One last quick check to see if the algorithm already finished
+ boost::this_thread::interruption_point();
+
+ _pAlg->signalAbort();
+}
+
+#else
+
+// pthreads version
+void *waitForInterrupt_pthreads(void *threadid)
+{
+ CAlgorithm* _pAlg = (CAlgorithm*)threadid;
+
+ while (!utIsInterruptPending()) {
+ usleep(50000);
+ pthread_testcancel();
+ }
+
+ //mexPrintf("Aborting. Please wait.\n");
+
+ // One last quick check to see if the algorithm already finished
+ pthread_testcancel();
+
+ _pAlg->signalAbort();
+
+ return 0;
+}
+
+#endif
+#endif
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_algorithm('run', id); or astra_mex_algorithm('iterate', id, iterations);
+ *
+ * Run or do iterations on a certain algorithm.
+ * id: identifier of the algorithm object as stored in the astra-library.
+ * iterations: if the algorithm is iterative, this specifies the number of iterations to perform.
+ */
+void astra_mex_algorithm_run(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iAid = (int)(mxGetScalar(prhs[1]));
+ int iIterations = 0;
+ if (3 <= nrhs) {
+ iIterations = (int)(mxGetScalar(prhs[2]));
+ }
+
+ // step2: get algorithm object
+ CAlgorithm* pAlg = CAlgorithmManager::getSingleton().get(iAid);
+ if (!pAlg) {
+ mexErrMsgTxt("Invalid algorithm ID.\n");
+ return;
+ }
+ if (!pAlg->isInitialized()) {
+ mexErrMsgTxt("Algorithm not initialized. \n");
+ return;
+ }
+
+ // step3: perform actions
+#ifndef USE_MATLAB_UNDOCUMENTED
+
+ pAlg->run(iIterations);
+
+#elif defined(USE_PTHREADS_CTRLC)
+
+ // Start a new thread to watch if the user pressed Ctrl-C
+ pthread_t thread;
+ pthread_create(&thread, 0, waitForInterrupt_pthreads, (void*)pAlg);
+
+ pAlg->run(iIterations);
+
+ // kill the watcher thread in case it's still running
+ pthread_cancel(thread);
+ pthread_join(thread, 0);
+
+#else
+
+ // Start a new thread to watch if the user pressed Ctrl-C
+ boost::thread interruptThread(waitForInterrupt_boost, pAlg);
+
+ pAlg->run(iIterations);
+
+ // kill the watcher thread in case it's still running
+ interruptThread.interrupt();
+ interruptThread.join();
+
+#endif
+}
+//-----------------------------------------------------------------------------------------
+/** astra_mex_algorithm('get_res_norm', id);
+ *
+ * Get the L2-norm of the residual sinogram. Not all algorithms
+ * support this operation.
+ */
+void astra_mex_algorithm_get_res_norm(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iAid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get algorithm object
+ CAlgorithm* pAlg = CAlgorithmManager::getSingleton().get(iAid);
+ if (!pAlg) {
+ mexErrMsgTxt("Invalid algorithm ID.\n");
+ return;
+ }
+ if (!pAlg->isInitialized()) {
+ mexErrMsgTxt("Algorithm not initialized. \n");
+ return;
+ }
+
+ CReconstructionAlgorithm2D* pAlg2D = dynamic_cast<CReconstructionAlgorithm2D*>(pAlg);
+ CReconstructionAlgorithm3D* pAlg3D = dynamic_cast<CReconstructionAlgorithm3D*>(pAlg);
+
+ float res = 0.0f;
+ bool ok;
+ if (pAlg2D)
+ ok = pAlg2D->getResidualNorm(res);
+ else if (pAlg3D)
+ ok = pAlg3D->getResidualNorm(res);
+ else
+ ok = false;
+
+ if (!ok) {
+ mexErrMsgTxt("Operation not supported.\n");
+ return;
+ }
+
+ plhs[0] = mxCreateDoubleScalar(res);
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_algorithm('delete', id1, id2, ...);
+ *
+ * Delete one or more algorithm objects currently stored in the astra-library.
+ * id1, id2, ... : identifiers of the algorithm objects as stored in the astra-library.
+ */
+void astra_mex_algorithm_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get algorithm ID
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ for (int i = 1; i < nrhs; i++) {
+ int iAid = (int)(mxGetScalar(prhs[i]));
+ CAlgorithmManager::getSingleton().remove(iAid);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_algorithm('clear');
+ *
+ * Delete all algorithm objects currently stored in the astra-library.
+ */
+void astra_mex_algorithm_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ CAlgorithmManager::getSingleton().clear();
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_algorithm('info');
+ *
+ * Print information about all the algorithm objects currently stored in the astra-library.
+ */
+void astra_mex_algorithm_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ mexPrintf("%s", astra::CAlgorithmManager::getSingleton().info().c_str());
+}
+
+//-----------------------------------------------------------------------------------------
+static void printHelp()
+{
+ mexPrintf("Please specify a mode of operation.\n");
+ mexPrintf("Valid modes: create, info, delete, clear, run/iterate, get_res_norm\n");
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * ... = astra_mex_algorithm(mode, ...);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+ int nrhs, const mxArray* prhs[])
+{
+ // INPUT: Mode
+ string sMode = "";
+ if (1 <= nrhs) {
+ sMode = mex_util_get_string(prhs[0]);
+ } else {
+ printHelp();
+ return;
+ }
+
+ // SWITCH (MODE)
+ if (sMode == "create") {
+ astra_mex_algorithm_create(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "info") {
+ astra_mex_algorithm_info(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "delete") {
+ astra_mex_algorithm_delete(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "clear") {
+ astra_mex_algorithm_clear(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "run" || sMode == "iterate") {
+ astra_mex_algorithm_run(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "get_res_norm") {
+ astra_mex_algorithm_get_res_norm(nlhs, plhs, nrhs, prhs);
+ } else {
+ printHelp();
+ }
+ return;
+}
diff --git a/matlab/mex/astra_mex_algorithm_vc08.vcproj b/matlab/mex/astra_mex_algorithm_vc08.vcproj
new file mode 100644
index 0000000..baa4c44
--- /dev/null
+++ b/matlab/mex/astra_mex_algorithm_vc08.vcproj
@@ -0,0 +1,593 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="astra_mex_algorithm"
+ ProjectGUID="{056BF7A9-294D-487C-8CC3-BE629077CA94}"
+ RootNamespace="astraMatlab"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft;..\..\lib\win32"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft;..\..\lib\x64"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft;..\..\lib\win32"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="false"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft;..\..\lib\x64"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft;..\..\lib\win32"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ BrowseInformation="1"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft;..\..\lib\x64"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft;..\..\lib\win32"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft;..\..\lib\x64"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\astra_mex_algorithm_c.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/matlab/mex/astra_mex_c.cpp b/matlab/mex/astra_mex_c.cpp
new file mode 100644
index 0000000..0068664
--- /dev/null
+++ b/matlab/mex/astra_mex_c.cpp
@@ -0,0 +1,127 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file astra_mex_c.cpp
+ *
+ * \brief Contains some basic "about" functions.
+ */
+
+#include <mex.h>
+#include "mexHelpFunctions.h"
+
+#include "astra/Globals.h"
+
+using namespace std;
+using namespace astra;
+
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex('credits');
+ *
+ * Print Credits
+ */
+void astra_mex_credits(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ mexPrintf("All Scale Tomographic Reconstruction Antwerp Toolbox (ASTRA-Toolbox) was developed at the University of Antwerp by\n");
+ mexPrintf(" * Prof. dr. Joost Batenburg\n");
+ mexPrintf(" * Andrei Dabravolski\n");
+ mexPrintf(" * Gert Merckx\n");
+ mexPrintf(" * Willem Jan Palenstijn\n");
+ mexPrintf(" * Tom Roelandts\n");
+ mexPrintf(" * Prof. dr. Jan Sijbers\n");
+ mexPrintf(" * dr. Wim van Aarle\n");
+ mexPrintf(" * Sander van der Maar\n");
+ mexPrintf(" * dr. Gert Van Gompel\n");
+}
+
+//-----------------------------------------------------------------------------------------
+/** use_cuda = astra_mex('use_cuda');
+ *
+ * Is CUDA enabled?
+ */
+void astra_mex_use_cuda(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(astra::cudaEnabled() ? 1 : 0);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** version_number = astra_mex('version');
+ *
+ * Fetch the version number of the toolbox.
+ */
+void astra_mex_version(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(astra::getVersion());
+ } else {
+ mexPrintf("astra toolbox version %s\n", astra::getVersionString());
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+
+static void printHelp()
+{
+ mexPrintf("Please specify a mode of operation.\n");
+ mexPrintf(" Valid modes: version, use_cuda, credits\n");
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * ... = astra_mex(type,...);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+ int nrhs, const mxArray* prhs[])
+{
+
+ // INPUT0: Mode
+ string sMode = "";
+ if (1 <= nrhs) {
+ sMode = mex_util_get_string(prhs[0]);
+ } else {
+ printHelp();
+ return;
+ }
+
+ // SWITCH (MODE)
+ if (sMode == std::string("version")) {
+ astra_mex_version(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("use_cuda")) {
+ astra_mex_use_cuda(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("credits")) {
+ astra_mex_credits(nlhs, plhs, nrhs, prhs);
+ } else {
+ printHelp();
+ }
+
+ return;
+}
+
+
diff --git a/matlab/mex/astra_mex_data2d_c.cpp b/matlab/mex/astra_mex_data2d_c.cpp
new file mode 100644
index 0000000..99fb38e
--- /dev/null
+++ b/matlab/mex/astra_mex_data2d_c.cpp
@@ -0,0 +1,667 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file astra_mex_data2d_c.cpp
+ *
+ * \brief Creates, manages and manipulates 2D volume and projection data objects.
+ */
+#include <mex.h>
+#include "mexHelpFunctions.h"
+
+#include <list>
+
+#include "astra/Globals.h"
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/Float32ProjectionData2D.h"
+#include "astra/Float32VolumeData2D.h"
+#include "astra/SparseMatrixProjectionGeometry2D.h"
+#include "astra/FanFlatProjectionGeometry2D.h"
+#include "astra/FanFlatVecProjectionGeometry2D.h"
+
+using namespace std;
+using namespace astra;
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_data2d('delete', id1, id2, ...);
+ *
+ * Delete one or more data objects currently stored in the astra-library.
+ * id1, id2, ... : identifiers of the 2d data objects as stored in the astra-library.
+ */
+void astra_mex_data2d_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ // step2: delete all specified data objects
+ for (int i = 1; i < nrhs; i++) {
+ int iDataID = (int)(mxGetScalar(prhs[i]));
+ CData2DManager::getSingleton().remove(iDataID);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_data2d('clear');
+ *
+ * Delete all data objects currently stored in the astra-library.
+ */
+void astra_mex_data2d_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ CData2DManager::getSingleton().clear();
+}
+
+//-----------------------------------------------------------------------------------------
+/** id = astra_mex_data2d('create', datatype, geometry, data);
+ *
+ * Create a new data 2d object in the astra-library.
+ * type: '-vol' for volume data, '-sino' for projection data
+ * geom: MATLAB struct with the geometry for the data
+ * data: Optional. Can be either a MATLAB matrix containing the data. In that case the dimensions
+ * should match that of the geometry of the object. It can also be a single value, in which case
+ * the entire data will be set to that value. If this isn't specified all values are set to 0.
+ * id: identifier of the 2d data object as it is now stored in the astra-library.
+ */
+void astra_mex_data2d_create(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[])
+{
+ // step1: get datatype
+ if (nrhs < 3) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ string sDataType = mex_util_get_string(prhs[1]);
+ CFloat32Data2D* pDataObject2D = NULL;
+
+ if (nrhs >= 4 && !(mex_is_scalar(prhs[3])|| mxIsDouble(prhs[3]) || mxIsLogical(prhs[3]) || mxIsSingle(prhs[3]) )) {
+ mexErrMsgTxt("Data must be single, double or logical.");
+ return;
+ }
+
+ // SWITCH DataType
+ if (sDataType == "-vol") {
+ // Read geometry
+ if (!mxIsStruct(prhs[2])) {
+ mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
+ }
+ XMLDocument* xml = struct2XML(string("VolumeGeometry"), prhs[2]);
+ if (!xml)
+ return;
+ Config cfg;
+ cfg.self = xml->getRootNode();
+ CVolumeGeometry2D* pGeometry = new CVolumeGeometry2D();
+ if (!pGeometry->initialize(cfg)) {
+ mexErrMsgTxt("Geometry class not initialized. \n");
+ delete xml;
+ delete pGeometry;
+ return;
+ }
+ // If data is specified, check dimensions
+ if (nrhs >= 4 && !mex_is_scalar(prhs[3])) {
+ if (pGeometry->getGridColCount() != mxGetN(prhs[3]) || pGeometry->getGridRowCount() != mxGetM(prhs[3])) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ delete xml;
+ delete pGeometry;
+ return;
+ }
+ }
+ // Initialize data object
+ pDataObject2D = new CFloat32VolumeData2D(pGeometry);
+ delete pGeometry;
+ delete xml;
+ }
+ else if (sDataType == "-sino") {
+ // Read geometry
+ if (!mxIsStruct(prhs[2])) {
+ mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
+ }
+ XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]);
+ if (!xml)
+ return;
+ Config cfg;
+ cfg.self = xml->getRootNode();
+ // FIXME: Change how the base class is created. (This is duplicated
+ // in 'change_geometry' and Projector2D.cpp.)
+ std::string type = cfg.self->getAttribute("type");
+ CProjectionGeometry2D* pGeometry;
+ if (type == "sparse_matrix") {
+ pGeometry = new CSparseMatrixProjectionGeometry2D();
+ } else if (type == "fanflat") {
+ //CFanFlatProjectionGeometry2D* pFanFlatProjectionGeometry = new CFanFlatProjectionGeometry2D();
+ //pFanFlatProjectionGeometry->initialize(Config(node));
+ //m_pProjectionGeometry = pFanFlatProjectionGeometry;
+ pGeometry = new CFanFlatProjectionGeometry2D();
+ } else if (type == "fanflat_vec") {
+ pGeometry = new CFanFlatVecProjectionGeometry2D();
+ } else {
+ pGeometry = new CParallelProjectionGeometry2D();
+ }
+ if (!pGeometry->initialize(cfg)) {
+ mexErrMsgTxt("Geometry class not initialized. \n");
+ delete pGeometry;
+ delete xml;
+ return;
+ }
+ // If data is specified, check dimensions
+ if (nrhs >= 4 && !mex_is_scalar(prhs[3])) {
+ if (pGeometry->getDetectorCount() != mxGetN(prhs[3]) || pGeometry->getProjectionAngleCount() != mxGetM(prhs[3])) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ delete pGeometry;
+ delete xml;
+ return;
+ }
+ }
+ // Initialize data object
+ pDataObject2D = new CFloat32ProjectionData2D(pGeometry);
+ delete pGeometry;
+ delete xml;
+ }
+ else {
+ mexErrMsgTxt("Invalid datatype. Please specify '-vol' or '-sino'. \n");
+ return;
+ }
+
+ // Check initialization
+ if (!pDataObject2D->isInitialized()) {
+ mexErrMsgTxt("Couldn't initialize data object.\n");
+ delete pDataObject2D;
+ return;
+ }
+
+ // Store data
+ if (nrhs == 3) {
+ for (int i = 0; i < pDataObject2D->getSize(); ++i) {
+ pDataObject2D->getData()[i] = 0.0f;
+ }
+ }
+
+ // Store data
+ if (nrhs >= 4) {
+ // fill with scalar value
+ if (mex_is_scalar(prhs[3])) {
+ float32 fValue = (float32)mxGetScalar(prhs[3]);
+ for (int i = 0; i < pDataObject2D->getSize(); ++i) {
+ pDataObject2D->getData()[i] = fValue;
+ }
+ }
+ // fill with array value
+ else {
+ const mwSize* dims = mxGetDimensions(prhs[3]);
+ // Check Data dimensions
+ if (pDataObject2D->getWidth() != mxGetN(prhs[3]) || pDataObject2D->getHeight() != mxGetM(prhs[3])) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ return;
+ }
+
+ // logical data
+ if (mxIsLogical(prhs[3])) {
+ bool* pbMatlabData = mxGetLogicals(prhs[3]);
+ int i = 0;
+ int col, row;
+ for (col = 0; col < dims[1]; ++col) {
+ for (row = 0; row < dims[0]; ++row) {
+ pDataObject2D->getData2D()[row][col] = (float32)pbMatlabData[i];
+ ++i;
+ }
+ }
+ // double data
+ } else if (mxIsDouble(prhs[3])) {
+ double* pdMatlabData = mxGetPr(prhs[3]);
+ int i = 0;
+ int col, row;
+ for (col = 0; col < dims[1]; ++col) {
+ for (row = 0; row < dims[0]; ++row) {
+ pDataObject2D->getData2D()[row][col] = pdMatlabData[i];
+ ++i;
+ }
+ }
+ // single data
+ } else if (mxIsSingle(prhs[3])) {
+ const float* pfMatlabData = (const float *)mxGetData(prhs[3]);
+ int i = 0;
+ int col, row;
+ for (col = 0; col < dims[1]; ++col) {
+ for (row = 0; row < dims[0]; ++row) {
+ pDataObject2D->getData2D()[row][col] = pfMatlabData[i];
+ ++i;
+ }
+ }
+ } else {
+ ASTRA_ASSERT(false);
+ }
+ }
+ }
+
+ // step4: store data object
+ int iIndex = CData2DManager::getSingleton().store(pDataObject2D);
+
+ // step5: return data id
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(iIndex);
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_data2d('store', id, data);
+ *
+ * Store data in an existing astra 2d dataobject with a MATLAB matrix or with a scalar value.
+ * id: identifier of the 2d data object as stored in the astra-library.
+ * data: can be either a MATLAB matrix containing the data. In that case the dimensions should match that of the geometry of the object. It can also be a single value, in which case the entire data will be set to that value.
+ */
+void astra_mex_data2d_store(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: input
+ if (nrhs < 3) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ if (!mxIsDouble(prhs[1])) {
+ mexErrMsgTxt("Identifier should be a scalar value. \n");
+ return;
+ }
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+
+ if (!(mex_is_scalar(prhs[2]) || mxIsDouble(prhs[2]) || mxIsLogical(prhs[2]) || mxIsSingle(prhs[2]))) {
+ mexErrMsgTxt("Data must be single, double or logical.");
+ return;
+ }
+
+ // step2: get data object
+ CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID);
+ if (!pDataObject || !pDataObject->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ // step3: insert data
+ // fill with scalar value
+ if (mex_is_scalar(prhs[2])) {
+ float32 fValue = (float32)mxGetScalar(prhs[2]);
+ for (int i = 0; i < pDataObject->getSize(); ++i) {
+ pDataObject->getData()[i] = fValue;
+ }
+ } else {
+ // Check Data dimensions
+ if (pDataObject->getWidth() != mxGetN(prhs[2]) || pDataObject->getHeight() != mxGetM(prhs[2])) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ return;
+ }
+ const mwSize* dims = mxGetDimensions(prhs[2]);
+
+ // logical data
+ if (mxIsLogical(prhs[2])) {
+ bool* pbMatlabData = mxGetLogicals(prhs[2]);
+ int i = 0;
+ int col, row;
+ for (col = 0; col < dims[1]; ++col) {
+ for (row = 0; row < dims[0]; ++row) {
+ pDataObject->getData2D()[row][col] = (float32)pbMatlabData[i];
+ ++i;
+ }
+ }
+ // double data
+ } else if (mxIsDouble(prhs[2])) {
+ double* pdMatlabData = mxGetPr(prhs[2]);
+ int i = 0;
+ int col, row;
+ for (col = 0; col < dims[1]; ++col) {
+ for (row = 0; row < dims[0]; ++row) {
+ pDataObject->getData2D()[row][col] = pdMatlabData[i];
+ ++i;
+ }
+ }
+ // single data
+ } else if (mxIsSingle(prhs[2])) {
+ const float* pfMatlabData = (const float *)mxGetData(prhs[2]);
+ int i = 0;
+ int col, row;
+ for (col = 0; col < dims[1]; ++col) {
+ for (row = 0; row < dims[0]; ++row) {
+ pDataObject->getData2D()[row][col] = pfMatlabData[i];
+ ++i;
+ }
+ }
+ } else {
+ ASTRA_ASSERT(false);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** geom = astra_mex_data2d('get_geometry', id);
+ *
+ * Fetch the geometry of a 2d data object stored in the astra-library.
+ * id: identifier of the 2d data object as stored in the astra-library.
+ * geom: MATLAB-struct containing information about the used geometry.
+ */
+void astra_mex_data2d_get_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ if (!mxIsDouble(prhs[1])) {
+ mexErrMsgTxt("Identifier should be a scalar value. \n");
+ return;
+ }
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get data object
+ CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID);
+ if (!pDataObject || !pDataObject->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ // create output
+ if (1 <= nlhs) {
+ if (pDataObject->getType() == CFloat32Data2D::PROJECTION) {
+ CFloat32ProjectionData2D* pDataObject2 = dynamic_cast<CFloat32ProjectionData2D*>(pDataObject);
+ plhs[0] = createProjectionGeometryStruct(pDataObject2->getGeometry());
+ }
+ else if (pDataObject->getType() == CFloat32Data2D::VOLUME) {
+ CFloat32VolumeData2D* pDataObject2 = dynamic_cast<CFloat32VolumeData2D*>(pDataObject);
+ plhs[0] = createVolumeGeometryStruct(pDataObject2->getGeometry());
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_data2d('change_geometry', id, geom);
+ *
+ * Change the associated geometry of a 2d data object (volume or sinogram)
+ * id: identifier of the 2d data object as stored in the astra-library.
+ * geom: the new geometry struct, as created by astra_create_vol/proj_geom
+ */
+void astra_mex_data2d_change_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: check input
+ if (nrhs < 3) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ if (!mxIsDouble(prhs[1])) {
+ mexErrMsgTxt("Identifier should be a scalar value. \n");
+ return;
+ }
+
+ // step2: get data object
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+ CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID);
+ if (!pDataObject || !pDataObject->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ CFloat32ProjectionData2D* pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(pDataObject);
+
+ if (pSinogram) {
+ // Projection data
+
+ // Read geometry
+ if (!mxIsStruct(prhs[2])) {
+ mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
+ }
+ XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]);
+ Config cfg;
+ cfg.self = xml->getRootNode();
+ // FIXME: Change how the base class is created. (This is duplicated
+ // in 'create' and Projector2D.cpp.)
+ std::string type = cfg.self->getAttribute("type");
+ CProjectionGeometry2D* pGeometry;
+ if (type == "sparse_matrix") {
+ pGeometry = new CSparseMatrixProjectionGeometry2D();
+ } else if (type == "fanflat") {
+ //CFanFlatProjectionGeometry2D* pFanFlatProjectionGeometry = new CFanFlatProjectionGeometry2D();
+ //pFanFlatProjectionGeometry->initialize(Config(node));
+ //m_pProjectionGeometry = pFanFlatProjectionGeometry;
+ pGeometry = new CFanFlatProjectionGeometry2D();
+ } else if (type == "fanflat_vec") {
+ pGeometry = new CFanFlatVecProjectionGeometry2D();
+ } else {
+ pGeometry = new CParallelProjectionGeometry2D();
+ }
+ if (!pGeometry->initialize(cfg)) {
+ mexErrMsgTxt("Geometry class not initialized. \n");
+ delete pGeometry;
+ delete xml;
+ return;
+ }
+ // If data is specified, check dimensions
+ if (pGeometry->getDetectorCount() != pSinogram->getDetectorCount() || pGeometry->getProjectionAngleCount() != pSinogram->getAngleCount()) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ delete pGeometry;
+ delete xml;
+ return;
+ }
+
+ // If ok, change geometry
+ pSinogram->changeGeometry(pGeometry);
+ delete pGeometry;
+ delete xml;
+
+ return;
+ }
+
+ CFloat32VolumeData2D* pVolume = dynamic_cast<CFloat32VolumeData2D*>(pDataObject);
+
+ if (pVolume) {
+ // Volume data
+
+ // Read geometry
+ if (!mxIsStruct(prhs[2])) {
+ mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
+ }
+ XMLDocument* xml = struct2XML(string("VolumeGeometry"), prhs[2]);
+ Config cfg;
+ cfg.self = xml->getRootNode();
+ CVolumeGeometry2D* pGeometry = new CVolumeGeometry2D();
+ if (!pGeometry->initialize(cfg)) {
+ mexErrMsgTxt("Geometry class not initialized. \n");
+ delete xml;
+ delete pGeometry;
+ return;
+ }
+ // If data is specified, check dimensions
+ if (pGeometry->getGridColCount() != pVolume->getWidth() || pGeometry->getGridRowCount() != pVolume->getHeight()) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ delete xml;
+ delete pGeometry;
+ return;
+ }
+
+ // If ok, change geometry
+ pVolume->changeGeometry(pGeometry);
+ delete xml;
+ delete pGeometry;
+
+ }
+
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+}
+
+//-----------------------------------------------------------------------------------------
+/** data = astra_mex_data2d('get', id);
+ *
+ * Fetch data from the astra-library to a MATLAB matrix.
+ * id: identifier of the 2d data object as stored in the astra-library.
+ * data: MATLAB data
+ */
+void astra_mex_data2d_get(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: check input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ if (!mxIsDouble(prhs[1])) {
+ mexErrMsgTxt("Identifier should be a scalar value. \n");
+ return;
+ }
+
+ // step2: get data object
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+ CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID);
+ if (!pDataObject || !pDataObject->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ // create output
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleMatrix(pDataObject->getHeight(), // # rows
+ pDataObject->getWidth(), // # cols
+ mxREAL); // datatype 64-bits
+ double* out = mxGetPr(plhs[0]);
+ int i = 0;
+ int row, col;
+ for (col = 0; col < pDataObject->getWidth(); ++col) {
+ for (row = 0; row < pDataObject->getHeight(); ++row) {
+ out[i] = pDataObject->getData2D()[row][col];
+ ++i;
+ }
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------
+/** data = astra_mex_data2d('get_single', id);
+ *
+ * Fetch data from the astra-library to a MATLAB matrix.
+ * id: identifier of the 2d data object as stored in the astra-library.
+ * data: MATLAB data
+ */
+void astra_mex_data2d_get_single(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: check input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ if (!mxIsDouble(prhs[1])) {
+ mexErrMsgTxt("Identifier should be a scalar value. \n");
+ return;
+ }
+
+ // step2: get data object
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+ CFloat32Data2D* pDataObject = astra::CData2DManager::getSingleton().get(iDataID);
+ if (!pDataObject || !pDataObject->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ // create output
+ if (1 <= nlhs) {
+ mwSize dims[2];
+ dims[0] = pDataObject->getHeight();
+ dims[1] = pDataObject->getWidth();
+ plhs[0] = mxCreateNumericArray(2, dims, mxSINGLE_CLASS, mxREAL);
+ float* out = (float *)mxGetData(plhs[0]);
+ int i = 0;
+ int row, col;
+ for (col = 0; col < pDataObject->getWidth(); ++col) {
+ for (row = 0; row < pDataObject->getHeight(); ++row) {
+ out[i] = pDataObject->getData2D()[row][col];
+ ++i;
+ }
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_data2d('info');
+ *
+ * Print information about all the 2d data objects currently stored in the astra-library.
+ */
+void astra_mex_data2d_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ mexPrintf("%s", astra::CData2DManager::getSingleton().info().c_str());
+}
+
+//-----------------------------------------------------------------------------------------
+
+static void printHelp()
+{
+ mexPrintf("Please specify a mode of operation.\n");
+ mexPrintf("Valid modes: get, get_single, delete, clear, set/store, create, get_geometry, change_geometry, info\n");
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * ... = astra_mex_data2d(type,...);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+ int nrhs, const mxArray* prhs[])
+{
+
+ // INPUT0: Mode
+ string sMode = "";
+ if (1 <= nrhs) {
+ sMode = mex_util_get_string(prhs[0]);
+ } else {
+ printHelp();
+ return;
+ }
+
+ // SWITCH (MODE)
+ if (sMode == std::string("get")) {
+ astra_mex_data2d_get(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("get_single")) {
+ astra_mex_data2d_get_single(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("delete")) {
+ astra_mex_data2d_delete(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "clear") {
+ astra_mex_data2d_clear(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("store") ||
+ sMode == std::string("set")) {
+ astra_mex_data2d_store(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("create")) {
+ astra_mex_data2d_create(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("get_geometry")) {
+ astra_mex_data2d_get_geometry(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("change_geometry")) {
+ astra_mex_data2d_change_geometry(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("info")) {
+ astra_mex_data2d_info(nlhs, plhs, nrhs, prhs);
+ } else {
+ printHelp();
+ }
+
+ return;
+}
+
+
diff --git a/matlab/mex/astra_mex_data2d_vc08.vcproj b/matlab/mex/astra_mex_data2d_vc08.vcproj
new file mode 100644
index 0000000..8f1fc13
--- /dev/null
+++ b/matlab/mex/astra_mex_data2d_vc08.vcproj
@@ -0,0 +1,591 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="astra_mex_data2d"
+ ProjectGUID="{E4092269-B19C-46F7-A84E-4F146CC70E44}"
+ RootNamespace="astraMatlab"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(CUDA_INC_PATH)&quot;;$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ BrowseInformation="1"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\astra_mex_data2d_c.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/matlab/mex/astra_mex_data3d_c.cpp b/matlab/mex/astra_mex_data3d_c.cpp
new file mode 100644
index 0000000..1af8844
--- /dev/null
+++ b/matlab/mex/astra_mex_data3d_c.cpp
@@ -0,0 +1,1036 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file astra_mex_data3d_c.cpp
+ *
+ * \brief Creates, manages and manipulates 3D volume and projection data objects.
+ */
+#include <mex.h>
+#include "mexHelpFunctions.h"
+
+#include <list>
+
+#include "astra/Globals.h"
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/Float32ProjectionData2D.h"
+#include "astra/Float32VolumeData2D.h"
+#include "astra/Float32ProjectionData3D.h"
+#include "astra/Float32ProjectionData3DMemory.h"
+#include "astra/Float32VolumeData3D.h"
+#include "astra/Float32VolumeData3DMemory.h"
+#include "astra/ParallelProjectionGeometry3D.h"
+#include "astra/ParallelVecProjectionGeometry3D.h"
+#include "astra/ConeProjectionGeometry3D.h"
+#include "astra/ConeVecProjectionGeometry3D.h"
+
+using namespace std;
+using namespace astra;
+
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * id = astra_mex_io_data('create', datatype, geometry, data);
+ * datatype: ['-vol','-sino','-sinocone']
+ */
+void astra_mex_data3d_create(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[])
+{
+ // step1: get datatype
+ if (nrhs < 3) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ string sDataType = mex_util_get_string(prhs[1]);
+ CFloat32Data3DMemory* pDataObject3D = NULL;
+
+ if (nrhs >= 4 && !(mex_is_scalar(prhs[3]) || mxIsDouble(prhs[3]) || mxIsSingle(prhs[3]))) {
+ mexErrMsgTxt("Data must be single or double.");
+ return;
+ }
+
+ mwSize dims[3];
+
+ // SWITCH DataType
+ if (sDataType == "-vol") {
+
+ // Read geometry
+ if (!mxIsStruct(prhs[2])) {
+ mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
+ }
+ Config cfg;
+ XMLDocument* xml = struct2XML("VolumeGeometry", prhs[2]);
+ if (!xml)
+ return;
+ cfg.self = xml->getRootNode();
+ CVolumeGeometry3D* pGeometry = new CVolumeGeometry3D();
+ if (!pGeometry->initialize(cfg)) {
+ mexErrMsgTxt("Geometry class not initialized. \n");
+ delete pGeometry;
+ delete xml;
+ return;
+ }
+ delete xml;
+
+ // If data is specified, check dimensions
+ if (nrhs >= 4 && !mex_is_scalar(prhs[3])) {
+ get3DMatrixDims(prhs[3], dims);
+ if (pGeometry->getGridColCount() != dims[0] || pGeometry->getGridRowCount() != dims[1] || pGeometry->getGridSliceCount() != dims[2]) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ delete pGeometry;
+ return;
+ }
+ }
+
+ // Initialize data object
+ pDataObject3D = new CFloat32VolumeData3DMemory(pGeometry);
+ delete pGeometry;
+ }
+
+ else if (sDataType == "-sino" || sDataType == "-proj3d") {
+
+ // Read geometry
+ if (!mxIsStruct(prhs[2])) {
+ mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
+ }
+ XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]);
+ if (!xml)
+ return;
+ Config cfg;
+ cfg.self = xml->getRootNode();
+
+ // FIXME: Change how the base class is created. (This is duplicated
+ // in Projector2D.cpp.)
+ std::string type = cfg.self->getAttribute("type");
+ CProjectionGeometry3D* pGeometry = 0;
+ if (type == "parallel3d") {
+ pGeometry = new CParallelProjectionGeometry3D();
+ } else if (type == "parallel3d_vec") {
+ pGeometry = new CParallelVecProjectionGeometry3D();
+ } else if (type == "cone") {
+ pGeometry = new CConeProjectionGeometry3D();
+ } else if (type == "cone_vec") {
+ pGeometry = new CConeVecProjectionGeometry3D();
+ } else {
+ mexErrMsgTxt("Invalid geometry type.\n");
+ return;
+ }
+
+ if (!pGeometry->initialize(cfg)) {
+ mexErrMsgTxt("Geometry class not initialized. \n");
+ delete pGeometry;
+ delete xml;
+ return;
+ }
+ delete xml;
+
+ // If data is specified, check dimensions
+ if (nrhs >= 4 && !mex_is_scalar(prhs[3])) {
+ get3DMatrixDims(prhs[3], dims);
+ if (pGeometry->getDetectorColCount() != dims[0] || pGeometry->getProjectionCount() != dims[1] || pGeometry->getDetectorRowCount() != dims[2]) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ delete pGeometry;
+ return;
+ }
+ }
+
+ // Initialize data object
+ pDataObject3D = new CFloat32ProjectionData3DMemory(pGeometry);
+ }
+
+ else if (sDataType == "-sinocone") {
+ // Read geometry
+ if (!mxIsStruct(prhs[2])) {
+ mexErrMsgTxt("Argument 3 is not a valid MATLAB struct.\n");
+ }
+ XMLDocument* xml = struct2XML("ProjectionGeometry", prhs[2]);
+ if (!xml)
+ return;
+ Config cfg;
+ cfg.self = xml->getRootNode();
+ CConeProjectionGeometry3D* pGeometry = new CConeProjectionGeometry3D();
+ if (!pGeometry->initialize(cfg)) {
+ mexErrMsgTxt("Geometry class not initialized. \n");
+ delete xml;
+ delete pGeometry;
+ return;
+ }
+ delete xml;
+ // If data is specified, check dimensions
+ if (nrhs >= 4 && !mex_is_scalar(prhs[3])) {
+ get3DMatrixDims(prhs[3], dims);
+ if (pGeometry->getDetectorRowCount() != dims[2] || pGeometry->getProjectionCount() != dims[1] || pGeometry->getDetectorColCount() != dims[0]) {
+ mexErrMsgTxt("The dimensions of the data do not match those specified in the geometry. \n");
+ delete pGeometry;
+ return;
+ }
+ }
+ // Initialize data object
+ pDataObject3D = new CFloat32ProjectionData3DMemory(pGeometry);
+ delete pGeometry;
+ }
+ else {
+ mexErrMsgTxt("Invalid datatype. Please specify '-vol' or '-proj3d'. \n");
+ return;
+ }
+
+ // Check initialization
+ if (!pDataObject3D->isInitialized()) {
+ mexErrMsgTxt("Couldn't initialize data object.\n");
+ delete pDataObject3D;
+ return;
+ }
+
+ // Store data
+
+ // fill with scalar value
+ if (nrhs < 4 || mex_is_scalar(prhs[3])) {
+ float32 fValue = 0.0f;
+ if (nrhs >= 4)
+ fValue = (float32)mxGetScalar(prhs[3]);
+ for (int i = 0; i < pDataObject3D->getSize(); ++i) {
+ pDataObject3D->getData()[i] = fValue;
+ }
+ }
+ // fill with array value
+ else if (mxIsDouble(prhs[3])) {
+ double* pdMatlabData = mxGetPr(prhs[3]);
+ int i = 0;
+ int col, row, slice;
+ for (slice = 0; slice < dims[2]; ++slice) {
+ for (row = 0; row < dims[1]; ++row) {
+ for (col = 0; col < dims[0]; ++col) {
+ // TODO: Benchmark and remove triple indexing?
+ pDataObject3D->getData3D()[slice][row][col] = pdMatlabData[i];
+ ++i;
+ }
+ }
+ }
+ }
+ else if (mxIsSingle(prhs[3])) {
+ const float* pfMatlabData = (const float*)mxGetData(prhs[3]);
+ int i = 0;
+ int col, row, slice;
+ for (slice = 0; slice < dims[2]; ++slice) {
+ for (row = 0; row < dims[1]; ++row) {
+ for (col = 0; col < dims[0]; ++col) {
+ // TODO: Benchmark and remove triple indexing?
+ pDataObject3D->getData3D()[slice][row][col] = pfMatlabData[i];
+ ++i;
+ }
+ }
+ }
+ }
+ pDataObject3D->updateStatistics();
+
+ // step4: store data object
+ int iIndex = CData3DManager::getSingleton().store(pDataObject3D);
+
+ // step5: return data id
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(iIndex);
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [id] = astra_mex_io_data('create_cache', config);
+ */
+void astra_mex_data3d_create_cache(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+// if (nrhs < 2) {
+// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+// return;
+// }
+//
+// if (!mxIsStruct(prhs[1])) {
+// mexErrMsgTxt("Argument 1 not a valid MATLAB struct. \n");
+// }
+//
+// // turn MATLAB struct to an XML-based Config object
+// XMLDocument* xml = struct2XML("Data3D", prhs[1]);
+// Config cfg;
+// cfg.self = xml->getRootNode();
+//
+// // create dataobject
+// string sType = cfg.self->getAttribute("type");
+// int iIndex;
+// if (sType == "ProjectionCached") {
+// CFloat32ProjectionData3DCached* pData = new CFloat32ProjectionData3DCached(cfg);
+// iIndex = CData3DManager::getSingleton().store(pData);
+// }
+//// else if (sType == "VolumeCached") {
+//// CFloat32VolumeData3DCached* pData = new CFloat32VolumeData3DCached(cfg);
+//// pData->initialize(cfg);
+//// iIndex = CData3DManager::getSingleton().store(pData);
+//// }
+//
+// // step4: set output
+// if (1 <= nlhs) {
+// plhs[0] = mxCreateDoubleScalar(iIndex);
+// }
+
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * data = astra_mex_data3d('get', id);
+ *
+ * Fetch data from the astra-library to a MATLAB matrix.
+ * id: identifier of the 3d data object as stored in the astra-library.
+ * data: MATLAB data
+
+ */
+void astra_mex_data3d_get(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get data object
+ CFloat32Data3DMemory* pDataObject = dynamic_cast<CFloat32Data3DMemory*>(astra::CData3DManager::getSingleton().get(iDataID));
+ if (!pDataObject || !pDataObject->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ // create output
+ if (1 <= nlhs) {
+ mwSize dims[3];
+ dims[0] = pDataObject->getWidth();
+ dims[1] = pDataObject->getHeight();
+ dims[2] = pDataObject->getDepth();
+
+ plhs[0] = mxCreateNumericArray(3, dims, mxDOUBLE_CLASS, mxREAL);
+ double* out = mxGetPr(plhs[0]);
+
+ int i = 0;
+ for (int slice = 0; slice < pDataObject->getDepth(); slice++) {
+ for (int row = 0; row < pDataObject->getHeight(); row++) {
+ for (int col = 0; col < pDataObject->getWidth(); col++) {
+ // TODO: Benchmark and remove triple indexing?
+ out[i] = pDataObject->getData3D()[slice][row][col];
+ ++i;
+ }
+ }
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * data = astra_mex_data3d('get_single', id);
+ *
+ * Fetch data from the astra-library to a MATLAB matrix.
+ * id: identifier of the 3d data object as stored in the astra-library.
+ * data: MATLAB data
+
+ */
+void astra_mex_data3d_get_single(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get data object
+ CFloat32Data3DMemory* pDataObject = dynamic_cast<CFloat32Data3DMemory*>(astra::CData3DManager::getSingleton().get(iDataID));
+ if (!pDataObject || !pDataObject->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ // create output
+ if (1 <= nlhs) {
+ mwSize dims[3];
+ dims[0] = pDataObject->getWidth();
+ dims[1] = pDataObject->getHeight();
+ dims[2] = pDataObject->getDepth();
+
+ plhs[0] = mxCreateNumericArray(3, dims, mxSINGLE_CLASS, mxREAL);
+ float* out = (float *)mxGetData(plhs[0]);
+
+ int i = 0;
+ for (int slice = 0; slice < pDataObject->getDepth(); slice++) {
+ for (int row = 0; row < pDataObject->getHeight(); row++) {
+ for (int col = 0; col < pDataObject->getWidth(); col++) {
+ // TODO: Benchmark and remove triple indexing?
+ out[i] = pDataObject->getData3D()[slice][row][col];
+ ++i;
+ }
+ }
+ }
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_data3d('store', id, data);
+ *
+ * Store MATLAB matrix data in the astra-library.
+ * id: identifier of the 3d data object as stored in the astra-library.
+ * data: MATLAB data
+
+ */
+void astra_mex_data3d_store(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: input
+ if (nrhs < 3) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get data object
+ CFloat32Data3DMemory* pDataObject = dynamic_cast<CFloat32Data3DMemory*>(astra::CData3DManager::getSingleton().get(iDataID));
+ if (!pDataObject || !pDataObject->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ if (!(mex_is_scalar(prhs[2]) || mxIsDouble(prhs[2]) || mxIsSingle(prhs[2]))) {
+ mexErrMsgTxt("Data must be single or double.");
+ return;
+ }
+
+ // fill with scalar value
+ if (mex_is_scalar(prhs[2])) {
+ float32 fValue = (float32)mxGetScalar(prhs[2]);
+ for (int i = 0; i < pDataObject->getSize(); ++i) {
+ pDataObject->getData()[i] = fValue;
+ }
+ }
+ // fill with array value
+ else if (mxIsDouble(prhs[2])) {
+ mwSize dims[3];
+ get3DMatrixDims(prhs[2], dims);
+ if (dims[0] != pDataObject->getWidth() || dims[1] != pDataObject->getHeight() || dims[2] != pDataObject->getDepth()) {
+ mexErrMsgTxt("Data object dimensions don't match.\n");
+ return;
+
+ }
+ double* pdMatlabData = mxGetPr(prhs[2]);
+ int i = 0;
+ int col, row, slice;
+ for (slice = 0; slice < dims[2]; ++slice) {
+ for (row = 0; row < dims[1]; ++row) {
+ for (col = 0; col < dims[0]; ++col) {
+ // TODO: Benchmark and remove triple indexing?
+ pDataObject->getData3D()[slice][row][col] = pdMatlabData[i];
+ ++i;
+ }
+ }
+ }
+ }
+ else if (mxIsSingle(prhs[2])) {
+ mwSize dims[3];
+ get3DMatrixDims(prhs[2], dims);
+ if (dims[0] != pDataObject->getWidth() || dims[1] != pDataObject->getHeight() || dims[2] != pDataObject->getDepth()) {
+ mexErrMsgTxt("Data object dimensions don't match.\n");
+ return;
+
+ }
+ const float* pfMatlabData = (const float *)mxGetData(prhs[2]);
+ int i = 0;
+ int col, row, slice;
+ for (slice = 0; slice < dims[2]; ++slice) {
+ for (row = 0; row < dims[1]; ++row) {
+ for (col = 0; col < dims[0]; ++col) {
+ // TODO: Benchmark and remove triple indexing?
+ pDataObject->getData3D()[slice][row][col] = pfMatlabData[i];
+ ++i;
+ }
+ }
+ }
+ }
+ pDataObject->updateStatistics();
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [id] = astra_mex_io_data('fetch_slice', id, slicenr);
+ */
+void astra_mex_data3d_fetch_slice_z(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+// // step1: get input
+// if (nrhs < 3) {
+// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+// return;
+// }
+// int iDid = (int)(mxGetScalar(prhs[1]));
+// int iSliceNr = (int)(mxGetScalar(prhs[2]));
+//
+// // Get data object
+// CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+// if (!pData) {
+// mexErrMsgTxt("DataObject not valid. \n");
+// return;
+// }
+//
+// CFloat32Data2D* res = NULL;
+// // Projection Data
+// if (pData->getType() == CFloat32Data3D::PROJECTION) {
+// CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData);
+//// res = pData2->fetchSlice(iSliceNr);
+// }
+// // Volume Data
+// else if (pData->getType() == CFloat32Data3D::VOLUME) {
+// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData);
+//// res = pData2->fetchSliceZ(iSliceNr);
+// }
+// // Error
+// else {
+// mexErrMsgTxt("DataObject not valid. \n");
+// return;
+// }
+//
+// // store data
+// int iIndex = CData2DManager::getSingleton().store(res);
+//
+// // step4: set output
+// if (1 <= nlhs) {
+// plhs[0] = mxCreateDoubleScalar(iIndex);
+// }
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_io_data('returnSlice', id, slicenr);
+ */
+void astra_mex_data3d_return_slice_z(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+// // step1: get input
+// if (nrhs < 3) {
+// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+// return;
+// }
+// int iDid = (int)(mxGetScalar(prhs[1]));
+// int iSliceNr = (int)(mxGetScalar(prhs[2]));
+//
+// // Get data object
+// CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+// if (!pData) {
+// mexErrMsgTxt("DataObject not valid. \n");
+// return;
+// }
+//
+// // Projection Data
+// if (pData->getType() == CFloat32Data3D::PROJECTION) {
+// CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData);
+//// TODO: think about returning slices
+//// pData2->returnSlice(iSliceNr);
+// }
+// // Volume Data
+// else if (pData->getType() == CFloat32Data3D::VOLUME) {
+// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData);
+//// TODO: think about returning slices
+//// pData2->returnSliceZ(iSliceNr);
+// }
+// // Error
+// else {
+// mexErrMsgTxt("DataObject not valid. \n");
+// return;
+// }
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [id] = astra_mex_io_data('fetch_projection', id, slicenr);
+ */
+void astra_mex_data3d_fetch_projection(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ //// step1: get input
+ //if (nrhs < 3) {
+ // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ // return;
+ //}
+ //int iDid = (int)(mxGetScalar(prhs[1]));
+ //int iProjectionNr = (int)(mxGetScalar(prhs[2]));
+
+ //// Get data object
+ //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+ //if (!pData) {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+
+ //CFloat32Data2D* res = NULL;
+ //// Projection Data
+ //if (pData->getType() == CFloat32Data3D::PROJECTION) {
+ // CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData);
+ // res = pData2->fetchProjection(iProjectionNr);
+ //}
+ //// Error
+ //else {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+ //
+ //// store data
+ //int iIndex = CData2DManager::getSingleton().store(res);
+
+ //// step4: set output
+ //if (1 <= nlhs) {
+ // plhs[0] = mxCreateDoubleScalar(iIndex);
+ //}
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_io_data('return_projection', id, slicenr);
+ */
+void astra_mex_data3d_return_projection(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ //// step1: get input
+ //if (nrhs < 3) {
+ // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ // return;
+ //}
+ //int iDid = (int)(mxGetScalar(prhs[1]));
+ //int iProjectionNr = (int)(mxGetScalar(prhs[2]));
+
+ //// Get data object
+ //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+ //if (!pData) {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+
+ //// Projection Data
+ //if (pData->getType() == CFloat32Data3D::PROJECTION) {
+ // CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData);
+ //// pData2->returnProjection(iProjectionNr);
+ //}
+ //// Error
+ //else {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [id] = astra_mex_io_data('fetch_projection', id, slicenr);
+ */
+void astra_mex_data3d_fetch_slice_x(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ //// step1: get input
+ //if (nrhs < 3) {
+ // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ // return;
+ //}
+ //int iDid = (int)(mxGetScalar(prhs[1]));
+ //int iSliceNr = (int)(mxGetScalar(prhs[2]));
+
+ //// Get data object
+ //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+ //if (!pData) {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+
+ //CFloat32Data2D* res = NULL;
+ //// Projection Data
+ //if (pData->getType() == CFloat32Data3D::VOLUME) {
+ // CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData);
+ // res = pData2->fetchSliceX(iSliceNr);
+ //}
+ //// Error
+ //else {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+ //
+ //// store data
+ //int iIndex = CData2DManager::getSingleton().store(res);
+
+ //// step4: set output
+ //if (1 <= nlhs) {
+ // plhs[0] = mxCreateDoubleScalar(iIndex);
+ //}
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_io_data('return_slice_x', id, slicenr);
+ */
+void astra_mex_data3d_return_slice_x(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+// // step1: get input
+// if (nrhs < 3) {
+// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+// return;
+// }
+// int iDid = (int)(mxGetScalar(prhs[1]));
+// int iSliceNr = (int)(mxGetScalar(prhs[2]));
+//
+// // Get data object
+// CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+// if (!pData) {
+// mexErrMsgTxt("DataObject not valid. \n");
+// return;
+// }
+//
+// // Projection Data
+// if (pData->getType() == CFloat32Data3D::VOLUME) {
+// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData);
+//// TODO: think about returning slices
+//// pData2->returnSliceX(iSliceNr);
+// }
+// // Error
+// else {
+// mexErrMsgTxt("DataObject not valid. \n");
+// return;
+// }
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [id] = astra_mex_io_data('fetch_slice_y', id, slicenr);
+ */
+void astra_mex_data3d_fetch_slice_y(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ //// step1: get input
+ //if (nrhs < 3) {
+ // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ // return;
+ //}
+ //int iDid = (int)(mxGetScalar(prhs[1]));
+ //int iSliceNr = (int)(mxGetScalar(prhs[2]));
+
+ //// Get data object
+ //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+ //if (!pData) {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+
+ //CFloat32Data2D* res = NULL;
+ //// Projection Data
+ //if (pData->getType() == CFloat32Data3D::VOLUME) {
+ // CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData);
+ // res = pData2->fetchSliceY(iSliceNr);
+ //}
+ //// Error
+ //else {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+ //
+ //// store data
+ //int iIndex = CData2DManager::getSingleton().store(res);
+
+ //// step4: set output
+ //if (1 <= nlhs) {
+ // plhs[0] = mxCreateDoubleScalar(iIndex);
+ //}
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_io_data('return_slice_y', id, slicenr);
+ */
+void astra_mex_data3d_return_slice_y(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+// // step1: get input
+// if (nrhs < 3) {
+// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+// return;
+// }
+// int iDid = (int)(mxGetScalar(prhs[1]));
+// int iSliceNr = (int)(mxGetScalar(prhs[2]));
+//
+// // Get data object
+// CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+// if (!pData) {
+// mexErrMsgTxt("DataObject not valid. \n");
+// return;
+// }
+//
+// // Projection Data
+// if (pData->getType() == CFloat32Data3D::VOLUME) {
+// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData);
+//// TODO: think about returning slices
+//// pData2->returnSliceY(iSliceNr);
+// }
+// // Error
+// else {
+// mexErrMsgTxt("DataObject not valid. \n");
+// return;
+// }
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [dim_x dim_y dim_z] = astra_mex_io_data('dimensions', id);
+ */
+void astra_mex_data3d_dimensions(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iDid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get data object
+ CFloat32Data3D* pData;
+ if (!(pData = CData3DManager::getSingleton().get(iDid))) {
+ mexErrMsgTxt("DataObject not valid. \n");
+ return;
+ }
+
+ // step3: output
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(pData->getWidth());
+ }
+ if (2 <= nlhs) {
+ plhs[1] = mxCreateDoubleScalar(pData->getHeight());
+ }
+ if (3 <= nlhs) {
+ plhs[2] = mxCreateDoubleScalar(pData->getDepth());
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [geom] = astra_mex_data3d('geometry', id);
+ */
+void astra_mex_data3d_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ //// Get input
+ //if (nrhs < 2) {
+ // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ // return;
+ //}
+ //int iDid = (int)(mxGetScalar(prhs[1]));
+
+ //// Get data object
+ //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+ //if (!pData) {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+
+ //// Projection Data
+ //if (pData->getType() == CFloat32Data3D::PROJECTION) {
+ // CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData);
+ // CProjectionGeometry3D* pProjGeom = pData2->getGeometry();
+ // XMLDocument* config = pProjGeom->toXML();
+
+ // if (1 <= nlhs) {
+ // plhs[0] = XML2struct(config);
+ // }
+ //}
+ //// Volume Data
+ //else if (pData->getType() == CFloat32Data3D::VOLUME) {
+ //// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData);
+ //// CVolumeGeometry2D* pVolGeom = pData2->getGeometry2D(iSliceNr);
+ //// if (1 <= nlhs) {
+ //// plhs[0] = createVolumeGeometryStruct(pVolGeom);
+ //// }
+ //}
+ //// Error
+ //else {
+ // mexErrMsgTxt("Type not valid. \n");
+ // return;
+ //}
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [geom_xml] = astra_mex_data3d('geometry_xml', id);
+ */
+void astra_mex_data3d_geometry_xml(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ //// Get input
+ //if (nrhs < 2) {
+ // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ // return;
+ //}
+ //int iDid = (int)(mxGetScalar(prhs[1]));
+
+ //// Get data object
+ //CFloat32Data3D* pData = CData3DManager::getSingleton().get(iDid);
+ //if (!pData) {
+ // mexErrMsgTxt("DataObject not valid. \n");
+ // return;
+ //}
+
+ //// Projection Data
+ //if (pData->getType() == CFloat32Data3D::PROJECTION) {
+ // CFloat32ProjectionData3D* pData2 = dynamic_cast<CFloat32ProjectionData3D*>(pData);
+ // CProjectionGeometry3D* pProjGeom = pData2->getGeometry();
+ // XMLDocument* config = pProjGeom->toXML();
+
+ // if (1 <= nlhs) {
+ // plhs[0] = mxCreateString(config->getRootNode()->toString().c_str());
+ // }
+ //}
+ //// Volume Data
+ //else if (pData->getType() == CFloat32Data3D::VOLUME) {
+ //// CFloat32VolumeData3D* pData2 = dynamic_cast<CFloat32VolumeData3D*>(pData);
+ //// CVolumeGeometry2D* pVolGeom = pData2->getGeometry2D(iSliceNr);
+ //// if (1 <= nlhs) {
+ //// plhs[0] = createVolumeGeometryStruct(pVolGeom);
+ //// }
+ //}
+ //// Error
+ //else {
+ // mexErrMsgTxt("Type not valid. \n");
+ // return;
+ //}
+}
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_data3d('delete', did1, did2, ...);
+ */
+void astra_mex_data3d_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ for (int i = 1; i < nrhs; i++) {
+ int iDataID = (int)(mxGetScalar(prhs[i]));
+ CData3DManager::getSingleton().remove(iDataID);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_data3d('clear');
+ */
+void astra_mex_data3d_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ CData3DManager::getSingleton().clear();
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_data3d('info');
+ */
+void astra_mex_data3d_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ mexPrintf("%s", astra::CData3DManager::getSingleton().info().c_str());
+}
+
+//-----------------------------------------------------------------------------------------
+
+static void printHelp()
+{
+ mexPrintf("Please specify a mode of operation.\n");
+ mexPrintf("Valid modes: create, create_cache, get, get_single, delete, clear, info\n");
+ mexPrintf(" fetch_projection, return_projection, fetch_slice[_z],\n");
+ mexPrintf(" return_slice[_z], fetch_slice_x, return slice_x\n");
+ mexPrintf(" fetch_slice_y, return slice_y, dimensions, geometry\n");
+ mexPrintf(" geometry_xml\n");
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * ... = astra_mex_io_data(mode,...);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+ int nrhs, const mxArray* prhs[])
+{
+
+ // INPUT: Mode
+ string sMode = "";
+ if (1 <= nrhs) {
+ sMode = mex_util_get_string(prhs[0]);
+ } else {
+ printHelp();
+ return;
+ }
+
+ // 3D data
+ if (sMode == std::string("create")) {
+ astra_mex_data3d_create(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("create_cache")) {
+ astra_mex_data3d_create_cache(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("get")) {
+ astra_mex_data3d_get(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("get_single")) {
+ astra_mex_data3d_get_single(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("store") ||
+ sMode == std::string("set")) {
+ astra_mex_data3d_store(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("delete")) {
+ astra_mex_data3d_delete(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "clear") {
+ astra_mex_data3d_clear(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "info") {
+ astra_mex_data3d_info(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("fetch_projection")) {
+ astra_mex_data3d_fetch_projection(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("return_projection")) {
+ astra_mex_data3d_return_projection(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("fetch_slice") || sMode == std::string("fetch_slice_z")) {
+ astra_mex_data3d_fetch_slice_z(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("return_slice") || sMode == std::string("return_slice_z")) {
+ astra_mex_data3d_return_slice_z(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("fetch_slice_x")) {
+ astra_mex_data3d_fetch_slice_x(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("return_slice_x")) {
+ astra_mex_data3d_return_slice_x(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("fetch_slice_y")) {
+ astra_mex_data3d_fetch_slice_y(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("return_slice_y")) {
+ astra_mex_data3d_return_slice_y(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("dimensions")) {
+ astra_mex_data3d_dimensions(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("geometry")) {
+ astra_mex_data3d_geometry(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("geometry_xml")) {
+ astra_mex_data3d_geometry_xml(nlhs, plhs, nrhs, prhs);
+ } else {
+ printHelp();
+ }
+
+ return;
+}
+
+
diff --git a/matlab/mex/astra_mex_data3d_vc08.vcproj b/matlab/mex/astra_mex_data3d_vc08.vcproj
new file mode 100644
index 0000000..2e69c16
--- /dev/null
+++ b/matlab/mex/astra_mex_data3d_vc08.vcproj
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="astra_mex_data3d"
+ ProjectGUID="{0BEC029B-0929-4BF9-BD8B-9C9806A52065}"
+ RootNamespace="astraMatlab"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\astra_mex_data3d_c.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/matlab/mex/astra_mex_matrix_c.cpp b/matlab/mex/astra_mex_matrix_c.cpp
new file mode 100644
index 0000000..accaab5
--- /dev/null
+++ b/matlab/mex/astra_mex_matrix_c.cpp
@@ -0,0 +1,437 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file astra_mex_matrix_c.cpp
+ *
+ * \brief Create sparse (projection) matrices in the ASTRA workspace
+ */
+#include <mex.h>
+#include "mexHelpFunctions.h"
+
+#include <list>
+
+#include "astra/Globals.h"
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/SparseMatrix.h"
+
+using namespace std;
+using namespace astra;
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_matrix('delete', id1, id2, ...);
+ *
+ * Delete one or more data objects currently stored in the astra-library.
+ * id1, id2, ... : identifiers of the 2d data objects as stored in the astra-library.
+ */
+void astra_mex_matrix_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ // step2: delete all specified data objects
+ for (int i = 1; i < nrhs; i++) {
+ int iDataID = (int)(mxGetScalar(prhs[i]));
+ CMatrixManager::getSingleton().remove(iDataID);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_matrix('clear');
+ *
+ * Delete all data objects currently stored in the astra-library.
+ */
+void astra_mex_matrix_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ CMatrixManager::getSingleton().clear();
+}
+
+
+
+static bool matlab_to_astra(const mxArray* _rhs, CSparseMatrix* _pMatrix)
+{
+ // Check input
+ if (!mxIsSparse (_rhs)) {
+ mexErrMsgTxt("Argument is not a valid MATLAB sparse matrix.\n");
+ return false;
+ }
+ if (!_pMatrix->isInitialized()) {
+ mexErrMsgTxt("Couldn't initialize data object.\n");
+ return false;
+ }
+
+ unsigned int iHeight = mxGetM(_rhs);
+ unsigned int iWidth = mxGetN(_rhs);
+ unsigned long lSize = mxGetNzmax(_rhs);
+
+ if (_pMatrix->m_lSize < lSize || _pMatrix->m_iHeight < iHeight) {
+ // TODO: support resizing?
+ mexErrMsgTxt("Matrix too large to store in this object.\n");
+ return false;
+ }
+
+ // Transpose matrix, as matlab stores a matrix column-by-column
+ // but we want it row-by-row.
+ // 1. Compute sizes of rows. We store these in _pMatrix->m_plRowStarts.
+ // 2. Fill data structure
+ // Complexity: O( #rows + #entries )
+
+ for (unsigned int i = 0; i <= iHeight; ++i)
+ _pMatrix->m_plRowStarts[i] = 0;
+
+ mwIndex *colStarts = mxGetJc(_rhs);
+ mwIndex *rowIndices = mxGetIr(_rhs);
+ double *floatValues = 0;
+ bool *boolValues = 0;
+ bool bLogical = mxIsLogical(_rhs);
+ if (bLogical)
+ boolValues = mxGetLogicals(_rhs);
+ else
+ floatValues = mxGetPr(_rhs);
+
+ for (mwIndex i = 0; i < colStarts[iWidth]; ++i) {
+ unsigned int iRow = rowIndices[i];
+ assert(iRow < iHeight);
+ _pMatrix->m_plRowStarts[iRow+1]++;
+ }
+
+ // Now _pMatrix->m_plRowStarts[i+1] is the number of entries in row i
+
+ for (unsigned int i = 1; i <= iHeight; ++i)
+ _pMatrix->m_plRowStarts[i] += _pMatrix->m_plRowStarts[i-1];
+
+ // Now _pMatrix->m_plRowStarts[i+1] is the number of entries in rows <= i,
+ // so the intended start of row i+1
+
+ int iCol = 0;
+ for (mwIndex i = 0; i < colStarts[iWidth]; ++i) {
+ while (i >= colStarts[iCol+1])
+ iCol++;
+
+ unsigned int iRow = rowIndices[i];
+ assert(iRow < iHeight);
+ float32 fVal;
+ if (bLogical)
+ fVal = (float32)boolValues[i];
+ else
+ fVal = (float32)floatValues[i];
+
+ unsigned long lIndex = _pMatrix->m_plRowStarts[iRow]++;
+ _pMatrix->m_pfValues[lIndex] = fVal;
+ _pMatrix->m_piColIndices[lIndex] = iCol;
+ }
+
+ // Now _pMatrix->m_plRowStarts[i] is the start of row i+1
+
+ for (unsigned int i = iHeight; i > 0; --i)
+ _pMatrix->m_plRowStarts[i] = _pMatrix->m_plRowStarts[i-1];
+ _pMatrix->m_plRowStarts[0] = 0;
+
+#if 0
+ // Debugging: dump matrix
+ for (unsigned int i = 0; i < iHeight; ++i) {
+ printf("Row %d: %ld-%ld\n", i, _pMatrix->m_plRowStarts[i], _pMatrix->m_plRowStarts[i+1]);
+ for (unsigned long j = _pMatrix->m_plRowStarts[i]; j < _pMatrix->m_plRowStarts[i+1]; ++j) {
+ printf("(%d,%d) = %f\n", i, _pMatrix->m_piColIndices[j], _pMatrix->m_pfValues[j]);
+ }
+ }
+#endif
+
+ return true;
+}
+
+static bool astra_to_matlab(const CSparseMatrix* _pMatrix, mxArray*& _lhs)
+{
+ if (!_pMatrix->isInitialized()) {
+ mexErrMsgTxt("Uninitialized data object.\n");
+ return false;
+ }
+
+ unsigned int iHeight = _pMatrix->m_iHeight;
+ unsigned int iWidth = _pMatrix->m_iWidth;
+ unsigned long lSize = _pMatrix->m_lSize;
+
+ _lhs = mxCreateSparse(iHeight, iWidth, lSize, mxREAL);
+ if (!mxIsSparse (_lhs)) {
+ mexErrMsgTxt("Couldn't initialize matlab sparse matrix.\n");
+ return false;
+ }
+
+ mwIndex *colStarts = mxGetJc(_lhs);
+ mwIndex *rowIndices = mxGetIr(_lhs);
+ double *floatValues = mxGetPr(_lhs);
+
+ for (unsigned int i = 0; i <= iWidth; ++i)
+ colStarts[i] = 0;
+
+ for (unsigned int i = 0; i < _pMatrix->m_plRowStarts[iHeight]; ++i) {
+ unsigned int iCol = _pMatrix->m_piColIndices[i];
+ assert(iCol < iWidth);
+ colStarts[iCol+1]++;
+ }
+ // Now _pMatrix->m_plRowStarts[i+1] is the number of entries in row i
+
+ for (unsigned int i = 1; i <= iWidth; ++i)
+ colStarts[i] += colStarts[i-1];
+ // Now _pMatrix->m_plRowStarts[i+1] is the number of entries in rows <= i,
+ // so the intended start of row i+1
+
+ unsigned int iRow = 0;
+ for (unsigned int i = 0; i < _pMatrix->m_plRowStarts[iHeight]; ++i) {
+ while (i >= _pMatrix->m_plRowStarts[iRow+1])
+ iRow++;
+
+ unsigned int iCol = _pMatrix->m_piColIndices[i];
+ assert(iCol < iWidth);
+ double fVal = _pMatrix->m_pfValues[i];
+ unsigned long lIndex = colStarts[iCol]++;
+ floatValues[lIndex] = fVal;
+ rowIndices[lIndex] = iRow;
+ }
+ // Now _pMatrix->m_plRowStarts[i] is the start of row i+1
+
+ for (unsigned int i = iWidth; i > 0; --i)
+ colStarts[i] = colStarts[i-1];
+ colStarts[0] = 0;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------------------
+/** id = astra_mex_matrix('create', data);
+ *
+ * Create a new matrix object in the astra-library.
+ * data: a sparse MATLAB matrix containing the data.
+ * id: identifier of the matrix object as it is now stored in the astra-library.
+ */
+void astra_mex_matrix_create(int& nlhs, mxArray* plhs[], int& nrhs, const mxArray* prhs[])
+{
+ // step1: get datatype
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ if (!mxIsSparse (prhs[1])) {
+ mexErrMsgTxt("Argument is not a valid MATLAB sparse matrix.\n");
+ return;
+ }
+
+ unsigned int iHeight = mxGetM(prhs[1]);
+ unsigned int iWidth = mxGetN(prhs[1]);
+ unsigned long lSize = mxGetNzmax(prhs[1]);
+
+ CSparseMatrix* pMatrix = new CSparseMatrix(iHeight, iWidth, lSize);
+
+ // Check initialization
+ if (!pMatrix->isInitialized()) {
+ mexErrMsgTxt("Couldn't initialize data object.\n");
+ delete pMatrix;
+ return;
+ }
+
+ bool bResult = matlab_to_astra(prhs[1], pMatrix);
+
+ if (!bResult) {
+ mexErrMsgTxt("Failed to create data object.\n");
+ delete pMatrix;
+ return;
+ }
+
+ // store data object
+ int iIndex = CMatrixManager::getSingleton().store(pMatrix);
+
+ // return data id
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(iIndex);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_matrix('store', id, data);
+ *
+ * Store a sparse MATLAB matrix in an existing astra matrix dataobject.
+ * id: identifier of the 2d data object as stored in the astra-library.
+ * data: a sparse MATLAB matrix.
+ */
+void astra_mex_matrix_store(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: input
+ if (nrhs < 3) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ if (!mxIsDouble(prhs[1])) {
+ mexErrMsgTxt("Identifier should be a scalar value. \n");
+ return;
+ }
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get data object
+ CSparseMatrix* pMatrix = astra::CMatrixManager::getSingleton().get(iDataID);
+ if (!pMatrix || !pMatrix->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ bool bResult = matlab_to_astra(prhs[2], pMatrix);
+ if (!bResult) {
+ mexErrMsgTxt("Failed to store matrix.\n");
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** geom = astra_mex_matrix('get_size', id);
+ *
+ * Fetch the dimensions and size of a matrix stored in the astra-library.
+ * id: identifier of the 2d data object as stored in the astra-library.
+ * geom: a 1x2 matrix containing [rows, columns]
+ */
+void astra_mex_matrix_get_size(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ if (!mxIsDouble(prhs[1])) {
+ mexErrMsgTxt("Identifier should be a scalar value. \n");
+ return;
+ }
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get data object
+ CSparseMatrix* pMatrix = astra::CMatrixManager::getSingleton().get(iDataID);
+ if (!pMatrix || !pMatrix->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ // create output
+ // TODO
+}
+
+//-----------------------------------------------------------------------------------------
+/** data = astra_mex_matrix('get', id);
+ *
+ * Fetch data from the astra-library to a MATLAB matrix.
+ * id: identifier of the matrix data object as stored in the astra-library.
+ * data: MATLAB
+ */
+void astra_mex_matrix_get(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: check input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ if (!mxIsDouble(prhs[1])) {
+ mexErrMsgTxt("Identifier should be a scalar value. \n");
+ return;
+ }
+ int iDataID = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get data object
+ CSparseMatrix* pMatrix = astra::CMatrixManager::getSingleton().get(iDataID);
+ if (!pMatrix || !pMatrix->isInitialized()) {
+ mexErrMsgTxt("Data object not found or not initialized properly.\n");
+ return;
+ }
+
+ // create output
+ if (1 <= nlhs) {
+ bool bResult = astra_to_matlab(pMatrix, plhs[0]);
+ if (!bResult) {
+ mexErrMsgTxt("Failed to get matrix.\n");
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_matrix('info');
+ *
+ * Print information about all the matrix objects currently stored in the astra-library.
+ */
+void astra_mex_matrix_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ mexPrintf("%s", astra::CMatrixManager::getSingleton().info().c_str());
+}
+
+//-----------------------------------------------------------------------------------------
+
+static void printHelp()
+{
+ mexPrintf("Please specify a mode of operation.\n");
+ mexPrintf("Valid modes: get, delete, clear, store, create, get_size, info\n");
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * ... = astra_mex_matrix(type,...);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+ int nrhs, const mxArray* prhs[])
+{
+
+ // INPUT0: Mode
+ string sMode = "";
+ if (1 <= nrhs) {
+ sMode = mex_util_get_string(prhs[0]);
+ } else {
+ printHelp();
+ return;
+ }
+
+ // SWITCH (MODE)
+ if (sMode == std::string("get")) {
+ astra_mex_matrix_get(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("delete")) {
+ astra_mex_matrix_delete(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "clear") {
+ astra_mex_matrix_clear(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("store")) {
+ astra_mex_matrix_store(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("create")) {
+ astra_mex_matrix_create(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("get_size")) {
+ astra_mex_matrix_get_size(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == std::string("info")) {
+ astra_mex_matrix_info(nlhs, plhs, nrhs, prhs);
+ } else {
+ printHelp();
+ }
+
+ return;
+}
+
+
diff --git a/matlab/mex/astra_mex_matrix_vc08.vcproj b/matlab/mex/astra_mex_matrix_vc08.vcproj
new file mode 100644
index 0000000..47509f6
--- /dev/null
+++ b/matlab/mex/astra_mex_matrix_vc08.vcproj
@@ -0,0 +1,591 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="astra_mex_matrix"
+ ProjectGUID="{9D041710-2119-4230-BCF2-5FBE753FDE49}"
+ RootNamespace="astraMatlab"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(CUDA_INC_PATH)&quot;;$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ BrowseInformation="1"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\astra_mex_matrix_c.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/matlab/mex/astra_mex_projector3d_c.cpp b/matlab/mex/astra_mex_projector3d_c.cpp
new file mode 100644
index 0000000..1385863
--- /dev/null
+++ b/matlab/mex/astra_mex_projector3d_c.cpp
@@ -0,0 +1,433 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file astra_mex_projector3d_c.cpp
+ *
+ * \brief Create and manage 3d projectors in the ASTRA workspace
+ */
+
+#include <mex.h>
+#include "mexHelpFunctions.h"
+
+#include "astra/Globals.h"
+
+#include "astra/Projector3D.h"
+#include "astra/AstraObjectManager.h"
+#include "astra/AstraObjectFactory.h"
+
+#include "astra/ProjectionGeometry3D.h"
+#include "astra/VolumeGeometry3D.h"
+
+#include <map>
+#include <vector>
+
+using namespace std;
+using namespace astra;
+
+//-----------------------------------------------------------------------------------------
+/**
+* [pid] = astra_mex_projector('create', cfgstruct);
+*/
+void astra_mex_projector3d_create(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ if (!mxIsStruct(prhs[1])) {
+ mexErrMsgTxt("Argument 1 not a valid MATLAB struct. \n");
+ }
+
+ // turn MATLAB struct to an XML-based Config object
+ XMLDocument* xml = struct2XML("Projector3D", prhs[1]);
+ Config cfg;
+ cfg.self = xml->getRootNode();
+
+ // create algorithm
+ CProjector3D* pProj = CProjector3DFactory::getSingleton().create(cfg);
+ if (pProj == NULL) {
+ mexErrMsgTxt("Error creating Projector3D. \n");
+ return;
+ }
+
+ // store projector
+ int iIndex = CProjector3DManager::getSingleton().store(pProj);
+
+ // step4: set output
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(iIndex);
+ }
+
+ }
+
+//-----------------------------------------------------------------------------------------
+/**
+* astra_mex_projector3d('destroy', pid1, pid2, ...);
+*/
+void astra_mex_projector3d_destroy(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ for (int i = 1; i < nrhs; i++) {
+ int iPid = (int)(mxGetScalar(prhs[i]));
+ CProjector3DManager::getSingleton().remove(iPid);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_projector3d('clear');
+ */
+void astra_mex_projector3d_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ CProjector3DManager::getSingleton().clear();
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+* [proj_geom] = astra_mex_projector3d('get_projection_geometry', pid);
+*/
+void astra_mex_projector3d_get_projection_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get projector
+ CProjector3D* pProjector;
+ if (!(pProjector = CProjector3DManager::getSingleton().get(iPid))) {
+ mexErrMsgTxt("Projector not found.\n");
+ return;
+ }
+
+ // step3: get projection_geometry and turn it into a MATLAB struct
+ //if (1 <= nlhs) {
+ // plhs[0] = createProjectionGeometryStruct(pProjector->getProjectionGeometry());
+ //}
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+* [recon_geom] = astra_mex_projector3d('get_volume_geometry', pid);
+*/
+void astra_mex_projector3d_get_reconstruction_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get projector
+ CProjector3D* pProjector;
+ if (!(pProjector = CProjector3DManager::getSingleton().get(iPid))) {
+ mexErrMsgTxt("Projector not found.\n");
+ return;
+ }
+
+ // step3: get projection_geometry and turn it into a MATLAB struct
+ //if (1 <= nlhs) {
+ // plhs[0] = createVolumeGeometryStruct(pProjector->getVolumeGeometry());
+ //}
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+* [weights] = astra_mex_projector3d('weights_single_ray', pid, projection_index, detector_index);
+*/
+void astra_mex_projector_weights_single_ray(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ //// step1: get input
+ //if (nrhs < 4) {
+ // mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ // return;
+ //}
+ //int iPid = (int)(mxGetScalar(prhs[1]));
+ //int iProjectionIndex = (int)(mxGetScalar(prhs[2]));
+ //int iDetectorIndex = (int)(mxGetScalar(prhs[3]));
+
+ //// step2: get projector
+ //CProjector3D* pProjector;
+ //if (!(pProjector = CProjector3DManager::getSingleton().get(iPid))) {
+ // mexErrMsgTxt("Projector not found.\n");
+ // return;
+ //}
+ //
+ //// step3: create output vars
+ //int iStoredPixelCount;
+ //int iMaxPixelCount = pProjector->getProjectionWeightsCount(iProjectionIndex);
+ //SWeightedPixel* pPixelsWeights = new SWeightedPixel3D[iMaxPixelCount];
+ //
+ //// step4: perform operation
+ //pProjector->computeSingleRayWeights(iProjectionIndex,
+ // iDetectorIndex,
+ // pPixelsWeights,
+ // iMaxPixelCount,
+ // iStoredPixelCount);
+
+ //// step5: return output
+ //if (1 <= nlhs) {
+ // mwSize dims[2];
+ // dims[0] = iStoredPixelCount;
+ // dims[1] = 2;
+
+ // plhs[0] = mxCreateNumericArray(2, dims, mxDOUBLE_CLASS, mxREAL);
+ // double* out = mxGetPr(plhs[0]);
+
+ // for (int col = 0; col < iStoredPixelCount; col++) {
+ // out[col] = pPixelsWeights[col].m_iIndex;
+ // out[iStoredPixelCount+col] = pPixelsWeights[col].m_fWeight;
+ // //cout << pPixelsWeights[col].m_iIndex << " " << pPixelsWeights[col].m_fWeight <<endl;
+ // }
+ //}
+ //
+ //// garbage collection
+ //delete[] pPixelsWeights;
+}
+
+////-----------------------------------------------------------------------------------------
+///**
+//* [weights] = astra_mex_projector('weights_projection', pid, projection_index);
+//*/
+//void astra_mex_projector_weights_projection(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+//{
+// // step1: get input
+// if (nrhs < 3) {
+// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+// return;
+// }
+// int iPid = (int)(mxGetScalar(prhs[1]));
+// int iProjectionIndex = (int)(mxGetScalar(prhs[2]));
+//
+// // step2: get projector
+// CProjector2D* pProjector;
+// if (!(pProjector = CProjectorManager::getSingleton().get(iPid))) {
+// mexErrMsgTxt("Projector not found.\n");
+// return;
+// }
+//
+// // step3: create output vars
+// SWeightedPixel2D* pPixelsWheights = new SWeightedPixel2D[pProjector->getProjectionWeightsCount(iProjectionIndex)];
+// int* piRayStoredPixelCount = new int[pProjector->getProjectionGeometry()->getDetectorCount()];
+//
+// // step4: perform operation
+// pProjector->computeProjectionRayWeights(iProjectionIndex, pPixelsWheights, piRayStoredPixelCount);
+//
+// // step5: return output
+// if (1 <= nlhs) {
+// // get basic values
+// int iMatrixSize = pProjector->getVolumeGeometry()->getWindowLengthX() *
+// pProjector->getVolumeGeometry()->getWindowLengthY();
+// int iDetectorCount = pProjector->getProjectionGeometry()->getDetectorCount();
+// int iTotalStoredPixelCount = 0;
+// for (int i = 0; i < iDetectorCount; i++) {
+// iTotalStoredPixelCount += piRayStoredPixelCount[i];
+// }
+//
+// // create matlab sparse matrix
+// plhs[0] = mxCreateSparse(iMatrixSize, // number of rows (#pixels)
+// iDetectorCount, // number of columns (#detectors)
+// iTotalStoredPixelCount, // number of non-zero elements
+// mxREAL); // element type
+// double* values = mxGetPr(plhs[0]);
+// mwIndex* rows = mxGetIr(plhs[0]);
+// mwIndex* cols = mxGetJc(plhs[0]);
+//
+// int currentBase = 0;
+// int currentIndex = 0;
+// for (int i = 0; i < iDetectorCount; i++) {
+// for (int j = 0; j < piRayStoredPixelCount[i]; j++) {
+// values[currentIndex + j] = pPixelsWheights[currentBase + j].m_fWeight;
+// rows[currentIndex + j] = pPixelsWheights[currentBase + j].m_iIndex;
+// }
+//
+// currentBase += pProjector->getProjectionWeightsCount(iProjectionIndex) / pProjector->getProjectionGeometry()->getDetectorCount();
+// currentIndex += piRayStoredPixelCount[i];
+// }
+// cols[0] = piRayStoredPixelCount[0];
+// for (int j = 1; j < iDetectorCount; j++) {
+// cols[j] = cols[j-1] + piRayStoredPixelCount[j];
+// }
+// cols[iDetectorCount] = iTotalStoredPixelCount;
+// }
+//
+//}
+//
+////-----------------------------------------------------------------------------------------
+///**
+//* output = astra_mex_projector('splat', pid, x, y);
+//*/
+//void astra_mex_projector_splat(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+//{
+// // step1: get input
+// if (nrhs < 4) {
+// mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+// return;
+// }
+// int iPid = (int)(mxGetScalar(prhs[1]));
+// int iX = (int)(mxGetScalar(prhs[2]));
+// int iY = (int)(mxGetScalar(prhs[3]));
+//
+// // step2: get projector
+// CProjector2D* pProjector;
+// if (!(pProjector = CProjectorManager::getSingleton().get(iPid))) {
+// mexErrMsgTxt("Projector not found.\n");
+// return;
+// }
+//
+// // step3: perform action
+// vector<SDetector2D> detinfo = pProjector->projectPoint(iX, iY);
+//
+// // step4: output
+// if (nlhs <= 1) {
+// plhs[0] = mxCreateDoubleMatrix(detinfo.size(), // # rows
+// 2, // # cols
+// mxREAL); // datatype 32-bits
+// double* out = mxGetPr(plhs[0]);
+//
+// // fill up output
+// int i = 0;
+// for (int x = 0; x < detinfo.size() ; x++) {
+// out[i] = detinfo[x].m_iAngleIndex;
+// i++;
+// }
+// for (int x = 0; x < detinfo.size() ; x++) {
+// out[i] = detinfo[x].m_iDetectorIndex;
+// i++;
+// }
+// }
+//
+//
+//}
+
+//-----------------------------------------------------------------------------------------
+/** result = astra_mex_projector3d('is_cuda', id);
+ *
+ * Return is the specified projector is a cuda projector.
+ * id: identifier of the projector object as stored in the astra-library.
+ */
+void astra_mex_projector3d_is_cuda(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get projector
+ CProjector3D* pProjector = CProjector3DManager::getSingleton().get(iPid);
+ if (!pProjector || !pProjector->isInitialized()) {
+ mexErrMsgTxt("Projector not initialized.\n");
+ return;
+ }
+
+#ifdef ASTRA_CUDA
+ CCudaProjector3D* pCP = dynamic_cast<CCudaProjector3D*>(pProjector);
+ plhs[0] = mxCreateLogicalScalar(pCP ? 1 : 0);
+#else
+ plhs[0] = mxCreateLogicalScalar(0);
+#endif
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * astra_mex_projector3d('help');
+ */
+void astra_mex_projector3d_help(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ cout << "astra_mex_projector3d help:" <<endl;
+ cout << "---------------------------" <<endl;
+}
+
+
+//-----------------------------------------------------------------------------------------
+
+static void printHelp()
+{
+ mexPrintf("Please specify a mode of operation.\n");
+ mexPrintf("Valid modes: create, delete, clear, get_projection_geometry,\n");
+ mexPrintf(" get_volume_geometry, weights_single_ray, weights_projection\n");
+ mexPrintf(" splat, is_cuda\n");
+}
+
+//-----------------------------------------------------------------------------------------
+/**
+ * [pid] = astra_mex_projector('read', projection_geometry, reconstruction_geometry);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+ int nrhs, const mxArray* prhs[])
+{
+ // INPUT: Mode
+ string sMode = "";
+ if (1 <= nrhs) {
+ sMode = mex_util_get_string(prhs[0]);
+ } else {
+ printHelp();
+ return;
+ }
+
+ // SWITCH (MODE)
+ if (sMode == "create") {
+ astra_mex_projector3d_create(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "delete") {
+ astra_mex_projector3d_destroy(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "clear") {
+ astra_mex_projector3d_clear(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "get_projection_geometry") {
+ astra_mex_projector3d_get_projection_geometry(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "get_volume_geometry") {
+ astra_mex_projector3d_get_reconstruction_geometry(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "weights_single_ray") {
+ astra_mex_projector_weights_single_ray(nlhs, plhs, nrhs, prhs);
+ //} else if (sMode == "weights_projection") {
+ // astra_mex_projector_weights_projection(nlhs, plhs, nrhs, prhs);
+ //} else if (sMode == "splat") {
+ // astra_mex_projector_splat(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "is_cuda") {
+ astra_mex_projector3d_is_cuda(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "help") {
+ astra_mex_projector3d_help(nlhs, plhs, nrhs, prhs);
+ } else {
+ printHelp();
+ }
+ return;
+}
+
+
diff --git a/matlab/mex/astra_mex_projector3d_vc08.vcproj b/matlab/mex/astra_mex_projector3d_vc08.vcproj
new file mode 100644
index 0000000..bedc53b
--- /dev/null
+++ b/matlab/mex/astra_mex_projector3d_vc08.vcproj
@@ -0,0 +1,588 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="astra_mex_projector3d"
+ ProjectGUID="{F94CCD79-AA11-42DF-AC8A-6C9D2238A883}"
+ RootNamespace="astraMatlab"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\astra_mex_projector3d_c.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/matlab/mex/astra_mex_projector_c.cpp b/matlab/mex/astra_mex_projector_c.cpp
new file mode 100644
index 0000000..5cbe502
--- /dev/null
+++ b/matlab/mex/astra_mex_projector_c.cpp
@@ -0,0 +1,510 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file astra_mex_projector_c.cpp
+ *
+ * \brief Create and manage 2d projectors in the ASTRA workspace
+ */
+#include "astra/Globals.h"
+
+#include <mex.h>
+#include "mexHelpFunctions.h"
+
+#include "astra/AstraObjectManager.h"
+#include "astra/Projector2D.h"
+#include "astra/AstraObjectFactory.h"
+
+#include "astra/Float32VolumeData2D.h"
+
+#include "astra/ProjectionGeometry2D.h"
+#include "astra/ParallelProjectionGeometry2D.h"
+#include "astra/VolumeGeometry2D.h"
+
+
+#include <map>
+#include <vector>
+
+using namespace std;
+using namespace astra;
+
+//-----------------------------------------------------------------------------------------
+/** id = astra_mex_projector('create', cfg);
+ *
+ * Create and configure a new projector object.
+ * cfg: MATLAB struct containing the configuration parameters, see doxygen documentation for details.
+ * id: identifier of the projector object as it is now stored in the astra-library.
+ */
+void astra_mex_projector_create(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ int iIndex = 0;
+
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ if (!mxIsStruct(prhs[1])) {
+ mexErrMsgTxt("Argument 1 not a valid MATLAB struct. \n");
+ }
+
+
+ // turn MATLAB struct to an XML-based Config object
+ XMLDocument* xml = struct2XML("Projector2D", prhs[1]);
+ Config cfg;
+ cfg.self = xml->getRootNode();
+
+ // create algorithm
+ CProjector2D* pProj = CProjector2DFactory::getSingleton().create(cfg);
+ if (pProj == NULL) {
+ delete xml;
+ mexErrMsgTxt("Error creating projector. \n");
+ return;
+ }
+
+ delete xml;
+
+ // store projector
+ iIndex = CProjector2DManager::getSingleton().store(pProj);
+
+ // step4: set output
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(iIndex);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_projector('delete', id1, id2, ...);
+ *
+ * Delete one or more projector objects currently stored in the astra-library.
+ * id1, id2, ... : identifiers of the projector objects as stored in the astra-library.
+ */
+void astra_mex_projector_delete(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+
+ for (int i = 1; i < nrhs; i++) {
+ int iPid = (int)(mxGetScalar(prhs[i]));
+ CProjector2DManager::getSingleton().remove(iPid);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_projector('clear');
+ *
+ * Delete all projector objects currently stored in the astra-library.
+ */
+void astra_mex_projector_clear(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ CProjector2DManager::getSingleton().clear();
+}
+
+//-----------------------------------------------------------------------------------------
+/** astra_mex_projector('info');
+ *
+ * Print information about all the projector objects currently stored in the astra-library.
+ */
+void astra_mex_projector_info(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ mexPrintf("%s", astra::CProjector2DManager::getSingleton().info().c_str());
+}
+
+//-----------------------------------------------------------------------------------------
+/** proj_geom = astra_mex_projector('projection_geometry', id);
+ *
+ * Fetch the projection geometry of a certain projector.
+ * id: identifier of the projector object as stored in the astra-library.
+ * proj_geom: MATLAB struct containing all information about the projection geometry
+*/
+void astra_mex_projector_projection_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get projector
+ CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid);
+ if (!pProjector || !pProjector->isInitialized()) {
+ mexErrMsgTxt("Projector not initialized.\n");
+ return;
+ }
+
+ // step3: get projection_geometry and turn it into a MATLAB struct
+ if (1 <= nlhs) {
+ plhs[0] = createProjectionGeometryStruct(pProjector->getProjectionGeometry());
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** vol_geom = astra_mex_projector('volume_geometry', id);
+ *
+ * Fetch the volume geometry of a certain projector.
+ * id: identifier of the projector object as stored in the astra-library.
+ * vol_geom: MATLAB struct containing all information about the volume geometry
+ */
+void astra_mex_projector_volume_geometry(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: read input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get projector
+ CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid);
+ if (!pProjector || !pProjector->isInitialized()) {
+ mexErrMsgTxt("Projector not initialized.\n");
+ return;
+ }
+
+ // step3: get projection_geometry and turn it into a MATLAB struct
+ if (1 <= nlhs) {
+ plhs[0] = createVolumeGeometryStruct(pProjector->getVolumeGeometry());
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** weights = astra_mex_projector('weights_single_ray', id, projection_index, detector_index);
+ *
+ * Calculate the nonzero weights of a certain projection ray.
+ * id: identifier of the projector object as stored in the astra-library.
+ * projection_index: index of the projection angle
+ * detector_index: index of the detector
+ * weights: list of computed weights [pixel_index, weight]
+ */
+void astra_mex_projector_weights_single_ray(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 4) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+ int iProjectionIndex = (int)(mxGetScalar(prhs[2]));
+ int iDetectorIndex = (int)(mxGetScalar(prhs[3]));
+
+ // step2: get projector
+ CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid);
+ if (!pProjector || !pProjector->isInitialized()) {
+ mexErrMsgTxt("Projector not initialized.\n");
+ return;
+ }
+
+ // step3: create output vars
+ int iStoredPixelCount;
+ int iMaxPixelCount = pProjector->getProjectionWeightsCount(iProjectionIndex);
+ SPixelWeight* pPixelsWeights = new SPixelWeight[iMaxPixelCount];
+
+ // step4: perform operation
+ pProjector->computeSingleRayWeights(iProjectionIndex,
+ iDetectorIndex,
+ pPixelsWeights,
+ iMaxPixelCount,
+ iStoredPixelCount);
+
+ // step5: return output
+ if (1 <= nlhs) {
+ mwSize dims[2];
+ dims[0] = iStoredPixelCount;
+ dims[1] = 2;
+
+ plhs[0] = mxCreateNumericArray(2, dims, mxDOUBLE_CLASS, mxREAL);
+ double* out = mxGetPr(plhs[0]);
+
+ for (int col = 0; col < iStoredPixelCount; col++) {
+ out[col] = pPixelsWeights[col].m_iIndex;
+ out[iStoredPixelCount+col] = pPixelsWeights[col].m_fWeight;
+ }
+ }
+
+ // garbage collection
+ delete[] pPixelsWeights;
+}
+
+//-----------------------------------------------------------------------------------------
+/** weights = astra_mex_projector('weights_projection', id, projection_index);
+ *
+ * Calculate the nonzero weights of all rays in a certain projection.
+ * id: identifier of the projector object as stored in the astra-library.
+ * projection_index: index of the projection angle
+ * weights: sparse matrix containing the rows of the projection matric belonging to the requested projection angle.
+ */
+void astra_mex_projector_weights_projection(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 3) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+ int iProjectionIndex = (int)(mxGetScalar(prhs[2]));
+
+ // step2: get projector
+ CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid);
+ if (!pProjector || !pProjector->isInitialized()) {
+ mexErrMsgTxt("Projector not initialized.\n");
+ return;
+ }
+
+ // step3: create output vars
+ SPixelWeight* pPixelsWheights = new SPixelWeight[pProjector->getProjectionWeightsCount(iProjectionIndex)];
+ int* piRayStoredPixelCount = new int[pProjector->getProjectionGeometry()->getDetectorCount()];
+
+ // step4: perform operation
+ pProjector->computeProjectionRayWeights(iProjectionIndex, pPixelsWheights, piRayStoredPixelCount);
+
+ // step5: return output
+ if (1 <= nlhs) {
+ // get basic values
+ int iMatrixSize = pProjector->getVolumeGeometry()->getWindowLengthX() *
+ pProjector->getVolumeGeometry()->getWindowLengthY();
+ int iDetectorCount = pProjector->getProjectionGeometry()->getDetectorCount();
+ int iTotalStoredPixelCount = 0;
+ for (int i = 0; i < iDetectorCount; i++) {
+ iTotalStoredPixelCount += piRayStoredPixelCount[i];
+ }
+
+ // create matlab sparse matrix
+ plhs[0] = mxCreateSparse(iMatrixSize, // number of rows (#pixels)
+ iDetectorCount, // number of columns (#detectors)
+ iTotalStoredPixelCount, // number of non-zero elements
+ mxREAL); // element type
+ double* values = mxGetPr(plhs[0]);
+ mwIndex* rows = mxGetIr(plhs[0]);
+ mwIndex* cols = mxGetJc(plhs[0]);
+
+ int currentBase = 0;
+ int currentIndex = 0;
+ for (int i = 0; i < iDetectorCount; i++) {
+ for (int j = 0; j < piRayStoredPixelCount[i]; j++) {
+ values[currentIndex + j] = pPixelsWheights[currentBase + j].m_fWeight;
+ rows[currentIndex + j] = pPixelsWheights[currentBase + j].m_iIndex;
+ }
+
+ currentBase += pProjector->getProjectionWeightsCount(iProjectionIndex) / pProjector->getProjectionGeometry()->getDetectorCount();
+ currentIndex += piRayStoredPixelCount[i];
+ }
+ cols[0] = piRayStoredPixelCount[0];
+ for (int j = 1; j < iDetectorCount; j++) {
+ cols[j] = cols[j-1] + piRayStoredPixelCount[j];
+ }
+ cols[iDetectorCount] = iTotalStoredPixelCount;
+ }
+
+ delete[] pPixelsWheights;
+ delete[] piRayStoredPixelCount;
+}
+
+//-----------------------------------------------------------------------------------------
+/** hit_detectors = astra_mex_projector('splat', id, col, row);
+ *
+ * Create a list of detector indices which have a nonzero contribution to the projection matrix for a pixel [row,col].
+ * id: identifier of the projector object as stored in the astra-library.
+ * col: column of the pixel
+ * row: row of the pixel
+ * hit_detectors: list of detector indices [angle_index, det_index] that are hit
+ */
+void astra_mex_projector_splat(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 4) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+ int iX = (int)(mxGetScalar(prhs[2]));
+ int iY = (int)(mxGetScalar(prhs[3]));
+
+ // step2: get projector
+ CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid);
+ if (!pProjector || !pProjector->isInitialized()) {
+ mexErrMsgTxt("Projector not initialized.\n");
+ return;
+ }
+
+ // step3: perform action
+ vector<SDetector2D> detinfo = pProjector->projectPoint(iX, iY);
+
+ // step4: output
+ if (nlhs <= 1) {
+ plhs[0] = mxCreateDoubleMatrix(detinfo.size(), // # rows
+ 2, // # cols
+ mxREAL); // datatype 32-bits
+ double* out = mxGetPr(plhs[0]);
+
+ // fill up output
+ int i = 0;
+ int x;
+ for (x = 0; x < detinfo.size(); ++x) {
+ out[i] = detinfo[x].m_iAngleIndex;
+ ++i;
+ }
+ for (x = 0; x < detinfo.size(); ++x) {
+ out[i] = detinfo[x].m_iDetectorIndex;
+ ++i;
+ }
+ }
+
+
+}
+
+//-----------------------------------------------------------------------------------------
+/** matrix_id = astra_mex_projector('matrix', id);
+ *
+ * Create an explicit projection matrix for this projector.
+ * It returns an ID usable with astra_mex_matrix().
+ * id: identifier of the projector object as stored in the astra-library.
+ */
+void astra_mex_projector_matrix(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get projector
+ CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid);
+ if (!pProjector || !pProjector->isInitialized()) {
+ mexErrMsgTxt("Projector not initialized.\n");
+ return;
+ }
+
+ CSparseMatrix* pMatrix = pProjector->getMatrix();
+ if (!pMatrix || !pMatrix->isInitialized()) {
+ mexErrMsgTxt("Couldn't initialize data object.\n");
+ delete pMatrix;
+ return;
+ }
+
+ // store data object
+ int iIndex = CMatrixManager::getSingleton().store(pMatrix);
+
+ // return data id
+ if (1 <= nlhs) {
+ plhs[0] = mxCreateDoubleScalar(iIndex);
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+/** result = astra_mex_projector('is_cuda', id);
+ *
+ * Return is the specified projector is a cuda projector.
+ * id: identifier of the projector object as stored in the astra-library.
+ */
+void astra_mex_projector_is_cuda(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
+{
+ // step1: get input
+ if (nrhs < 2) {
+ mexErrMsgTxt("Not enough arguments. See the help document for a detailed argument list. \n");
+ return;
+ }
+ int iPid = (int)(mxGetScalar(prhs[1]));
+
+ // step2: get projector
+ CProjector2D* pProjector = CProjector2DManager::getSingleton().get(iPid);
+ if (!pProjector || !pProjector->isInitialized()) {
+ mexErrMsgTxt("Projector not initialized.\n");
+ return;
+ }
+
+#ifdef ASTRA_CUDA
+ CCudaProjector2D* pCP = dynamic_cast<CCudaProjector2D*>(pProjector);
+ plhs[0] = mxCreateLogicalScalar(pCP ? 1 : 0);
+#else
+ plhs[0] = mxCreateLogicalScalar(0);
+#endif
+}
+
+
+
+//-----------------------------------------------------------------------------------------
+
+static void printHelp()
+{
+ mexPrintf("Please specify a mode of operation.\n");
+ mexPrintf("Valid modes: create, delete, clear, info, projection_geometry,\n");
+ mexPrintf(" volume_geometry, weights_single_ray, weights_projection\n");
+ mexPrintf(" splat, matrix, is_cuda\n");
+}
+
+
+//-----------------------------------------------------------------------------------------
+/**
+ * ... = astra_mex_projector(mode, ...);
+ */
+void mexFunction(int nlhs, mxArray* plhs[],
+ int nrhs, const mxArray* prhs[])
+{
+ // INPUT: Mode
+ string sMode = "";
+ if (1 <= nrhs) {
+ sMode = mex_util_get_string(prhs[0]);
+ } else {
+ printHelp();
+ return;
+ }
+
+ // SWITCH (MODE)
+ if (sMode == "create") {
+ astra_mex_projector_create(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "delete") {
+ astra_mex_projector_delete(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "clear") {
+ astra_mex_projector_clear(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "info") {
+ astra_mex_projector_info(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "projection_geometry") {
+ astra_mex_projector_projection_geometry(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "volume_geometry") {
+ astra_mex_projector_volume_geometry(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "weights_single_ray") {
+ astra_mex_projector_weights_single_ray(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "weights_projection") {
+ astra_mex_projector_weights_projection(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "splat") {
+ astra_mex_projector_splat(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "matrix") {
+ astra_mex_projector_matrix(nlhs, plhs, nrhs, prhs);
+ } else if (sMode == "is_cuda") {
+ astra_mex_projector_is_cuda(nlhs, plhs, nrhs, prhs);
+ } else {
+ printHelp();
+ }
+ return;
+}
+
+
diff --git a/matlab/mex/astra_mex_projector_vc08.vcproj b/matlab/mex/astra_mex_projector_vc08.vcproj
new file mode 100644
index 0000000..1380061
--- /dev/null
+++ b/matlab/mex/astra_mex_projector_vc08.vcproj
@@ -0,0 +1,591 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="astra_mex_projector"
+ ProjectGUID="{4DD6056F-8EEE-4C9A-B2A9-923F01A32E97}"
+ RootNamespace="astraMatlab"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="&quot;$(MATLAB_ROOT)\extern\include\&quot;;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ BrowseInformation="1"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\astra_mex_projector_c.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/matlab/mex/astra_mex_vc08.vcproj b/matlab/mex/astra_mex_vc08.vcproj
new file mode 100644
index 0000000..58c1e0a
--- /dev/null
+++ b/matlab/mex/astra_mex_vc08.vcproj
@@ -0,0 +1,591 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="astra_mex"
+ ProjectGUID="{3FDA35E0-0D54-4663-A3E6-5ABA96F32221}"
+ RootNamespace="astraMatlab"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;&quot;$(CUDA_INC_PATH)&quot;;..\..\lib\include;..\..\lib\include\cuda;..\..\include\;"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="2"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;$(CUDA_INC_PATH)&quot;;$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ PreprocessorDefinitions="ASTRA_CUDA"
+ RuntimeLibrary="3"
+ BrowseInformation="1"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64D.lib libmex.lib libmx.lib libut.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw32"
+ AdditionalLibraryDirectories="..\..\bin\win32;$(MATLAB_ROOT)\extern\lib\win32\microsoft"
+ ModuleDefinitionFile="mex.def"
+ GenerateDebugInformation="true"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)bin\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\$(ProjectName)"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(MATLAB_ROOT)\extern\include\;..\..\lib\include;..\..\include"
+ RuntimeLibrary="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64D.lib libmex.lib libmx.lib"
+ OutputFile="$(OutDir)\$(ProjectName)_c.mexw64"
+ AdditionalLibraryDirectories="..\..\bin\x64;$(MATLAB_ROOT)\extern\lib\win64\microsoft"
+ ModuleDefinitionFile="mex.def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\astra_mex_c.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mexHelpFunctions.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/matlab/mex/mex.def b/matlab/mex/mex.def
new file mode 100644
index 0000000..c54c4e0
--- /dev/null
+++ b/matlab/mex/mex.def
@@ -0,0 +1 @@
+EXPORTS mexFunction \ No newline at end of file
diff --git a/matlab/mex/mexHelpFunctions.cpp b/matlab/mex/mexHelpFunctions.cpp
new file mode 100644
index 0000000..4105ee1
--- /dev/null
+++ b/matlab/mex/mexHelpFunctions.cpp
@@ -0,0 +1,642 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+/** \file mexHelpFunctions.cpp
+ *
+ * \brief Contains some functions for interfacing matlab with c data structures
+ */
+#include "mexHelpFunctions.h"
+
+#include "astra/SparseMatrixProjectionGeometry2D.h"
+#include "astra/FanFlatVecProjectionGeometry2D.h"
+#include "astra/AstraObjectManager.h"
+
+using namespace std;
+using namespace astra;
+
+
+//-----------------------------------------------------------------------------------------
+// get string from matlab
+std::string mex_util_get_string(const mxArray* pInput)
+{
+ if (!mxIsChar(pInput)) {
+ return "";
+ }
+ mwSize iLength = mxGetNumberOfElements(pInput) + 1;
+ char* buf = new char[iLength];
+ mxGetString(pInput, buf, iLength);
+ std::string res = std::string(buf);
+ delete[] buf;
+ return res;
+}
+
+//-----------------------------------------------------------------------------------------
+// is option
+bool isOption(std::list<std::string> lOptions, std::string sOption)
+{
+ return std::find(lOptions.begin(), lOptions.end(), sOption) != lOptions.end();
+}
+
+//-----------------------------------------------------------------------------------------
+// turn a matlab struct into a c++ map
+std::map<std::string, mxArray*> parseStruct(const mxArray* pInput)
+{
+ std::map<std::string, mxArray*> res;
+
+ // check type
+ if (!mxIsStruct(pInput)) {
+ mexErrMsgTxt("Input must be a struct.");
+ return res;
+ }
+
+ // get field names
+ int nfields = mxGetNumberOfFields(pInput);
+ for (int i = 0; i < nfields; i++) {
+ std::string sFieldName = std::string(mxGetFieldNameByNumber(pInput, i));
+ res[sFieldName] = mxGetFieldByNumber(pInput,0,i);
+ }
+ return res;
+}
+
+//-----------------------------------------------------------------------------------------
+// turn a c++ map into a matlab struct
+mxArray* buildStruct(std::map<std::string, mxArray*> mInput)
+{
+ mwSize dims[2] = {1, 1};
+ mxArray* res = mxCreateStructArray(2,dims,0,0);
+
+ for (std::map<std::string, mxArray*>::iterator it = mInput.begin(); it != mInput.end(); it++) {
+ mxAddField(res, (*it).first.c_str());
+ mxSetField(res, 0, (*it).first.c_str(), (*it).second);
+ }
+ return res;
+}
+
+//-----------------------------------------------------------------------------------------
+// parse projection geometry data
+astra::CProjectionGeometry2D* parseProjectionGeometryStruct(const mxArray* prhs)
+{
+ // parse struct
+ std::map<string, mxArray*> mStruct = parseStruct(prhs);
+
+ // create projection geometry object
+ string type = mex_util_get_string(mStruct["type"]);
+ if (type == "parallel") {
+
+ // detector_width
+ float32 fDetWidth = 1.0f;
+ mxArray* tmp = mStruct["detector_width"];
+ if (tmp != NULL) {
+ fDetWidth = (float32)(mxGetScalar(tmp));
+ }
+
+ // detector_count
+ int iDetCount = 100;
+ tmp = mStruct["detector_count"];
+ if (tmp != NULL) {
+ iDetCount = (int)(mxGetScalar(tmp));
+ }
+
+ // angles
+ float32* pfAngles;
+ int iAngleCount;
+ tmp = mStruct["projection_angles"];
+ if (tmp != NULL) {
+ double* angleValues = mxGetPr(tmp);
+ iAngleCount = mxGetN(tmp) * mxGetM(tmp);
+ pfAngles = new float32[iAngleCount];
+ for (int i = 0; i < iAngleCount; i++) {
+ pfAngles[i] = angleValues[i];
+ }
+ } else {
+ mexErrMsgTxt("'angles' not specified, error.");
+ return NULL;
+ }
+
+ // create projection geometry
+ return new astra::CParallelProjectionGeometry2D(iAngleCount, // number of projections
+ iDetCount, // number of detectors
+ fDetWidth, // width of the detectors
+ pfAngles); // angles array
+ }
+
+ else if (type == "fanflat") {
+
+ // detector_width
+ float32 fDetWidth = 1.0f;
+ mxArray* tmp = mStruct["detector_width"];
+ if (tmp != NULL) {
+ fDetWidth = (float32)(mxGetScalar(tmp));
+ }
+
+ // detector_count
+ int iDetCount = 100;
+ tmp = mStruct["detector_count"];
+ if (tmp != NULL) {
+ iDetCount = (int)(mxGetScalar(tmp));
+ }
+
+ // angles
+ float32* pfAngles;
+ int iAngleCount;
+ tmp = mStruct["projection_angles"];
+ if (tmp != NULL) {
+ double* angleValues = mxGetPr(tmp);
+ iAngleCount = mxGetN(tmp) * mxGetM(tmp);
+ pfAngles = new float32[iAngleCount];
+ for (int i = 0; i < iAngleCount; i++) {
+ pfAngles[i] = angleValues[i];
+ }
+ } else {
+ mexErrMsgTxt("'angles' not specified, error.");
+ return NULL;
+ }
+
+ // origin_source_dist
+ int iDistOriginSource = 100;
+ tmp = mStruct["origin_source_dist"];
+ if (tmp != NULL) {
+ iDistOriginSource = (int)(mxGetScalar(tmp));
+ }
+
+ // origin_det_dist
+ int iDistOriginDet = 100;
+ tmp = mStruct["origin_det_dist"];
+ if (tmp != NULL) {
+ iDistOriginDet = (int)(mxGetScalar(tmp));
+ }
+
+ // create projection geometry
+ return new astra::CFanFlatProjectionGeometry2D(iAngleCount, // number of projections
+ iDetCount, // number of detectors
+ fDetWidth, // width of the detectors
+ pfAngles, // angles array
+ iDistOriginSource, // distance origin source
+ iDistOriginDet); // distance origin detector
+ }
+
+ else {
+ mexPrintf("Only parallel and fanflat projection geometry implemented.");
+ return NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------------------
+// create projection geometry data
+mxArray* createProjectionGeometryStruct(astra::CProjectionGeometry2D* _pProjGeom)
+{
+ // temporary map to store the data for the MATLAB struct
+ std::map<std::string, mxArray*> mGeometryInfo;
+
+ // detectorCount
+ mGeometryInfo["DetectorCount"] = mxCreateDoubleScalar(_pProjGeom->getDetectorCount());
+
+ if (!_pProjGeom->isOfType("fanflat_vec")) {
+ // detectorWidth
+ mGeometryInfo["DetectorWidth"] = mxCreateDoubleScalar(_pProjGeom->getDetectorWidth());
+
+ // pfProjectionAngles
+ mxArray* pAngles = mxCreateDoubleMatrix(1, _pProjGeom->getProjectionAngleCount(), mxREAL);
+ double* out = mxGetPr(pAngles);
+ for (int i = 0; i < _pProjGeom->getProjectionAngleCount(); i++) {
+ out[i] = _pProjGeom->getProjectionAngle(i);
+ }
+ mGeometryInfo["ProjectionAngles"] = pAngles;
+ }
+ else {
+ astra::CFanFlatVecProjectionGeometry2D* pVecGeom = dynamic_cast<astra::CFanFlatVecProjectionGeometry2D*>(_pProjGeom);
+ mxArray* pVectors = mxCreateDoubleMatrix(1, pVecGeom->getProjectionAngleCount()*6, mxREAL);
+ double* out = mxGetPr(pVectors);
+ int iDetCount = pVecGeom->getDetectorCount();
+ for (int i = 0; i < pVecGeom->getProjectionAngleCount(); i++) {
+ const SFanProjection* p = &pVecGeom->getProjectionVectors()[i];
+ out[6*i + 0] = p->fSrcX;
+ out[6*i + 1] = p->fSrcY;
+ out[6*i + 2] = p->fDetSX + 0.5f*iDetCount*p->fDetUX;
+ out[6*i + 3] = p->fDetSY + 0.5f*iDetCount*p->fDetUY;
+ out[6*i + 4] = p->fDetUX;
+ out[6*i + 5] = p->fDetUY;
+ }
+ mGeometryInfo["Vectors"] = pVectors;
+ }
+
+ // parallel specific options
+ if (_pProjGeom->isOfType("parallel")) {
+ // type
+ mGeometryInfo["type"] = mxCreateString("parallel");
+ }
+ // fanflat specific options
+ else if (_pProjGeom->isOfType("fanflat")) {
+ astra::CFanFlatProjectionGeometry2D* pFanFlatGeom = dynamic_cast<astra::CFanFlatProjectionGeometry2D*>(_pProjGeom);
+ // detectorCount
+ mGeometryInfo["DistanceOriginSource"] = mxCreateDoubleScalar(pFanFlatGeom->getOriginSourceDistance());
+ // detectorWidth
+ mGeometryInfo["DistanceOriginDetector"] = mxCreateDoubleScalar(pFanFlatGeom->getOriginDetectorDistance());
+ // type
+ mGeometryInfo["type"] = mxCreateString("fanflat");
+ }
+ else if (_pProjGeom->isOfType("sparse_matrix")) {
+ astra::CSparseMatrixProjectionGeometry2D* pSparseMatrixGeom = dynamic_cast<astra::CSparseMatrixProjectionGeometry2D*>(_pProjGeom);
+ mGeometryInfo["type"] = mxCreateString("sparse_matrix");
+ mGeometryInfo["MatrixID"] = mxCreateDoubleScalar(CMatrixManager::getSingleton().getIndex(pSparseMatrixGeom->getMatrix()));
+ }
+ else if(_pProjGeom->isOfType("fanflat_vec")) {
+ mGeometryInfo["type"] = mxCreateString("fanflat_vec");
+ }
+
+ // build and return the MATLAB struct
+ return buildStruct(mGeometryInfo);
+}
+
+//-----------------------------------------------------------------------------------------
+// parse reconstruction geometry data
+astra::CVolumeGeometry2D* parseVolumeGeometryStruct(const mxArray* prhs)
+{
+ // parse struct
+ std::map<string, mxArray*> mStruct = parseStruct(prhs);
+
+ std::map<string, mxArray*> mOptions = parseStruct(mStruct["option"]);
+
+ // GridColCount
+ int iWindowColCount = 128;
+ mxArray* tmp = mStruct["GridColCount"];
+ if (tmp != NULL) {
+ iWindowColCount = (int)(mxGetScalar(tmp));
+ }
+
+ // GridRowCount
+ int iWindowRowCount = 128;
+ tmp = mStruct["GridRowCount"];
+ if (tmp != NULL) {
+ iWindowRowCount = (int)(mxGetScalar(tmp));
+ }
+
+ // WindowMinX
+ float32 fWindowMinX = - iWindowColCount / 2;
+ tmp = mOptions["WindowMinX"];
+ if (tmp != NULL) {
+ fWindowMinX = (float32)(mxGetScalar(tmp));
+ }
+
+ // WindowMaxX
+ float32 fWindowMaxX = iWindowColCount / 2;
+ tmp = mOptions["WindowMaxX"];
+ if (tmp != NULL) {
+ fWindowMaxX = (float32)(mxGetScalar(tmp));
+ }
+
+ // WindowMinY
+ float32 fWindowMinY = - iWindowRowCount / 2;
+ tmp = mOptions["WindowMinY"];
+ if (tmp != NULL) {
+ fWindowMinY = (float32)(mxGetScalar(tmp));
+ }
+
+ // WindowMaxX
+ float32 fWindowMaxY = iWindowRowCount / 2;
+ tmp = mOptions["WindowMaxY"];
+ if (tmp != NULL) {
+ fWindowMaxY = (float32)(mxGetScalar(tmp));
+ }
+
+ // create and return reconstruction geometry
+ return new astra::CVolumeGeometry2D(iWindowColCount, iWindowRowCount,
+ fWindowMinX, fWindowMinY,
+ fWindowMaxX, fWindowMaxY);
+}
+
+//-----------------------------------------------------------------------------------------
+// create reconstruction geometry data
+mxArray* createVolumeGeometryStruct(astra::CVolumeGeometry2D* _pReconGeom)
+{
+ // temporary map to store the data for the MATLAB struct
+ std::map<std::string, mxArray*> mGeometryInfo;
+
+ // fill up map
+ mGeometryInfo["GridColCount"] = mxCreateDoubleScalar(_pReconGeom->getGridColCount());
+ mGeometryInfo["GridRowCount"] = mxCreateDoubleScalar(_pReconGeom->getGridRowCount());
+
+ std::map<std::string, mxArray*> mGeometryOptions;
+ mGeometryOptions["WindowMinX"] = mxCreateDoubleScalar(_pReconGeom->getWindowMinX());
+ mGeometryOptions["WindowMaxX"] = mxCreateDoubleScalar(_pReconGeom->getWindowMaxX());
+ mGeometryOptions["WindowMinY"] = mxCreateDoubleScalar(_pReconGeom->getWindowMinY());
+ mGeometryOptions["WindowMaxY"] = mxCreateDoubleScalar(_pReconGeom->getWindowMaxY());
+
+ mGeometryInfo["option"] = buildStruct(mGeometryOptions);
+
+ // build and return the MATLAB struct
+ return buildStruct(mGeometryInfo);
+}
+
+
+//-----------------------------------------------------------------------------------------
+string matlab2string(const mxArray* pField)
+{
+ // is string?
+ if (mxIsChar(pField)) {
+ return mex_util_get_string(pField);
+ }
+
+ // is scalar?
+ if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) == 1) {
+ return boost::lexical_cast<string>(mxGetScalar(pField));
+ }
+
+ return "";
+}
+
+//-----------------------------------------------------------------------------------------
+// Options struct to xml node
+bool readOptions(XMLNode* node, const mxArray* pOptionStruct)
+{
+ // loop all fields
+ int nfields = mxGetNumberOfFields(pOptionStruct);
+ for (int i = 0; i < nfields; i++) {
+ std::string sFieldName = std::string(mxGetFieldNameByNumber(pOptionStruct, i));
+ const mxArray* pField = mxGetFieldByNumber(pOptionStruct, 0, i);
+
+ if (node->hasOption(sFieldName)) {
+ mexErrMsgTxt("Duplicate option");
+ return false;
+ }
+
+ // string or scalar
+ if (mxIsChar(pField) || mex_is_scalar(pField)) {
+ string sValue = matlab2string(pField);
+ node->addOption(sFieldName, sValue);
+ } else
+ // numerical array
+ if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) > 1) {
+ if (!mxIsDouble(pField)) {
+ mexErrMsgTxt("Numeric input must be double.");
+ return false;
+ }
+
+ XMLNode* listbase = node->addChildNode("Option");
+ listbase->addAttribute("key", sFieldName);
+ listbase->addAttribute("listsize", mxGetM(pField)*mxGetN(pField));
+ double* pdValues = mxGetPr(pField);
+ int index = 0;
+ for (unsigned int row = 0; row < mxGetM(pField); row++) {
+ for (unsigned int col = 0; col < mxGetN(pField); col++) {
+ XMLNode* item = listbase->addChildNode("ListItem");
+ item->addAttribute("index", index);
+ item->addAttribute("value", pdValues[col*mxGetM(pField)+row]);
+ index++;
+ delete item;
+ }
+ }
+ delete listbase;
+ } else {
+ mexErrMsgTxt("Unsupported option type");
+ return false;
+ }
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------------------
+// struct to xml node
+bool readStruct(XMLNode* root, const mxArray* pStruct)
+{
+ // loop all fields
+ int nfields = mxGetNumberOfFields(pStruct);
+ for (int i = 0; i < nfields; i++) {
+
+ // field and fieldname
+ std::string sFieldName = std::string(mxGetFieldNameByNumber(pStruct, i));
+ const mxArray* pField = mxGetFieldByNumber(pStruct, 0, i);
+
+ // string
+ if (mxIsChar(pField)) {
+ string sValue = matlab2string(pField);
+ if (sFieldName == "type") {
+ root->addAttribute("type", sValue);
+ } else {
+ delete root->addChildNode(sFieldName, sValue);
+ }
+ }
+
+ // scalar
+ if (mex_is_scalar(pField)) {
+ string sValue = matlab2string(pField);
+ delete root->addChildNode(sFieldName, sValue);
+ }
+
+ // numerical array
+ if (mxIsNumeric(pField) && mxGetM(pField)*mxGetN(pField) > 1) {
+ if (!mxIsDouble(pField)) {
+ mexErrMsgTxt("Numeric input must be double.");
+ return false;
+ }
+ XMLNode* listbase = root->addChildNode(sFieldName);
+ listbase->addAttribute("listsize", mxGetM(pField)*mxGetN(pField));
+ double* pdValues = mxGetPr(pField);
+ int index = 0;
+ for (unsigned int row = 0; row < mxGetM(pField); row++) {
+ for (unsigned int col = 0; col < mxGetN(pField); col++) {
+ XMLNode* item = listbase->addChildNode("ListItem");
+ item->addAttribute("index", index);
+ item->addAttribute("value", pdValues[col*mxGetM(pField)+row]);
+ index++;
+ delete item;
+ }
+ }
+ delete listbase;
+ }
+
+
+ // not castable to a single string
+ if (mxIsStruct(pField)) {
+ if (sFieldName == "options" || sFieldName == "option" || sFieldName == "Options" || sFieldName == "Option") {
+ bool ret = readOptions(root, pField);
+ if (!ret)
+ return false;
+ } else {
+ XMLNode* newNode = root->addChildNode(sFieldName);
+ bool ret = readStruct(newNode, pField);
+ delete newNode;
+ if (!ret)
+ return false;
+ }
+ }
+
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------------------
+// turn a MATLAB struct into an XML Document
+XMLDocument* struct2XML(string rootname, const mxArray* pStruct)
+{
+ if (!mxIsStruct(pStruct)) {
+ mexErrMsgTxt("Input must be a struct.");
+ return NULL;
+ }
+
+ // create the document
+ XMLDocument* doc = XMLDocument::createDocument(rootname);
+ XMLNode* rootnode = doc->getRootNode();
+
+ // read the struct
+ bool ret = readStruct(rootnode, pStruct);
+ //doc->getRootNode()->print();
+ delete rootnode;
+
+ if (!ret) {
+ delete doc;
+ doc = 0;
+ }
+
+ return doc;
+}
+
+
+
+
+
+//-----------------------------------------------------------------------------------------
+// turn an std vector<float32> object to an mxArray
+mxArray* vectorToMxArray(std::vector<astra::float32> mInput)
+{
+ mxArray* res = mxCreateDoubleMatrix(1, mInput.size(), mxREAL);
+ double* pdData = mxGetPr(res);
+ for (unsigned int i = 0; i < mInput.size(); i++) {
+ pdData[i] = mInput[i];
+ }
+ return res;
+}
+
+//-----------------------------------------------------------------------------------------
+// turn a vector<vector<float32>> object to an mxArray
+mxArray* vector2DToMxArray(std::vector<std::vector<astra::float32> > mInput)
+{
+ unsigned int sizex = mInput.size();
+ if (sizex == 0) return mxCreateString("empty");
+ unsigned int sizey = mInput[0].size();
+
+ mxArray* res = mxCreateDoubleMatrix(sizex, sizey, mxREAL);
+ double* pdData = mxGetPr(res);
+ for (unsigned int i = 0; i < sizex; i++) {
+ for (unsigned int j = 0; j < sizey && j < mInput[i].size(); j++) {
+ pdData[j*sizex+i] = mInput[i][j];
+ }
+ }
+ return res;
+}
+
+//-----------------------------------------------------------------------------------------
+// turn a boost::any object to an mxArray
+mxArray* anyToMxArray(boost::any _any)
+{
+ if (_any.type() == typeid(std::string)) {
+ std::string str = boost::any_cast<std::string>(_any);
+ return mxCreateString(str.c_str());
+ }
+ if (_any.type() == typeid(int)) {
+ return mxCreateDoubleScalar(boost::any_cast<int>(_any));
+ }
+ if (_any.type() == typeid(float32)) {
+ return mxCreateDoubleScalar(boost::any_cast<float32>(_any));
+ }
+ if (_any.type() == typeid(std::vector<astra::float32>)) {
+ return vectorToMxArray(boost::any_cast<std::vector<float32> >(_any));
+ }
+ if (_any.type() == typeid(std::vector<std::vector<astra::float32> >)) {
+ return vector2DToMxArray(boost::any_cast<std::vector<std::vector<float32> > >(_any));
+ }
+ return NULL;
+}
+//-----------------------------------------------------------------------------------------
+// return true ig the argument is a scalar
+bool mex_is_scalar(const mxArray* pInput)
+{
+ return (mxIsNumeric(pInput) && mxGetM(pInput)*mxGetN(pInput) == 1);
+}
+
+//-----------------------------------------------------------------------------------------
+mxArray* XML2struct(astra::XMLDocument* xml)
+{
+ XMLNode* node = xml->getRootNode();
+ mxArray* str = XMLNode2struct(xml->getRootNode());
+ delete node;
+ return str;
+}
+
+//-----------------------------------------------------------------------------------------
+mxArray* XMLNode2struct(astra::XMLNode* node)
+{
+ std::map<std::string, mxArray*> mList;
+
+ // type_attribute
+ if (node->hasAttribute("type")) {
+ mList["type"] = mxCreateString(node->getAttribute("type").c_str());
+ }
+
+ list<XMLNode*> nodes = node->getNodes();
+ for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+ XMLNode* subnode = (*it);
+ // list
+ if (subnode->hasAttribute("listsize")) {
+ cout << "lkmdsqldqsjkl" << endl;
+ cout << " " << node->getContentNumericalArray().size() << endl;
+ mList[subnode->getName()] = vectorToMxArray(node->getContentNumericalArray());
+ }
+ // string
+ else {
+ mList[subnode->getName()] = mxCreateString(subnode->getContent().c_str());
+ }
+ delete subnode;
+ }
+
+ return buildStruct(mList);
+}
+
+void get3DMatrixDims(const mxArray* x, mwSize *dims)
+{
+ const mwSize* mdims = mxGetDimensions(x);
+ mwSize dimCount = mxGetNumberOfDimensions(x);
+ if (dimCount == 1) {
+ dims[0] = mdims[0];
+ dims[1] = 1;
+ dims[2] = 1;
+ } else if (dimCount == 2) {
+ dims[0] = mdims[0];
+ dims[1] = mdims[1];
+ dims[2] = 1;
+ } else if (dimCount == 3) {
+ dims[0] = mdims[0];
+ dims[1] = mdims[1];
+ dims[2] = mdims[2];
+ } else {
+ dims[0] = 0;
+ dims[1] = 0;
+ dims[2] = 0;
+ }
+}
diff --git a/matlab/mex/mexHelpFunctions.h b/matlab/mex/mexHelpFunctions.h
new file mode 100644
index 0000000..425b4ef
--- /dev/null
+++ b/matlab/mex/mexHelpFunctions.h
@@ -0,0 +1,76 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _INC_ASTRA_MEX_HELPFUNCTIONS
+#define _INC_ASTRA_MEX_HELPFUNCTIONS
+
+#include <string>
+#include <list>
+#include <iostream>
+#include <sstream>
+#include <map>
+#include <algorithm>
+#include <mex.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/any.hpp>
+
+#include "astra/Globals.h"
+#include "astra/Utilities.h"
+
+#include "astra/ParallelProjectionGeometry2D.h"
+#include "astra/FanFlatProjectionGeometry2D.h"
+#include "astra/VolumeGeometry2D.h"
+
+#include "astra/XMLDocument.h"
+#include "astra/XMLNode.h"
+
+std::string mex_util_get_string(const mxArray* pInput);
+bool isOption(std::list<std::string> lOptions, std::string sOption);
+
+bool mex_is_scalar(const mxArray* pInput);
+
+std::map<std::string, mxArray*> parseStruct(const mxArray* pInput);
+mxArray* buildStruct(std::map<std::string, mxArray*> mInput);
+mxArray* vectorToMxArray(std::vector<astra::float32> mInput);
+
+mxArray* anyToMxArray(boost::any _any);
+
+astra::CProjectionGeometry2D* parseProjectionGeometryStruct(const mxArray*);
+mxArray* createProjectionGeometryStruct(astra::CProjectionGeometry2D*);
+astra::CVolumeGeometry2D* parseVolumeGeometryStruct(const mxArray*);
+mxArray* createVolumeGeometryStruct(astra::CVolumeGeometry2D* _pReconGeom);
+
+astra::XMLDocument* struct2XML(string rootname, const mxArray* pStruct);
+
+mxArray* XML2struct(astra::XMLDocument* xml);
+mxArray* XMLNode2struct(astra::XMLNode* xml);
+
+void get3DMatrixDims(const mxArray* x, mwSize *dims);
+
+#endif
diff --git a/matlab/tools/ROIselectfull.m b/matlab/tools/ROIselectfull.m
new file mode 100644
index 0000000..a50c979
--- /dev/null
+++ b/matlab/tools/ROIselectfull.m
@@ -0,0 +1,18 @@
+function V_out = ROIselectfull(input, ROI)
+
+ s1 = size(input,1);
+ s2 = size(input,2);
+ [x y] = meshgrid(-(s2-1)/2:(s2-1)/2,(s1-1)/2:-1:-(s1-1)/2);
+ A = Afstand(x,y,0,0);
+
+ V_out = zeros(size(input));
+ for slice = 1:size(input,3);
+ V = input(:,:,slice);
+ V(A > ROI/2) = 0;
+ V_out(:,:,slice) = V;
+ end
+end
+
+function A = Afstand(x1,y1,x2,y2)
+ A = sqrt((x1-x2).^2+(y1-y2).^2);
+end \ No newline at end of file
diff --git a/matlab/tools/astra_add_noise_to_sino.m b/matlab/tools/astra_add_noise_to_sino.m
new file mode 100644
index 0000000..a262f49
--- /dev/null
+++ b/matlab/tools/astra_add_noise_to_sino.m
@@ -0,0 +1,47 @@
+function sinogram_out = astra_add_noise_to_sino(sinogram_in,I0)
+
+%--------------------------------------------------------------------------
+% sinogram_out = astra_add_noise_to_sino(sinogram_in,I0)
+%
+% Add poisson noise to a sinogram.
+%
+% sinogram_in: input sinogram, can be either MATLAB-data or an
+% astra-identifier. In the latter case, this operation is inplace and the
+% result will also be stored in this data object.
+% I0: background intensity, used to set noise level, lower equals more
+% noise
+% sinogram_out: output sinogram in MATLAB-data.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+if numel(sinogram_in) == 1
+ sinogramRaw = astra_mex_data2d('get', sinogram_in);
+else
+ sinogramRaw = sinogram_in;
+end
+
+% scale to [0,1]
+max_sinogramRaw = max(sinogramRaw(:));
+sinogramRawScaled = sinogramRaw ./ max_sinogramRaw;
+% to detector count
+sinogramCT = I0 * exp(-sinogramRawScaled);
+% add poison noise
+sinogramCT_A = sinogramCT * 1e-12;
+sinogramCT_B = double(imnoise(sinogramCT_A, 'poisson'));
+sinogramCT_C = sinogramCT_B * 1e12;
+% to density
+sinogramCT_D = sinogramCT_C / I0;
+sinogram_out = -max_sinogramRaw * log(sinogramCT_D);
+
+if numel(sinogram_in) == 1
+ astra_mex_data2d('store', sinogram_in, sinogram_out);
+end
diff --git a/matlab/tools/astra_clear.m b/matlab/tools/astra_clear.m
new file mode 100644
index 0000000..d42e395
--- /dev/null
+++ b/matlab/tools/astra_clear.m
@@ -0,0 +1,19 @@
+%--------------------------------------------------------------------------
+% Clears and frees memory of all objects (data, projectors, algorithms)
+% currently in the astra-library.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+astra_mex_data2d('clear');
+astra_mex_data3d('clear');
+astra_mex_algorithm('clear');
+astra_mex_projector('clear');
diff --git a/matlab/tools/astra_create_backprojection.m b/matlab/tools/astra_create_backprojection.m
new file mode 100644
index 0000000..7f0b02f
--- /dev/null
+++ b/matlab/tools/astra_create_backprojection.m
@@ -0,0 +1,63 @@
+function [vol_id, vol] = astra_create_backprojection(data, proj_id)
+
+%--------------------------------------------------------------------------
+% [vol_id, vol] = astra_create_backprojection(data, proj_id)
+%
+% Create a CPU based back projection.
+%
+% data: input sinogram, can be either MATLAB-data or an astra-identifier.
+% proj_id: identifier of the projector as it is stored in the astra-library
+% vol_id: identifier of the volume data object as it is now stored in the astra-library.
+% vol: MATLAB data version of the volume
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+% get projection geometry
+proj_geom = astra_mex_projector('projection_geometry', proj_id);
+vol_geom = astra_mex_projector('volume_geometry', proj_id);
+
+% store sinogram
+if (numel(data) > 1)
+ sino_id = astra_mex_data2d('create','-sino', proj_geom, data);
+else
+ sino_id = data;
+end
+
+% store volume
+vol_id = astra_mex_data2d('create','-vol', vol_geom, 0);
+
+if astra_mex_projector('is_cuda', proj_id)
+ cfg = astra_struct('BP_CUDA');
+else
+ cfg = astra_struct('BP');
+end
+
+cfg.ProjectorId = proj_id;
+cfg.ProjectionDataId = sino_id;
+cfg.ReconstructionDataId = vol_id;
+
+% create backprojection
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id);
+astra_mex_algorithm('delete', alg_id);
+
+if (numel(data) > 1)
+ astra_mex_data2d('delete', sino_id);
+end
+
+if nargout >= 2
+ vol = astra_mex_data2d('get',vol_id);
+end
+
+
+
diff --git a/matlab/tools/astra_create_backprojection3d_cuda.m b/matlab/tools/astra_create_backprojection3d_cuda.m
new file mode 100644
index 0000000..afa41db
--- /dev/null
+++ b/matlab/tools/astra_create_backprojection3d_cuda.m
@@ -0,0 +1,54 @@
+function [vol_id, vol] = astra_create_backprojection3d_cuda(data, proj_geom, vol_geom)
+
+%--------------------------------------------------------------------------
+% [vol_id, vol] = astra_create_backprojection3d_cuda(data, proj_geom, vol_geom)
+%
+% Create a GPU based backprojection.
+%
+% data: input projection data, can be either MATLAB-data or an astra-identifier.
+% proj_geom: MATLAB struct containing the projection geometry.
+% vol_geom: MATLAB struct containing the volume geometry.
+% vol_id: identifier of the volume data object as it is now stored in
+% the astra-library.
+% vol: MATLAB data version of the volume.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+% store projection data
+if (numel(data) > 1)
+ sino_id = astra_mex_data3d('create','-proj3d', proj_geom, data);
+else
+ sino_id = data;
+end
+
+% store volume
+vol_id = astra_mex_data3d('create','-vol', vol_geom, 0);
+
+% create sinogram
+cfg = astra_struct('BP3D_CUDA');
+cfg.ProjectionDataId = sino_id;
+cfg.ReconstructionDataId = vol_id;
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id);
+astra_mex_algorithm('delete', alg_id);
+
+if (numel(data) > 1)
+ astra_mex_data3d('delete', sino_id);
+end
+
+if nargout >= 2
+ vol = astra_mex_data3d('get',vol_id);
+end
+
+
+
diff --git a/matlab/tools/astra_create_backprojection_cuda.m b/matlab/tools/astra_create_backprojection_cuda.m
new file mode 100644
index 0000000..cef7864
--- /dev/null
+++ b/matlab/tools/astra_create_backprojection_cuda.m
@@ -0,0 +1,39 @@
+function backProj = astra_create_backprojection_cuda(sinogramData, proj_geom, vol_geom)
+ %--------------------------------------------------------------------------
+ % backProj = astra_create_backprojection_cuda(sinogramData, proj_geom, vol_geom)
+ %
+ % Creates a CUDA-based simple backprojection
+ %
+ % sinogramData: 2D matrix with projections stored row-based
+ % theta: projection angles, length should be equal to the number of rows in
+ % sinogramData
+ % reconstructionSize: vector with length 2 with the row and column count of
+ % the reconstruction image
+ % backProj: 2D back projection from sinogram data
+ %--------------------------------------------------------------------------
+ %------------------------------------------------------------------------
+ % This file is part of the
+ % All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+ %
+ % Copyright: iMinds-Vision Lab, University of Antwerp
+ % License: Open Source under GPLv3
+ % Contact: mailto:astra@ua.ac.be
+ % Website: http://astra.ua.ac.be
+ %------------------------------------------------------------------------
+ % $Id$
+
+ recon_id = astra_mex_data2d('create', '-vol', vol_geom, 0);
+ sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogramData);
+
+ cfg = astra_struct('BP_CUDA');
+ cfg.ProjectionDataId = sinogram_id;
+ cfg.ReconstructionDataId = recon_id;
+
+ alg_id = astra_mex_algorithm('create', cfg);
+ astra_mex_algorithm('run', alg_id);
+ backProj = astra_mex_data2d('get', recon_id);
+
+ astra_mex_data2d('delete', sinogram_id);
+ astra_mex_data2d('delete', recon_id);
+ astra_mex_algorithm('delete', alg_id);
+end
diff --git a/matlab/tools/astra_create_fbp_reconstruction.m b/matlab/tools/astra_create_fbp_reconstruction.m
new file mode 100644
index 0000000..4456f9c
--- /dev/null
+++ b/matlab/tools/astra_create_fbp_reconstruction.m
@@ -0,0 +1,23 @@
+function [FBP_id, FBP] = astra_create_fbp_reconstruction(sinogram, proj_id)
+
+proj_geom = astra_mex_projector('projection_geometry', proj_id);
+vol_geom = astra_mex_projector('volume_geometry', proj_id);
+
+if numel(sinogram) == 1
+ sinogram_id = sinogram;
+else
+ sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram);
+end
+
+FBP_id = astra_mex_data2d('create','-vol',vol_geom, 0);
+
+cfg = astra_struct('FBP_CUDA');
+cfg.ProjectionDataId = sinogram_id;
+cfg.ReconstructionDataId = FBP_id;
+cfg.FilterType = 'Ram-Lak';
+cfg.ProjectorId = proj_id;
+cfg.Options.GPUindex = 0;
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('run', alg_id);
+
+FBP = astra_mex_data2d('get', FBP_id);
diff --git a/matlab/tools/astra_create_proj_geom.m b/matlab/tools/astra_create_proj_geom.m
new file mode 100644
index 0000000..dbf0464
--- /dev/null
+++ b/matlab/tools/astra_create_proj_geom.m
@@ -0,0 +1,204 @@
+function proj_geom = astra_create_proj_geom(type, varargin)
+
+%--------------------------------------------------------------------------
+% proj_geom = astra_create_proj_geom('parallel', det_width, det_count, angles)
+%
+% Create a 2D parallel beam geometry. See the API for more information.
+% det_width: distance between two adjacent detectors
+% det_count: number of detectors in a single projection
+% angles: projection angles in radians, should be between -pi/4 and 7pi/4
+% proj_geom: MATLAB struct containing all information of the geometry
+%--------------------------------------------------------------------------
+% proj_geom = astra_create_proj_geom('parallel3d', det_spacing_x, det_spacing_y, det_row_count, det_col_count, angles)
+%
+% Create a 3D parallel beam geometry. See the API for more information.
+% det_spacing_x: distance between two horizontally adjacent detectors
+% det_spacing_y: distance between two vertically adjacent detectors
+% det_row_count: number of detector rows in a single projection
+% det_col_count: number of detector columns in a single projection
+% angles: projection angles in radians, should be between -pi/4 and 7pi/4
+% proj_geom: MATLAB struct containing all information of the geometry
+%--------------------------------------------------------------------------
+% proj_geom = astra_create_proj_geom('fanflat', det_width, det_count, angles, source_origin, origin_det)
+%
+% Create a 2D flat fan beam geometry. See the API for more information.
+% det_width: distance between two adjacent detectors
+% det_count: number of detectors in a single projection
+% angles: projection angles in radians, should be between -pi/4 and 7pi/4
+% source_origin: distance between the source and the center of rotation
+% origin_det: distance between the center of rotation and the detector array
+% proj_geom: MATLAB struct containing all information of the geometry
+%--------------------------------------------------------------------------
+% proj_geom = astra_create_proj_geom('fanflat_vec', det_count, vectors)
+%
+% Create a 2D flat fan beam geometry specified by 2D vectors.
+% See the API for more information.
+% det_count: number of detectors in a single projection
+% vectors: a matrix containing the actual geometry. Each row corresponds
+% to a single projection, and consists of:
+% ( srcX, srcY, dX, dY, uX, uY )
+% src: the ray source
+% d : the center of the detector
+% u : the vector from detector pixel 0 to 1
+% proj_geom: MATLAB struct containing all information of the geometry
+%--------------------------------------------------------------------------
+% proj_geom = astra_create_proj_geom('cone', det_spacing_x, det_spacing_y, det_row_count, det_col_count, angles, source_origin, origin_det)
+%
+% Create a 3D cone beam geometry. See the API for more information.
+% det_spacing_x: distance between two horizontally adjacent detectors
+% det_spacing_y: distance between two vertically adjacent detectors
+% det_row_count: number of detector rows in a single projection
+% det_col_count: number of detector columns in a single projection
+% angles: projection angles in radians, should be between -pi/4 and 7pi/4
+% source_origin: distance between the source and the center of rotation
+% origin_det: distance between the center of rotation and the detector array
+% proj_geom: MATLAB struct containing all information of the geometry
+%--------------------------------------------------------------------------
+% proj_geom = astra_create_proj_geom('cone_vec', det_row_count, det_col_count, vectors)
+%
+% Create a 3D cone beam geometry specified by 3D vectors.
+% See the API for more information.
+% det_row_count: number of detector rows in a single projection
+% det_col_count: number of detector columns in a single projection
+% vectors: a matrix containing the actual geometry. Each row corresponds
+% to a single projection, and consists of:
+% ( srcX, srcY, srcZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ )
+% src: the ray source
+% d : the center of the detector
+% u : the vector from detector pixel (0,0) to (0,1)
+% v : the vector from detector pixel (0,0) to (1,0)
+% proj_geom: MATLAB struct containing all information of the geometry
+%--------------------------------------------------------------------------
+% proj_geom = astra_create_proj_geom('parallel3d_vec', det_row_count, det_col_count, vectors)
+%
+% Create a 3D parallel beam geometry specified by 3D vectors.
+% See the API for more information.
+% det_row_count: number of detector rows in a single projection
+% det_col_count: number of detector columns in a single projection
+% vectors: a matrix containing the actual geometry. Each row corresponds
+% to a single projection, and consists of:
+% ( rayX, rayY, rayZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ )
+% ray: the ray direction
+% d : the center of the detector
+% u : the vector from detector pixel (0,0) to (0,1)
+% v : the vector from detector pixel (0,0) to (1,0)
+% proj_geom: MATLAB struct containing all information of the geometry
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+if strcmp(type,'parallel')
+ if numel(varargin) < 3
+ error('not enough variables: astra_create_proj_geom(parallel, detector_spacing, det_count, angles)');
+ end
+ proj_geom = struct( ...
+ 'type', 'parallel', ...
+ 'DetectorWidth', varargin{1}, ...
+ 'DetectorCount', varargin{2}, ...
+ 'ProjectionAngles', varargin{3} ...
+ );
+
+elseif strcmp(type,'fanflat')
+ if numel(varargin) < 5
+ error('not enough variables: astra_create_proj_geom(fanflat, det_width, det_count, angles, source_origin, source_det)');
+ end
+ proj_geom = struct( ...
+ 'type', 'fanflat', ...
+ 'DetectorWidth', varargin{1}, ...
+ 'DetectorCount', varargin{2}, ...
+ 'ProjectionAngles', varargin{3}, ...
+ 'DistanceOriginSource', varargin{4}, ...
+ 'DistanceOriginDetector', varargin{5} ...
+ );
+
+elseif strcmp(type,'fanflat_vec')
+ if numel(varargin) < 2
+ error('not enough variables: astra_create_proj_geom(fanflat_vec, det_count, V')
+ end
+ if size(varargin{2}, 2) ~= 6
+ error('V should be a Nx6 matrix, with N the number of projections')
+ end
+ proj_geom = struct( ...
+ 'type', 'fanflat_vec', ...
+ 'DetectorCount', varargin{1}, ...
+ 'Vectors', varargin{2} ...
+ );
+
+elseif strcmp(type,'parallel3d')
+ if numel(varargin) < 5
+ error('not enough variables: astra_create_proj_geom(parallel3d, detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles)');
+ end
+ proj_geom = struct( ...
+ 'type', 'parallel3d', ...
+ 'DetectorSpacingX', varargin{1}, ...
+ 'DetectorSpacingY', varargin{2}, ...
+ 'DetectorRowCount', varargin{3}, ...
+ 'DetectorColCount', varargin{4}, ...
+ 'ProjectionAngles', varargin{5} ...
+ );
+elseif strcmp(type,'cone')
+ if numel(varargin) < 7
+ error('not enough variables: astra_create_proj_geom(cone, detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles, source_origin, source_det)');
+ end
+ proj_geom = struct( ...
+ 'type', 'cone', ...
+ 'DetectorSpacingX', varargin{1}, ...
+ 'DetectorSpacingY', varargin{2}, ...
+ 'DetectorRowCount', varargin{3}, ...
+ 'DetectorColCount', varargin{4}, ...
+ 'ProjectionAngles', varargin{5}, ...
+ 'DistanceOriginSource', varargin{6}, ...
+ 'DistanceOriginDetector',varargin{7} ...
+ );
+elseif strcmp(type,'cone_vec')
+ if numel(varargin) < 3
+ error('not enough variables: astra_create_proj_geom(cone_vec, det_row_count, det_col_count, V')
+ end
+ if size(varargin{3}, 2) ~= 12
+ error('V should be a Nx12 matrix, with N the number of projections')
+ end
+ proj_geom = struct( ...
+ 'type', 'cone_vec', ...
+ 'DetectorRowCount', varargin{1}, ...
+ 'DetectorColCount', varargin{2}, ...
+ 'Vectors', varargin{3} ...
+ );
+elseif strcmp(type,'parallel3d_vec')
+ if numel(varargin) < 3
+ error('not enough variables: astra_create_proj_geom(parallel3d_vec, det_row_count, det_col_count, V')
+ end
+ if size(varargin{3}, 2) ~= 12
+ error('V should be a Nx12 matrix, with N the number of projections')
+ end
+ proj_geom = struct( ...
+ 'type', 'parallel3d_vec', ...
+ 'DetectorRowCount', varargin{1}, ...
+ 'DetectorColCount', varargin{2}, ...
+ 'Vectors', varargin{3} ...
+ );
+elseif strcmp(type,'sparse_matrix')
+ if numel(varargin) < 3
+ error('not enough variables: astra_create_proj_geom(sparse_matrix, det_width, det_count, angles, matrix_id)')
+ end
+ proj_geom = struct( ...
+ 'type', 'sparse_matrix', ...
+ 'DetectorWidth', varargin{1}, ...
+ 'DetectorCount', varargin{2}, ...
+ 'ProjectionAngles', varargin{3}, ...
+ 'MatrixID', varargin{4} ...
+ );
+
+else
+ disp(['Error: unknown type ' type]);
+ proj_geom = struct();
+end
+
diff --git a/matlab/tools/astra_create_projector.m b/matlab/tools/astra_create_projector.m
new file mode 100644
index 0000000..f773d0d
--- /dev/null
+++ b/matlab/tools/astra_create_projector.m
@@ -0,0 +1,50 @@
+function proj_id = astra_create_projector(type, proj_geom, vol_geom)
+
+%--------------------------------------------------------------------------
+% proj_id = astra_create_projector(type, proj_geom, vol_geom)
+%
+% Create a new projector object based on projection and volume geometry.
+% Used when the default values of each projector are sufficient.
+%
+% type: type of the projector. 'blob', 'line', 'linear' 'strip', ... See API for more information.
+% proj_geom: MATLAB struct containing the projection geometry.
+% vol_geom: MATLAB struct containing the volume geometry.
+% proj_id: identifier of the projector as it is now stored in the astra-library.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+cfg_proj = astra_struct(type);
+cfg_proj.ProjectionGeometry = proj_geom;
+cfg_proj.VolumeGeometry = vol_geom;
+
+if strcmp(type,'blob')
+ % Blob options
+ blob_size = 2;
+ blob_sample_rate = 0.01;
+ blob_values = kaiserBessel(2, 10.4, blob_size, 0:blob_sample_rate:blob_size);
+ cfg_proj.Kernel.KernelSize = blob_size;
+ cfg_proj.Kernel.SampleRate = blob_sample_rate;
+ cfg_proj.Kernel.SampleCount = length(blob_values);
+ cfg_proj.Kernel.KernelValues = blob_values;
+end
+
+if strcmp(type,'linear3d') || strcmp(type,'linearcone') || strcmp(type,'cuda3d')
+ proj_id = astra_mex_projector3d('create', cfg_proj);
+else
+ proj_id = astra_mex_projector('create', cfg_proj);
+end
+
+
+
+
+
diff --git a/matlab/tools/astra_create_reconstruction.m b/matlab/tools/astra_create_reconstruction.m
new file mode 100644
index 0000000..15e452c
--- /dev/null
+++ b/matlab/tools/astra_create_reconstruction.m
@@ -0,0 +1,97 @@
+function [recon_id, recon] = astra_create_reconstruction(rec_type, proj_id, sinogram, iterations, use_mask, mask, use_minc, minc, use_maxc, maxc)
+
+%--------------------------------------------------------------------------
+% [recon_id, recon] = astra_create_reconstruction(rec_type, proj_id, sinogram, iterations, use_mask, mask, use_minc, minc, use_maxc, maxc)
+%
+% Create a CPU based iterative reconstruction.
+%
+% rec_type: reconstruction type, 'ART', 'SART' 'SIRT' or 'CGLS', not all options are adjustable
+% proj_id: identifier of the projector as it is stored in the astra-library
+% sinogram: sinogram data OR sinogram identifier
+% iterations: number of iterations to perform
+% use_mask: use a reconstrucionmask? 'yes' or 'no'
+% mask: mask data OR mask identifier.
+% use_minc: use a minimum constraint? 'yes' or 'no'
+% minc: minimum constraint value
+% use_maxc: use a maximum constraint? 'yes' or 'no'
+% maxc: maximum constraint value
+% recon_id: identifier of the reconstruction data object as it is now stored in the astra-library
+% recon: MATLAB data version of the reconstruction
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+if nargin <= 4
+ use_mask = 'no';
+ mask = [];
+ use_minc = 'no';
+ minc = 0;
+ use_maxc = 'no';
+ maxc = 255;
+end
+
+if nargin <= 6
+ use_minc = 'no';
+ minc = 0;
+ use_maxc = 'no';
+ maxc = 255;
+end
+
+if numel(sinogram) == 1
+ sinogram_id = sinogram;
+else
+ proj_geom = astra_mex_projector('projection_geometry', proj_id);
+ sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram);
+end
+
+% create reconstruction object
+vol_geom = astra_mex_projector('volume_geometry', proj_id);
+recon_id = astra_mex_data2d('create', '-vol', vol_geom, 0);
+
+% configure
+cfg = astra_struct(rec_type);
+cfg.ProjectorId = proj_id;
+cfg.ProjectionDataId = sinogram_id;
+cfg.ReconstructionDataId = recon_id;
+if strcmp(use_mask,'yes')
+ if numel(mask) == 1
+ mask_id = mask;
+ else
+ mask_id = astra_mex_data2d('create', '-vol', vol_geom, mask);
+ end
+ cfg.options.ReconstructionMaskId = mask_id;
+end
+cfg.options.UseMinConstraint = use_minc;
+cfg.options.MinConstraintValue = minc;
+cfg.options.UseMaxConstraint = use_maxc;
+cfg.options.MaxConstraintValue = maxc;
+cfg.options.ProjectionOrder = 'random';
+alg_id = astra_mex_algorithm('create', cfg);
+
+% iterate
+astra_mex_algorithm('iterate', alg_id, iterations);
+
+% return object
+recon = astra_mex_data2d('get', recon_id);
+
+% garbage collection
+astra_mex_algorithm('delete', alg_id);
+if numel(sinogram) ~= 1
+ astra_mex_data2d('delete', sinogram_id);
+end
+
+if strcmp(use_mask,'yes')
+ if numel(mask) ~= 1
+ astra_mex_data2d('delete', mask_id);
+ end
+end
+
diff --git a/matlab/tools/astra_create_reconstruction_cuda.m b/matlab/tools/astra_create_reconstruction_cuda.m
new file mode 100644
index 0000000..b428eb5
--- /dev/null
+++ b/matlab/tools/astra_create_reconstruction_cuda.m
@@ -0,0 +1,80 @@
+function [recon_id, recon] = astra_create_reconstruction_cuda(rec_type, proj_geom, vol_geom, sinogram, iterations, use_mask, mask, use_minc, minc, use_maxc, maxc)
+
+%--------------------------------------------------------------------------
+% [recon_id, recon] = astra_create_reconstruction_cuda(rec_type, proj_geom, vol_geom, sinogram, iterations, use_mask, mask, use_minc, minc, use_maxc, maxc)
+%
+% Create a GPU based iterative reconstruction.
+%
+% rec_type: reconstruction type, only 'SIRT_CUDA' for now
+% proj_geom: projection geometry struct
+% vol_geom: volume geometry struct
+% sinogram: sinogram data OR sinogram identifier
+% iterations: number of iterations to perform
+% use_mask: use a reconstrucionmask? 'yes' or 'no'
+% mask: mask data OR mask identifier.
+% use_minc: use a minimum constraint? 'yes' or 'no'
+% minc: minimum constraint value
+% use_maxc: use a maximum constraint? 'yes' or 'no'
+% maxc: maximum constraint value
+% recon_id: identifier of the reconstruction data object as it is now stored in the astra-library
+% recon: MATLAB data version of the reconstruction
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+if numel(sinogram) == 1
+ sinogram_id = sinogram;
+else
+ sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram);
+end
+
+% create reconstruction object
+recon_id = astra_mex_data2d('create', '-vol', vol_geom, 0);
+
+% configure
+cfg = astra_struct('SIRT_CUDA');
+cfg.ProjectionGeometry = proj_geom;
+cfg.ReconstructionGeometry = vol_geom;
+cfg.ProjectionDataId = sinogram_id;
+cfg.ReconstructionDataId = recon_id;
+if strcmp(use_mask,'yes')
+ if numel(mask) == 1
+ mask_id = mask;
+ else
+ mask_id = astra_mex_data2d('create', '-vol', vol_geom, mask);
+ end
+ cfg.options.ReconstructionMaskId = mask_id;
+end
+cfg.options.UseMinConstraint = use_minc;
+cfg.options.MinConstraintValue = minc;
+cfg.options.UseMaxConstraint = use_maxc;
+cfg.options.MaxConstraintValue = maxc;
+alg_id = astra_mex_algorithm('create', cfg);
+
+% iterate
+astra_mex_algorithm('iterate', alg_id, iterations);
+
+% return object
+recon = astra_mex_data2d('get', recon_id);
+
+% garbage collection
+astra_mex_algorithm('delete', alg_id);
+if numel(sinogram) ~= 1
+ astra_mex_data2d('delete', sinogram_id);
+end
+
+if strcmp(use_mask,'yes')
+ if numel(mask) ~= 1
+ astra_mex_data2d('delete', mask_id);
+ end
+end
+
diff --git a/matlab/tools/astra_create_sino.m b/matlab/tools/astra_create_sino.m
new file mode 100644
index 0000000..4771bd6
--- /dev/null
+++ b/matlab/tools/astra_create_sino.m
@@ -0,0 +1,63 @@
+function [sino_id, sino] = astra_create_sino(data, proj_id)
+
+%--------------------------------------------------------------------------
+% [sino_id, sino] = astra_create_sino(data, proj_id)
+%
+% Create a CPU based forward projection.
+%
+% data: input volume, can be either MATLAB-data or an astra-identifier.
+% proj_id: identifier of the projector as it is stored in the astra-library
+% sino_id: identifier of the sinogram data object as it is now stored in the astra-library.
+% sino: MATLAB data version of the sinogram
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+% get projection geometry
+proj_geom = astra_mex_projector('projection_geometry', proj_id);
+vol_geom = astra_mex_projector('volume_geometry', proj_id);
+
+% store volume
+if (numel(data) > 1)
+ volume_id = astra_mex_data2d('create','-vol', vol_geom, data);
+else
+ volume_id = data;
+end
+
+% store sino
+sino_id = astra_mex_data2d('create','-sino', proj_geom, 0);
+
+if astra_mex_projector('is_cuda', proj_id)
+ cfg = astra_struct('FP_CUDA');
+else
+ cfg = astra_struct('FP');
+end
+
+cfg.ProjectorId = proj_id;
+cfg.ProjectionDataId = sino_id;
+cfg.VolumeDataId = volume_id;
+
+% create sinogram
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id);
+astra_mex_algorithm('delete', alg_id);
+
+if (numel(data) > 1)
+ astra_mex_data2d('delete', volume_id);
+end
+
+if nargout >= 2
+ sino = astra_mex_data2d('get',sino_id);
+end
+
+
+
diff --git a/matlab/tools/astra_create_sino3d_cuda.m b/matlab/tools/astra_create_sino3d_cuda.m
new file mode 100644
index 0000000..ef22ebe
--- /dev/null
+++ b/matlab/tools/astra_create_sino3d_cuda.m
@@ -0,0 +1,54 @@
+function [sino_id, sino] = astra_create_sino3d_cuda(data, proj_geom, vol_geom)
+
+%--------------------------------------------------------------------------
+% [sino_id, sino] = astra_create_sino3d_cuda(data, proj_geom, vol_geom)
+%
+% Create a GPU based forward projection.
+%
+% data: input volume, can be either MATLAB-data or an astra-identifier.
+% proj_geom: MATLAB struct containing the projection geometry.
+% vol_geom: MATLAB struct containing the volume geometry.
+% sino_id: identifier of the sinogram data object as it is now stored in
+% the astra-library.
+% sino: MATLAB data version of the sinogram.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+% store volume
+if (numel(data) > 1)
+ volume_id = astra_mex_data3d('create','-vol', vol_geom, data);
+else
+ volume_id = data;
+end
+
+% store sino
+sino_id = astra_mex_data3d('create','-sino', proj_geom, 0);
+
+% create sinogram
+cfg = astra_struct('FP3D_CUDA');
+cfg.ProjectionDataId = sino_id;
+cfg.VolumeDataId = volume_id;
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id);
+astra_mex_algorithm('delete', alg_id);
+
+if (numel(data) > 1)
+ astra_mex_data3d('delete', volume_id);
+end
+
+if nargout >= 2
+ sino = astra_mex_data3d('get',sino_id);
+end
+
+
+
diff --git a/matlab/tools/astra_create_sino_cuda.m b/matlab/tools/astra_create_sino_cuda.m
new file mode 100644
index 0000000..82bda7c
--- /dev/null
+++ b/matlab/tools/astra_create_sino_cuda.m
@@ -0,0 +1,58 @@
+function [sino_id, sino] = astra_create_sino_cuda(data, proj_geom, vol_geom, gpu_index)
+
+%--------------------------------------------------------------------------
+% [sino_id, sino] = astra_create_sino_cuda(data, proj_geom, vol_geom, gpu_index)
+%
+% Create a GPU based forward projection.
+%
+% data: input volume, can be either MATLAB-data or an astra-identifier.
+% proj_geom: MATLAB struct containing the projection geometry.
+% vol_geom: MATLAB struct containing the volume geometry.
+% gpu_index: the index of the GPU to use (optional).
+% sino_id: identifier of the sinogram data object as it is now stored in
+% the astra-library.
+% sino: MATLAB data version of the sinogram.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+% store volume
+if (numel(data) > 1)
+ volume_id = astra_mex_data2d('create','-vol', vol_geom, data);
+else
+ volume_id = data;
+end
+
+% store sino
+sino_id = astra_mex_data2d('create','-sino', proj_geom, 0);
+
+% create sinogram
+cfg = astra_struct('FP_CUDA');
+cfg.ProjectionDataId = sino_id;
+cfg.VolumeDataId = volume_id;
+if nargin > 3
+ cfg.option.GPUindex = gpu_index;
+end
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id);
+astra_mex_algorithm('delete', alg_id);
+
+if (numel(data) > 1)
+ astra_mex_data2d('delete', volume_id);
+end
+
+if nargout >= 2
+ sino = astra_mex_data2d('get',sino_id);
+end
+
+
+
diff --git a/matlab/tools/astra_create_sino_gpu.m b/matlab/tools/astra_create_sino_gpu.m
new file mode 100644
index 0000000..95a3b09
--- /dev/null
+++ b/matlab/tools/astra_create_sino_gpu.m
@@ -0,0 +1,58 @@
+function [sino_id, sino] = astra_create_sino_gpu(data, proj_geom, vol_geom, gpu_index)
+
+%--------------------------------------------------------------------------
+% [sino_id, sino] = astra_create_sino_gpu(data, proj_geom, vol_geom, gpu_index)
+%
+% Create a GPU based forward projection.
+%
+% data: input volume, can be either MATLAB-data or an astra-identifier.
+% proj_geom: MATLAB struct containing the projection geometry.
+% vol_geom: MATLAB struct containing the volume geometry.
+% gpu_index: the index of the GPU to use (optional).
+% sino_id: identifier of the sinogram data object as it is now stored in
+% the astra-library.
+% sino: MATLAB data version of the sinogram.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+% store volume
+if (numel(data) > 1)
+ volume_id = astra_mex_data2d('create','-vol', vol_geom, data);
+else
+ volume_id = data;
+end
+
+% store sino
+sino_id = astra_mex_data2d('create','-sino', proj_geom, 0);
+
+% create sinogram
+cfg = astra_struct('FP_CUDA');
+cfg.ProjectionDataId = sino_id;
+cfg.VolumeDataId = volume_id;
+if nargin > 3
+ cfg.option.GPUindex = gpu_index;
+end
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id);
+astra_mex_algorithm('delete', alg_id);
+
+if (numel(data) > 1)
+ astra_mex_data2d('delete', volume_id);
+end
+
+if nargout >= 2
+ sino = astra_mex_data2d('get',sino_id);
+end
+
+
+
diff --git a/matlab/tools/astra_create_sino_sampling.m b/matlab/tools/astra_create_sino_sampling.m
new file mode 100644
index 0000000..6b86d61
--- /dev/null
+++ b/matlab/tools/astra_create_sino_sampling.m
@@ -0,0 +1,59 @@
+function [sino_id, sino] = astra_create_sino_sampling(data, proj_geom, vol_geom, gpu_index, sampling)
+
+%--------------------------------------------------------------------------
+% [sino_id, sino] = astra_create_sino_cuda(data, proj_geom, vol_geom, gpu_index)
+%
+% Create a GPU based forward projection.
+%
+% data: input volume, can be either MATLAB-data or an astra-identifier.
+% proj_geom: MATLAB struct containing the projection geometry.
+% vol_geom: MATLAB struct containing the volume geometry.
+% gpu_index: the index of the GPU to use (optional).
+% sino_id: identifier of the sinogram data object as it is now stored in
+% the astra-library.
+% sino: MATLAB data version of the sinogram.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+
+% store volume
+if (numel(data) > 1)
+ volume_id = astra_mex_data2d('create','-vol', vol_geom, data);
+else
+ volume_id = data;
+end
+
+% store sino
+sino_id = astra_mex_data2d('create','-sino', proj_geom, 0);
+
+% create sinogram
+cfg = astra_struct('FP_CUDA');
+cfg.ProjectionDataId = sino_id;
+cfg.VolumeDataId = volume_id;
+cfg.option.DetectorSuperSampling = sampling;
+if nargin > 3
+ cfg.option.GPUindex = gpu_index;
+end
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id);
+astra_mex_algorithm('delete', alg_id);
+
+if (numel(data) > 1)
+ astra_mex_data2d('delete', volume_id);
+end
+
+if nargout >= 2
+ sino = astra_mex_data2d('get',sino_id);
+end
+
+
+
diff --git a/matlab/tools/astra_create_vol_geom.m b/matlab/tools/astra_create_vol_geom.m
new file mode 100644
index 0000000..61db8fb
--- /dev/null
+++ b/matlab/tools/astra_create_vol_geom.m
@@ -0,0 +1,96 @@
+function vol_geom = astra_create_vol_geom(varargin)
+
+%--------------------------------------------------------------------------
+% vol_geom = astra_create_vol_geom([row_count col_count]);
+% vol_geom = astra_create_vol_geom(row_count, col_count);
+% vol_geom = astra_create_vol_geom(row_count, col_count, min_x, max_x, min_y, max_y);
+%
+% Create a 2D volume geometry. See the API for more information.
+% row_count: number of rows.
+% col_count: number of columns.
+% min_x: minimum value on the x-axis.
+% max_x: maximum value on the x-axis.
+% min_y: minimum value on the y-axis.
+% max_y: maximum value on the y-axis.
+% vol_geom: MATLAB struct containing all information of the geometry.
+%--------------------------------------------------------------------------
+% vol_geom = astra_create_vol_geom(row_count, col_count, slice_count);
+%
+% Create a 3D volume geometry. See the API for more information.
+% row_count: number of rows.
+% col_count: number of columns.
+% slice_count: number of slices.
+% vol_geom: MATLAB struct containing all information of the geometry.
+%--------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+% astra_create_vol_geom([row_and_col_count ])
+if numel(varargin) == 1 && numel(varargin{1}) == 1
+ vol_geom = struct();
+ vol_geom.GridRowCount = varargin{1}(1);
+ vol_geom.GridColCount = varargin{1}(1);
+ vol_geom.option.WindowMinX = -varargin{1}(1) / 2;
+ vol_geom.option.WindowMaxX = varargin{1}(1) / 2;
+ vol_geom.option.WindowMinY = -varargin{1}(1) / 2;
+ vol_geom.option.WindowMaxY = varargin{1}(1) / 2;
+
+
+% astra_create_vol_geom([row_count col_count])
+elseif numel(varargin) == 1 && numel(varargin{1}) == 2
+ vol_geom = struct();
+ vol_geom.GridRowCount = varargin{1}(1);
+ vol_geom.GridColCount = varargin{1}(2);
+ vol_geom.option.WindowMinX = -varargin{1}(2) / 2;
+ vol_geom.option.WindowMaxX = varargin{1}(2) / 2;
+ vol_geom.option.WindowMinY = -varargin{1}(1) / 2;
+ vol_geom.option.WindowMaxY = varargin{1}(1) / 2;
+
+% astra_create_vol_geom([row_count col_count slice_count])
+elseif numel(varargin) == 1 && numel(varargin{1}) == 3
+ vol_geom = struct();
+ vol_geom.GridRowCount = varargin{1}(1);
+ vol_geom.GridColCount = varargin{1}(2);
+ vol_geom.GridSliceCount = varargin{1}(3);
+ vol_geom.option.WindowMinX = -varargin{1}(2) / 2;
+ vol_geom.option.WindowMaxX = varargin{1}(2) / 2;
+ vol_geom.option.WindowMinY = -varargin{1}(1) / 2;
+ vol_geom.option.WindowMaxY = varargin{1}(1) / 2;
+ vol_geom.option.WindowMinZ = -varargin{1}(3) / 2;
+ vol_geom.option.WindowMaxZ = varargin{1}(3) / 2;
+
+% astra_create_vol_geom(row_count, col_count)
+elseif numel(varargin) == 2
+ vol_geom = struct();
+ vol_geom.GridRowCount = varargin{1};
+ vol_geom.GridColCount = varargin{2};
+ vol_geom.option.WindowMinX = -varargin{2} / 2;
+ vol_geom.option.WindowMaxX = varargin{2} / 2;
+ vol_geom.option.WindowMinY = -varargin{1} / 2;
+ vol_geom.option.WindowMaxY = varargin{1} / 2;
+
+% astra_create_vol_geom(row_count, col_count, min_x, max_x, min_y, max_y)
+elseif numel(varargin) == 6
+ vol_geom = struct();
+ vol_geom.GridRowCount = varargin{1};
+ vol_geom.GridColCount = varargin{2};
+ vol_geom.option.WindowMinX = varargin{3};
+ vol_geom.option.WindowMaxX = varargin{4};
+ vol_geom.option.WindowMinY = varargin{5};
+ vol_geom.option.WindowMaxY = varargin{6};
+
+% astra_create_vol_geom(row_count, col_count, slice_count)
+elseif numel(varargin) == 3
+ vol_geom = struct();
+ vol_geom.GridRowCount = varargin{1};
+ vol_geom.GridColCount = varargin{2};
+ vol_geom.GridSliceCount = varargin{3};
+end
diff --git a/matlab/tools/astra_data_gui.fig b/matlab/tools/astra_data_gui.fig
new file mode 100644
index 0000000..d73e430
--- /dev/null
+++ b/matlab/tools/astra_data_gui.fig
Binary files differ
diff --git a/matlab/tools/astra_data_gui.m b/matlab/tools/astra_data_gui.m
new file mode 100644
index 0000000..337a5d4
--- /dev/null
+++ b/matlab/tools/astra_data_gui.m
@@ -0,0 +1,396 @@
+function varargout = astra_data_gui(varargin)
+% ASTRA_DATA_GUI M-file for ASTRA_DATA_GUI.fig
+% ASTRA_DATA_GUI, by itself, creates a new ASTRA_DATA_GUI or raises the existing
+% singleton*.
+%
+% H = ASTRA_DATA_GUI returns the handle to a new ASTRA_DATA_GUI or the handle to
+% the existing singleton*.
+%
+% ASTRA_DATA_GUI('CALLBACK',hObject,eventData,handles,...) calls the local
+% function named CALLBACK in ASTRA_DATA_GUI.M with the given input arguments.
+%
+% ASTRA_DATA_GUI('Property','Value',...) creates a new ASTRA_DATA_GUI or raises the
+% existing singleton*. Starting from the left, property value pairs are
+% applied to the GUI before ASTRA_DATA_GUI_OpeningFcn gets called. An
+% unrecognized property name or invalid value makes property application
+% stop. All inputs are passed to ASTRA_DATA_GUI_OpeningFcn via varargin.
+%
+% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
+% instance to run (singleton)".
+%
+% See also: GUIDE, GUIDATA, GUIHANDLES
+
+% Edit the above text to modify the response to help ASTRA_DATA_GUI
+
+% Last Modified by GUIDE v2.5 05-Mar-2012 14:34:03
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name', mfilename, ...
+ 'gui_Singleton', gui_Singleton, ...
+ 'gui_OpeningFcn', @astra_data_gui_OpeningFcn, ...
+ 'gui_OutputFcn', @astra_data_gui_OutputFcn, ...
+ 'gui_LayoutFcn', [] , ...
+ 'gui_Callback', []);
+if nargin && ischar(varargin{1})
+ gui_State.gui_Callback = str2func(varargin{1});
+end
+
+if nargout
+ [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+ gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+
+% --- Executes just before astra_data_gui is made visible.
+function astra_data_gui_OpeningFcn(hObject, eventdata, handles, varargin)
+% This function has no output args, see OutputFcn.
+% hObject handle to figure
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+% varargin command line arguments to astra_data_gui (see VARARGIN)
+
+% Choose default command line output for astra_data_gui
+handles.output = hObject;
+handles.data = [];
+
+% Update handles structure
+guidata(hObject, handles);
+
+% UIWAIT makes astra_data_gui wait for user response (see UIRESUME)
+% uiwait(handles.figure1);
+
+
+% --- Outputs from this function are returned to the command line.
+function varargout = astra_data_gui_OutputFcn(hObject, eventdata, handles)
+% varargout cell array for returning output args (see VARARGOUT);
+% hObject handle to figure
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+% Get default command line output from handles structure
+varargout{1} = handles.output;
+
+
+% Use this function to display a figure using the gui from any m-file
+% example:
+% Handle = astra_data_gui();
+% astra_data_gui('loadVolume',guihandles(Handle),'rand(30,30,30)',15);
+function loadVolume(handles,name,figure_number)
+set(handles.txt_var, 'String', name);
+set(handles.figure_number, 'String', num2str(figure_number));
+btn_load_Callback(handles.txt_var, [], handles);
+
+
+
+
+
+function txt_var_Callback(hObject, eventdata, handles) %#ok<*DEFNU>
+% hObject handle to txt_var (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+% Hints: get(hObject,'String') returns contents of txt_var as text
+% str2double(get(hObject,'String')) returns contents of txt_var as a double
+
+
+% --- Executes during object creation, after setting all properties.
+function txt_var_CreateFcn(hObject, eventdata, handles)
+% hObject handle to txt_var (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles empty - handles not created until after all CreateFcns called
+
+% Hint: edit controls usually have a white background on Windows.
+% See ISPC and COMPUTER.
+if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+ set(hObject,'BackgroundColor','white');
+end
+
+
+% --- Executes on button press in btn_load.
+function btn_load_Callback(hObject, eventdata, handles)
+% hObject handle to btn_load (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+s = get(handles.txt_var, 'String');
+data = evalin('base', s);
+handles.data = data;
+guidata(hObject, handles);
+
+% Set Default Stuff
+set(handles.sld_slice, 'Min',1);
+set(handles.sld_slice, 'Max', size(data,3));
+set(handles.sld_slice, 'SliderStep', [1/(size(data,3)-2) 1/(size(data,3)-2)]);
+set(handles.sld_slice, 'Value', size(data,3)/2);
+
+sliderValue = floor(get(handles.sld_slice, 'Value'));
+set(handles.txt_slice, 'String', num2str(sliderValue));
+set(handles.txt_min, 'String', num2str(1));
+set(handles.txt_max, 'String', num2str(size(data,3)));
+
+set(handles.sld_magnification, 'Min',1);
+set(handles.sld_magnification, 'Max', 400);
+set(handles.sld_magnification, 'SliderStep', [1/(400-2) 1/(400-2)]);
+set(handles.sld_magnification, 'Value', 100);
+
+sliderValue3 = floor(get(handles.sld_magnification, 'Value'));
+set(handles.txt_mag, 'String', num2str(sliderValue3));
+
+
+figure_number = floor(str2double(get(handles.figure_number, 'String')));
+if(isnan(figure_number) || figure_number < 1)
+ set(handles.figure_number, 'String', num2str(10));
+end
+
+showimage(handles);
+
+% --- SHOW IMAGE
+function showimage(handles)
+ sliderValue = floor(get(handles.sld_slice, 'Value'));
+ magnification = floor(get(handles.sld_magnification, 'Value'));
+ figure_number = floor(str2double(get(handles.figure_number, 'String')));
+ image_matrix = handles.data;
+ if get(handles.btn_x, 'Value') == 1
+ figure(figure_number), imshow(sliceExtractor((image_matrix(:,:,:)), 'y', sliderValue),[],'InitialMagnification', magnification);
+ ylabel('y')
+ xlabel('z')
+ set(gcf,'Name','ASTRA DATA GUI')
+ elseif get(handles.btn_y, 'Value') == 1
+ figure(figure_number), imshow(sliceExtractor((image_matrix(:,:,:)), 'x', sliderValue),[],'InitialMagnification', magnification);
+ ylabel('x')
+ xlabel('z')
+ set(gcf,'Name','ASTRA DATA GUI')
+ else
+ figure(figure_number), imshow(sliceExtractor((image_matrix(:,:,:)), 'z', sliderValue),[],'InitialMagnification', magnification);
+ ylabel('x')
+ xlabel('y')
+ set(gcf,'Name','ASTRA DATA GUI')
+ end
+
+
+% --- Executes on slider movement.
+function sld_slice_Callback(hObject, eventdata, handles)
+% hObject handle to sld_slice (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+sliderValue = floor(get(handles.sld_slice, 'Value'));
+set(handles.txt_slice, 'String', num2str(sliderValue));
+showimage(handles);
+
+% --- Executes during object creation, after setting all properties.
+function sld_slice_CreateFcn(hObject, eventdata, handles)
+% hObject handle to sld_slice (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles empty - handles not created until after all CreateFcns called
+
+% Hint: slider controls usually have a light gray background.
+if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+ set(hObject,'BackgroundColor',[.9 .9 .9]);
+end
+
+
+% --- Executes on button press in pushbutton2.
+function pushbutton2_Callback(hObject, eventdata, handles)
+% hObject handle to pushbutton2 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+
+% --- Executes on button press in pushbutton3.
+function pushbutton3_Callback(hObject, eventdata, handles)
+% hObject handle to pushbutton3 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+
+% --- Executes on button press in pushbutton4.
+function pushbutton4_Callback(hObject, eventdata, handles)
+% hObject handle to pushbutton4 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+
+function txt_slice_Callback(hObject, eventdata, handles)
+% hObject handle to txt_slice (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+slice = str2double(get(handles.txt_slice, 'String'));
+max = str2num(get(handles.txt_max,'String'));
+min = str2num(get(handles.txt_min,'String'));
+if(slice > max)
+ set(handles.txt_slice, 'String', num2str(max));
+ set(handles.sld_slice, 'Value', max);
+elseif(slice < min)
+ set(handles.txt_slice, 'String', num2str(min));
+ set(handles.sld_slice, 'Value', min);
+else
+ set(handles.sld_slice, 'Value', slice);
+end
+showimage(handles);
+
+% --- Executes during object creation, after setting all properties.
+function txt_slice_CreateFcn(hObject, eventdata, handles)
+% hObject handle to txt_slice (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles empty - handles not created until after all CreateFcns called
+
+% Hint: edit controls usually have a white background on Windows.
+% See ISPC and COMPUTER.
+if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+ set(hObject,'BackgroundColor','white');
+end
+
+% --- Executes on slider movement.
+function sld_magnification_Callback(hObject, eventdata, handles)
+% hObject handle to sld_slice2 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+% Hints: get(hObject,'Value') returns position of slider
+% get(hObject,'Min') and get(hObject,'Max') to determine range of slider
+sliderValue3 = floor(get(handles.sld_magnification, 'Value'));
+set(handles.txt_mag, 'String', num2str(sliderValue3));
+
+if(~isempty(handles.data))
+ showimage(handles);
+end
+
+
+
+% --- Executes during object creation, after setting all properties.
+function sld_magnification_CreateFcn(hObject, eventdata, handles)
+% hObject handle to sld_slice2 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles empty - handles not created until after all CreateFcns called
+% Hint: slider controls usually have a light gray background.
+if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+ set(hObject,'BackgroundColor',[.9 .9 .9]);
+end
+
+
+function txt_mag_Callback(hObject, eventdata, handles)
+% hObject handle to txt_slice2 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+magnification = str2double(get(handles.txt_mag, 'String'));
+if(magnification > 400)
+ set(handles.txt_mag, 'String', num2str(400));
+ set(handles.sld_magnification, 'Value', 400);
+elseif(magnification < 1)
+ set(handles.txt_mag, 'String', num2str(1));
+ set(handles.sld_magnification, 'Value', 1);
+else
+ set(handles.sld_magnification, 'Value', magnification);
+end
+
+if(~isempty(handles.data))
+ showimage(handles);
+end
+
+% --- Executes during object creation, after setting all properties.
+function txt_mag_CreateFcn(hObject, eventdata, handles)
+% hObject handle to txt_slice2 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles empty - handles not created until after all CreateFcns called
+
+% Hint: edit controls usually have a white background on Windows.
+% See ISPC and COMPUTER.
+if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+ set(hObject,'BackgroundColor','white');
+end
+
+% --- Executes on slider movement.
+function figure_number_Callback(hObject, eventdata, handles)
+% hObject handle to sld_slice2 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles structure with handles and user data (see GUIDATA)
+
+% Hints: get(hObject,'Value') returns position of slider
+% get(hObject,'Min') and get(hObject,'Max') to determine range of slider
+number = floor(str2double(get(handles.figure_number, 'String')));
+if(number < 1)
+ set(handles.figure_number, 'String', num2str(1));
+else
+ set(handles.figure_number, 'String', num2str(number));
+end
+
+if(~isempty(handles.data))
+ showimage(handles);
+end
+
+
+% --- Executes during object creation, after setting all properties.
+function figure_number_CreateFcn(hObject, eventdata, handles)
+% hObject handle to sld_slice2 (see GCBO)
+% eventdata reserved - to be defined in a future version of MATLAB
+% handles empty - handles not created until after all CreateFcns called
+% Hint: slider controls usually have a light gray background.
+if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+ set(hObject,'BackgroundColor',[.9 .9 .9]);
+end
+
+
+
+% --- Executes when selected object is changed in btn_dir.
+function btn_dir_SelectionChangeFcn(hObject, eventdata, handles)
+% hObject handle to the selected object in btn_dir
+% eventdata structure with the following fields (see UIBUTTONGROUP)
+% EventName: string 'SelectionChanged' (read only)
+% OldValue: handle of the previously selected object or empty if none was selected
+% NewValue: handle of the currently selected object
+% handles structure with handles and user data (see GUIDATA)
+
+data = handles.data;
+
+if(hObject == handles.btn_x)
+ set(handles.btn_x, 'Value', 1);
+ set(handles.btn_y, 'Value', 0);
+ set(handles.btn_z, 'Value', 0);
+elseif(hObject == handles.btn_y)
+ set(handles.btn_x, 'Value', 0);
+ set(handles.btn_y, 'Value', 1);
+ set(handles.btn_z, 'Value', 0);
+elseif(hObject == handles.btn_z)
+ set(handles.btn_x, 'Value', 0);
+ set(handles.btn_y, 'Value', 0);
+ set(handles.btn_z, 'Value', 1);
+end
+
+if get(handles.btn_x, 'Value') == 1
+ set(handles.sld_slice, 'Min',1);
+ set(handles.sld_slice, 'Max', size(data,1));
+ set(handles.sld_slice, 'SliderStep', [1/(size(data,1)-2) 1/(size(data,1)-2)]);
+ set(handles.sld_slice, 'Value', size(data,1)/2);
+
+ sliderValue = get(handles.sld_slice, 'Value');
+ set(handles.txt_slice, 'String', num2str(sliderValue));
+ set(handles.txt_min, 'String', num2str(1));
+ set(handles.txt_max, 'String', num2str(size(data,1)));
+
+elseif get(handles.btn_y, 'Value') == 1
+ set(handles.sld_slice, 'Min',1);
+ set(handles.sld_slice, 'Max', size(data,2));
+ set(handles.sld_slice, 'SliderStep', [1/(size(data,2)-2) 1/(size(data,2)-2)]);
+ set(handles.sld_slice, 'Value', size(data,2)/2);
+
+ sliderValue = get(handles.sld_slice, 'Value');
+ set(handles.txt_slice, 'String', num2str(sliderValue));
+ set(handles.txt_min, 'String', num2str(1));
+ set(handles.txt_max, 'String', num2str(size(data,2)));
+else
+ set(handles.sld_slice, 'Min',1);
+ set(handles.sld_slice, 'Max', size(data,3));
+ set(handles.sld_slice, 'SliderStep', [1/(size(data,3)-2) 1/(size(data,3)-2)]);
+ set(handles.sld_slice, 'Value', size(data,3)/2);
+
+ sliderValue = get(handles.sld_slice, 'Value');
+ set(handles.txt_slice, 'String', num2str(sliderValue));
+ set(handles.txt_min, 'String', num2str(1));
+ set(handles.txt_max, 'String', num2str(size(data,3)));
+end
+
+showimage(handles);
diff --git a/matlab/tools/astra_data_op.m b/matlab/tools/astra_data_op.m
new file mode 100644
index 0000000..b6ef0e2
--- /dev/null
+++ b/matlab/tools/astra_data_op.m
@@ -0,0 +1,11 @@
+function astra_data_op(op, data, scalar, gpu_core)
+
+cfg = astra_struct('DataOperation_CUDA');
+cfg.Operation = op;
+cfg.Scalar = scalar;
+cfg.DataId = data;
+cfg.option.GPUindex = gpu_core;
+
+alg_id = astra_mex_algorithm('create',cfg);
+astra_mex_algorithm('run',alg_id);
+astra_mex_algorithm('delete',alg_id); \ No newline at end of file
diff --git a/matlab/tools/astra_data_op_mask.m b/matlab/tools/astra_data_op_mask.m
new file mode 100644
index 0000000..d46c925
--- /dev/null
+++ b/matlab/tools/astra_data_op_mask.m
@@ -0,0 +1,12 @@
+function astra_data_op_mask(op, data, scalar, mask, gpu_core)
+
+cfg = astra_struct('DataOperation_CUDA');
+cfg.Operation = op;
+cfg.Scalar = scalar;
+cfg.DataId = data;
+cfg.option.GPUindex = gpu_core;
+cfg.option.MaskId = mask;
+
+alg_id = astra_mex_algorithm('create',cfg);
+astra_mex_algorithm('run',alg_id);
+astra_mex_algorithm('delete',alg_id); \ No newline at end of file
diff --git a/matlab/tools/astra_downsample_sinogram.m b/matlab/tools/astra_downsample_sinogram.m
new file mode 100644
index 0000000..30c1cdd
--- /dev/null
+++ b/matlab/tools/astra_downsample_sinogram.m
@@ -0,0 +1,36 @@
+function [sinogram_new, proj_geom_new] = astra_downsample_sinogram(sinogram, proj_geom, factor)
+
+%------------------------------------------------------------------------
+% [sinogram_new, proj_geom_new] = astra_downsample_sinogram(sinogram, proj_geom, factor)
+%
+% Downsample the sinogram with some factor and adjust projection geometry
+% accordingly
+%
+% sinogram: MATLAB data version of the sinogram.
+% proj_geom: MATLAB struct containing the projection geometry.
+% factor: the factor by which the number of detectors is divided.
+% sinogram_new: MATLAB data version of the resampled sinogram.
+% proj_geom_new: MATLAB struct containing the new projection geometry.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+if mod(size(sinogram,2),factor) ~= 0
+ disp('size of the sinogram must be a divisor of the factor');
+end
+
+sinogram_new = zeros(size(sinogram,1),size(sinogram,2)/factor);
+for i = 1:size(sinogram,2)/factor
+ sinogram_new(:,i) = sum(sinogram(:,(factor*(i-1)+1):factor*i),2);
+end
+
+proj_geom_new = proj_geom;
+proj_geom_new.DetectorCount = proj_geom_new.DetectorCount / factor;
diff --git a/matlab/tools/astra_geom_2vec.m b/matlab/tools/astra_geom_2vec.m
new file mode 100644
index 0000000..0abd07c
--- /dev/null
+++ b/matlab/tools/astra_geom_2vec.m
@@ -0,0 +1,84 @@
+function proj_geom_out = astra_geom_2vec(proj_geom)
+
+ % FANFLAT
+ if strcmp(proj_geom.type,'fanflat')
+
+ vectors = zeros(numel(proj_geom.ProjectionAngles), 6);
+ for i = 1:numel(proj_geom.ProjectionAngles)
+
+ % source
+ vectors(i,1) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginSource;
+ vectors(i,2) = -cos(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginSource;
+
+ % center of detector
+ vectors(i,3) = -sin(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginDetector;
+ vectors(i,4) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginDetector;
+
+ % vector from detector pixel 0 to 1
+ vectors(i,5) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorWidth;
+ vectors(i,6) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorWidth;
+ end
+
+ proj_geom_out = astra_create_proj_geom('fanflat_vec', proj_geom.DetectorCount, vectors);
+
+ % CONE
+ elseif strcmp(proj_geom.type,'cone')
+
+ vectors = zeros(numel(proj_geom.ProjectionAngles), 12);
+ for i = 1:numel(proj_geom.ProjectionAngles)
+
+ % source
+ vectors(i,1) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginSource;
+ vectors(i,2) = -cos(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginSource;
+ vectors(i,3) = 0;
+
+ % center of detector
+ vectors(i,4) = -sin(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginDetector;
+ vectors(i,5) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DistanceOriginDetector;
+ vectors(i,6) = 0;
+
+ % vector from detector pixel (0,0) to (0,1)
+ vectors(i,7) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorSpacingX;
+ vectors(i,8) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorSpacingX;
+ vectors(i,9) = 0;
+
+ % vector from detector pixel (0,0) to (1,0)
+ vectors(i,10) = 0;
+ vectors(i,11) = 0;
+ vectors(i,12) = proj_geom.DetectorSpacingY;
+ end
+
+ proj_geom_out = astra_create_proj_geom('cone_vec', proj_geom.DetectorRowCount, proj_geom.DetectorColCount, vectors);
+
+ % PARALLEL
+ elseif strcmp(proj_geom.type,'parallel3d')
+
+ vectors = zeros(numel(proj_geom.ProjectionAngles), 12);
+ for i = 1:numel(proj_geom.ProjectionAngles)
+
+ % ray direction
+ vectors(i,1) = sin(proj_geom.ProjectionAngles(i));
+ vectors(i,2) = -cos(proj_geom.ProjectionAngles(i));
+ vectors(i,3) = 0;
+
+ % center of detector
+ vectors(i,4) = 0;
+ vectors(i,5) = 0;
+ vectors(i,6) = 0;
+
+ % vector from detector pixel (0,0) to (0,1)
+ vectors(i,7) = cos(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorSpacingX;
+ vectors(i,8) = sin(proj_geom.ProjectionAngles(i)) * proj_geom.DetectorSpacingX;
+ vectors(i,9) = 0;
+
+ % vector from detector pixel (0,0) to (1,0)
+ vectors(i,10) = 0;
+ vectors(i,11) = 0;
+ vectors(i,12) = proj_geom.DetectorSpacingY;
+ end
+
+ proj_geom_out = astra_create_proj_geom('parallel3d_vec', proj_geom.DetectorRowCount, proj_geom.DetectorColCount, vectors);
+
+ else
+ error(['No suitable vector geometry found for type: ' proj_geom.type])
+ end
diff --git a/matlab/tools/astra_geom_postalignment.m b/matlab/tools/astra_geom_postalignment.m
new file mode 100644
index 0000000..4115af2
--- /dev/null
+++ b/matlab/tools/astra_geom_postalignment.m
@@ -0,0 +1,11 @@
+function proj_geom = astra_geom_postalignment(proj_geom, factor)
+
+ if strcmp(proj_geom.type,'fanflat_vec')
+ proj_geom.Vectors(:,3:4) = proj_geom.Vectors(:,3:4) + factor * proj_geom.Vectors(:,5:6);
+
+ elseif strcmp(proj_geom.type,'cone_vec') || strcmp(proj_geom.type,'parallel3d_vec')
+ proj_geom.Vectors(:,4:6) = proj_geom.Vectors(:,4:6) + factor * proj_geom.Vectors(:,7:9);
+
+ else
+ error('Projection geometry not suited for postalignment correction.')
+ end
diff --git a/matlab/tools/astra_geom_size.m b/matlab/tools/astra_geom_size.m
new file mode 100644
index 0000000..c4956f5
--- /dev/null
+++ b/matlab/tools/astra_geom_size.m
@@ -0,0 +1,28 @@
+function s = astra_geom_size(geom, dim)
+
+ if isfield(geom, 'GridSliceCount')
+ % 3D Volume geometry?
+ s = [ geom.GridColCount, geom.GridRowCount, geom.GridSliceCount ];
+ elseif isfield(geom, 'GridColCount')
+ % 2D Volume geometry?
+ s = [ geom.GridRowCount, geom.GridColCount ];
+ elseif strcmp(geom.type,'parallel') || strcmp(geom.type,'fanflat')
+ s = [numel(geom.ProjectionAngles), geom.DetectorCount];
+
+ elseif strcmp(geom.type,'parallel3d') || strcmp(geom.type,'cone')
+ s = [geom.DetectorRowCount, numel(geom.ProjectionAngles), geom.DetectorColCount];
+
+ elseif strcmp(geom.type,'fanflat_vec')
+ s = [size(geom.Vectors,1), geom.DetectorCount];
+
+ elseif strcmp(geom.type,'parallel3d_vec') || strcmp(geom.type,'cone_vec')
+ s = [geom.DetectorColCount, size(geom.Vectors,1), geom.DetectorRowCount];
+
+ end
+
+ if nargin == 2
+ s = s(dim);
+ end
+
+end
+
diff --git a/matlab/tools/astra_geom_superresolution.m b/matlab/tools/astra_geom_superresolution.m
new file mode 100644
index 0000000..b2b0ebf
--- /dev/null
+++ b/matlab/tools/astra_geom_superresolution.m
@@ -0,0 +1,14 @@
+function proj_geom = astra_geom_superresolution(proj_geom, factor)
+
+ if strcmp(proj_geom.type,'parallel')
+ proj_geom.DetectorWidth = proj_geom.DetectorWidth/factor;
+ proj_geom.DetectorCount = proj_geom.DetectorCount * factor;
+ elseif strcmp(proj_geom.type,'fanflat')
+ proj_geom.DetectorWidth = proj_geom.DetectorWidth/factor;
+ proj_geom.DetectorCount = proj_geom.DetectorCount * factor;
+ elseif strcmp(proj_geom.type,'fanflat_vec')
+ proj_geom.Vectors(:,5:6) = proj_geom.Vectors(:,5:6) / factor; % DetectorSize
+ proj_geom.DetectorCount = proj_geom.DetectorCount * factor;
+ else
+ error('Projection geometry not suited for super-resolution (or not implemented).')
+ end
diff --git a/matlab/tools/astra_imshow.m b/matlab/tools/astra_imshow.m
new file mode 100644
index 0000000..6069674
--- /dev/null
+++ b/matlab/tools/astra_imshow.m
@@ -0,0 +1,10 @@
+function V = astra_imshow(data, range)
+
+if numel(data) == 1
+ data = astra_mex_data2d('get', data);
+end
+imshow(data,range);
+
+if nargout >= 1
+ V = data;
+end \ No newline at end of file
diff --git a/matlab/tools/astra_mex.m b/matlab/tools/astra_mex.m
new file mode 100644
index 0000000..e04cfea
--- /dev/null
+++ b/matlab/tools/astra_mex.m
@@ -0,0 +1,24 @@
+function [varargout] = astra_mex(varargin)
+%------------------------------------------------------------------------
+% Reference page in Help browser
+% <a href="matlab:docsearch('astra_mex' )">astra_mex</a>.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+if nargout == 0
+ astra_mex_c(varargin{:});
+ if exist('ans','var')
+ varargout{1} = ans;
+ end
+else
+ varargout = cell(1,nargout);
+ [varargout{:}] = astra_mex_c(varargin{:});
+end
diff --git a/matlab/tools/astra_mex_algorithm.m b/matlab/tools/astra_mex_algorithm.m
new file mode 100644
index 0000000..138a43c
--- /dev/null
+++ b/matlab/tools/astra_mex_algorithm.m
@@ -0,0 +1,24 @@
+function [varargout] = astra_mex_algorithm(varargin)
+%------------------------------------------------------------------------
+% Reference page in Help browser
+% <a href="matlab:docsearch('astra_mex_algorithm' )">astra_mex_algorithm</a>.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+if nargout == 0
+ astra_mex_algorithm_c(varargin{:});
+ if exist('ans','var')
+ varargout{1} = ans;
+ end
+else
+ varargout = cell(1,nargout);
+ [varargout{:}] = astra_mex_algorithm_c(varargin{:});
+end
diff --git a/matlab/tools/astra_mex_data2d.m b/matlab/tools/astra_mex_data2d.m
new file mode 100644
index 0000000..eacbcb9
--- /dev/null
+++ b/matlab/tools/astra_mex_data2d.m
@@ -0,0 +1,24 @@
+function [varargout] = astra_mex_data2d(varargin)
+%------------------------------------------------------------------------
+% Reference page in Help browser
+% <a href="matlab:docsearch('astra_mex_data2d' )">astra_mex_data2d</a>.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+if nargout == 0
+ astra_mex_data2d_c(varargin{:});
+ if exist('ans','var')
+ varargout{1} = ans;
+ end
+else
+ varargout = cell(1,nargout);
+ [varargout{:}] = astra_mex_data2d_c(varargin{:});
+end
diff --git a/matlab/tools/astra_mex_data3d.m b/matlab/tools/astra_mex_data3d.m
new file mode 100644
index 0000000..3bbbd68
--- /dev/null
+++ b/matlab/tools/astra_mex_data3d.m
@@ -0,0 +1,24 @@
+function [varargout] = astra_mex_data3d(varargin)
+%------------------------------------------------------------------------
+% Reference page in Help browser
+% <a href="matlab:docsearch('astra_mex_data3d' )">astra_mex_data3d</a>.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+if nargout == 0
+ astra_mex_data3d_c(varargin{:});
+ if exist('ans','var')
+ varargout{1} = ans;
+ end
+else
+ varargout = cell(1,nargout);
+ [varargout{:}] = astra_mex_data3d_c(varargin{:});
+end
diff --git a/matlab/tools/astra_mex_matrix.m b/matlab/tools/astra_mex_matrix.m
new file mode 100644
index 0000000..182ab1e
--- /dev/null
+++ b/matlab/tools/astra_mex_matrix.m
@@ -0,0 +1,24 @@
+function [varargout] = astra_mex_matrix(varargin)
+%------------------------------------------------------------------------
+% Reference page in Help browser
+% <a href="matlab:docsearch('astra_mex_matrix' )">astra_mex_matrix</a>.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+if nargout == 0
+ astra_mex_matrix_c(varargin{:});
+ if exist('ans','var')
+ varargout{1} = ans;
+ end
+else
+ varargout = cell(1,nargout);
+ [varargout{:}] = astra_mex_matrix_c(varargin{:});
+end
diff --git a/matlab/tools/astra_mex_projector.m b/matlab/tools/astra_mex_projector.m
new file mode 100644
index 0000000..487da06
--- /dev/null
+++ b/matlab/tools/astra_mex_projector.m
@@ -0,0 +1,24 @@
+function [varargout] = astra_mex_projector(varargin)
+%------------------------------------------------------------------------
+% Reference page in Help browser
+% <a href="matlab:docsearch('astra_mex_projector' )">astra_mex_projector</a>.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+if nargout == 0
+ astra_mex_projector_c(varargin{:});
+ if exist('ans','var')
+ varargout{1} = ans;
+ end
+else
+ varargout = cell(1,nargout);
+ [varargout{:}] = astra_mex_projector_c(varargin{:});
+end
diff --git a/matlab/tools/astra_mex_projector3d.m b/matlab/tools/astra_mex_projector3d.m
new file mode 100644
index 0000000..3d21ce9
--- /dev/null
+++ b/matlab/tools/astra_mex_projector3d.m
@@ -0,0 +1,24 @@
+function [varargout] = astra_mex_projector3d(varargin)
+%------------------------------------------------------------------------
+% Reference page in Help browser
+% <a href="matlab:docsearch('astra_mex_projector3d' )">astra_mex_projector3d</a>.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+if nargout == 0
+ astra_mex_projector3d_c(varargin{:});
+ if exist('ans','var')
+ varargout{1} = ans;
+ end
+else
+ varargout = cell(1,nargout);
+ [varargout{:}] = astra_mex_projector3d_c(varargin{:});
+end
diff --git a/matlab/tools/astra_projector_handle.m b/matlab/tools/astra_projector_handle.m
new file mode 100644
index 0000000..72d4c73
--- /dev/null
+++ b/matlab/tools/astra_projector_handle.m
@@ -0,0 +1,29 @@
+classdef astra_projector_handle < handle
+ %ASTRA_PROJECTOR_HANDLE Handle class around an astra_mex_projector id
+ % Automatically deletes the projector when deleted.
+
+ %------------------------------------------------------------------------
+ % This file is part of the
+ % All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+ %
+ % Copyright: iMinds-Vision Lab, University of Antwerp
+ % License: Open Source under GPLv3
+ % Contact: mailto:astra@ua.ac.be
+ % Website: http://astra.ua.ac.be
+ %------------------------------------------------------------------------
+
+ properties
+ id
+ end
+
+ methods
+ function obj = astra_projector_handle(proj_id)
+ obj.id = proj_id;
+ end
+ function delete(obj)
+ astra_mex_projector('delete', obj.id);
+ end
+ end
+
+end
+
diff --git a/matlab/tools/astra_set_directory.m b/matlab/tools/astra_set_directory.m
new file mode 100644
index 0000000..1d5a368
--- /dev/null
+++ b/matlab/tools/astra_set_directory.m
@@ -0,0 +1,27 @@
+function in = astra_set_directory(in)
+
+%------------------------------------------------------------------------
+% in = astra_set_directory(in)
+%
+% Creates the directories present in the input path if they do not exist
+% already
+%
+% in: input path.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+a = find(in == '/' | in == '\');
+for i = 1:numel(a)
+ if ~isdir(in(1:a(i)))
+ mkdir(in(1:a(i)));
+ end
+end
diff --git a/matlab/tools/astra_struct.m b/matlab/tools/astra_struct.m
new file mode 100644
index 0000000..f65b2ec
--- /dev/null
+++ b/matlab/tools/astra_struct.m
@@ -0,0 +1,37 @@
+function res = astra_struct(type)
+
+%------------------------------------------------------------------------
+% res = astra_struct(type)
+%
+% Create an ASTRA struct
+%
+% type: type of the struct to be generated.
+% res: the generated matlab struct.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+res = struct();
+res.options = struct();
+
+
+if nargin >= 1
+ % For backward compatibility, transparently accept SIRT_CUDA2
+ % for SIRT_CUDA, and FP_CUDA2 for FP_CUDA.
+ if strcmp(type, 'SIRT_CUDA2')
+ type = 'SIRT_CUDA';
+ warning('SIRT_CUDA2 has been deprecated. Use SIRT_CUDA instead.');
+ end
+ if strcmp(type, 'FP_CUDA2')
+ type = 'FP_CUDA';
+ warning('FP_CUDA2 has been deprecated. Use FP_CUDA instead.');
+ end
+ res.type = type;
+end
diff --git a/matlab/tools/compute_rnmp.m b/matlab/tools/compute_rnmp.m
new file mode 100644
index 0000000..6c00a01
--- /dev/null
+++ b/matlab/tools/compute_rnmp.m
@@ -0,0 +1,29 @@
+function [rnmp, nmp] = compute_rnmp(phantom, S)
+
+ phantom = double(phantom == max(phantom(:)));
+ S = double(S == max(S(:)));
+
+ %u1 = sort(unique(phantom));
+ %u2 = sort(unique(S));
+ %for i = 1:numel(u1)
+ % phantom_(phantom == u1(i)) = i;
+ % S_(S == u2(i)) = i;
+ %end
+ %phantom = phantom_;
+ %S = S_;
+
+ if numel(size(phantom)) == 2
+ S = imresize(S, size(phantom), 'nearest');
+ elseif numel(size(phantom)) == 3
+ S2 = zeros(size(phantom));
+ for slice = 1:size(phantom,3)
+ S2(:,:,slice) = imresize(S(:,:,slice), [size(phantom,1) size(phantom,2)], 'nearest');
+ end
+ S = S2;
+ end
+
+ nmp = sum(abs(phantom(:) ~= S(:)));
+ rnmp = nmp / sum(phantom(:));
+
+end
+
diff --git a/matlab/tools/createOrderART.m b/matlab/tools/createOrderART.m
new file mode 100644
index 0000000..a469d8a
--- /dev/null
+++ b/matlab/tools/createOrderART.m
@@ -0,0 +1,66 @@
+function rayOrder = createOrderART(proj_geom, mode)
+
+%------------------------------------------------------------------------
+% rayOrder = createOrderART(proj_geom, mode)
+%
+% Creates an array defining the order in which ART will iterate over the
+% projections and projection rays
+%
+% proj_geom: MATLAB struct containing the projection geometry.
+% mode: string defining the wanted ray order, can be either 'sequential',
+% 'randomray' or 'randomproj'.
+% rayOrder: array of two columns of length angle_count * det_count, with
+% the first column being the index of the projection and the second column
+% the index of the ray.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+angle_count = length(proj_geom.projection_angles);
+det_count = proj_geom.detector_count;
+
+% create order
+rayOrder = zeros(angle_count * det_count, 2);
+if strcmp(mode,'sequential') == 1
+ index = 1;
+ for i = 1:angle_count
+ for j = 1:det_count
+ rayOrder(index,1) = i;
+ rayOrder(index,2) = j;
+ index = index + 1;
+ end
+ end
+elseif strcmp(mode,'randomray') == 1
+ index = 1;
+ for i = 1:angle_count
+ for j = 1:det_count
+ rayOrder(index,1) = i;
+ rayOrder(index,2) = j;
+ index = index + 1;
+ end
+ end
+ r = randperm(angle_count * det_count);
+ rayOrder(:,1) = rayOrder(r,1);
+ rayOrder(:,2) = rayOrder(r,2);
+elseif strcmp(mode,'randomproj') == 1
+ index = 1;
+ r = randperm(angle_count);
+ for i = 1:angle_count
+ for j = 1:det_count
+ rayOrder(index,1) = r(i);
+ rayOrder(index,2) = j;
+ index = index + 1;
+ end
+ end
+else
+ disp('mode not known');
+end
+
diff --git a/matlab/tools/downsample_sinogram.m b/matlab/tools/downsample_sinogram.m
new file mode 100644
index 0000000..1fb4ec8
--- /dev/null
+++ b/matlab/tools/downsample_sinogram.m
@@ -0,0 +1,12 @@
+function sinogram_out = downsample_sinogram(sinogram, ds)
+
+ if ds == 1
+ sinogram_out = sinogram;
+ return;
+ end
+
+ sinogram_out = sinogram(:,1:ds:end,:);
+ for i = 2:ds
+ sinogram_out = sinogram_out + sinogram(:,i:ds:end,:);
+ end
+ sinogram_out = sinogram_out / (ds*ds); \ No newline at end of file
diff --git a/matlab/tools/imreadgs.m b/matlab/tools/imreadgs.m
new file mode 100644
index 0000000..9c27eb4
--- /dev/null
+++ b/matlab/tools/imreadgs.m
@@ -0,0 +1,26 @@
+function Im = imreadgs(filename)
+
+%------------------------------------------------------------------------
+% Im = imreadgs(filename)
+%
+% Reads an image and transforms it into a grayscale image consisting of
+% doubles.
+%
+% filename: name of the image file.
+% Im: a grayscale image in double.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+Im = double(imread(filename));
+if size(Im,3) > 1
+ Im = Im(:,:,1);
+end
diff --git a/matlab/tools/imresize3D.m b/matlab/tools/imresize3D.m
new file mode 100644
index 0000000..9032cc3
--- /dev/null
+++ b/matlab/tools/imresize3D.m
@@ -0,0 +1,26 @@
+function out = imresize3D(in, s_out, method)
+
+%------------------------------------------------------------------------
+% out = imresize3D(in, s_out, method)
+%
+% Resizes a 3-component image
+%
+% in: input image.
+% s_out: 2 element array with the wanted image size, [rows columns].
+% out: the resized 3-component image.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+out = zeros(s_out);
+for i = 1:size(in,3)
+ out(:,:,i) = imresize(in(:,:,i), s_out(1:2), method);
+end
diff --git a/matlab/tools/imscale.m b/matlab/tools/imscale.m
new file mode 100644
index 0000000..957f11f
--- /dev/null
+++ b/matlab/tools/imscale.m
@@ -0,0 +1,28 @@
+function out = imscale(in)
+
+%------------------------------------------------------------------------
+% out = imscale(in)
+%
+% Rescales the image values between zero and one.
+%
+% in: input image.
+% out: scaled output image.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+mi = min(in(:));
+ma = max(in(:));
+if (ma-mi) == 0
+ out = zeros(size(in));
+else
+ out = (in - mi) / (ma - mi);
+end
diff --git a/matlab/tools/imwritesc.m b/matlab/tools/imwritesc.m
new file mode 100644
index 0000000..2f81dc8
--- /dev/null
+++ b/matlab/tools/imwritesc.m
@@ -0,0 +1,22 @@
+function imwritesc(in, filename)
+
+%------------------------------------------------------------------------
+% imwritesc(in, filename)
+%
+% Rescale between zero and one and write image
+%
+% in: input image.
+% filename: name of output image file.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+imwrite(imscale(in),filename);
diff --git a/matlab/tools/kaiserBessel.m b/matlab/tools/kaiserBessel.m
new file mode 100644
index 0000000..aef7b9d
--- /dev/null
+++ b/matlab/tools/kaiserBessel.m
@@ -0,0 +1,31 @@
+function res = kaiserBessel(m,alpha,a,r)
+
+%------------------------------------------------------------------------
+% res = kaiserBessel(m,alpha,a,r)
+%
+% Calculates the Kaiser windowing function
+%
+% a: length of the sequence.
+% m: order.
+% alpha: determines shape of window.
+% r: input values for which to compute window value.
+% res: the window values.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+sq = sqrt(1 - (r./a).^2);
+
+res1 = 1 ./ besseli(m, alpha);
+res2 = sq .^ m;
+res3 = besseli(m, alpha .* sq);
+
+res = res1 .* res2 .* res3;
diff --git a/matlab/tools/linspace2.m b/matlab/tools/linspace2.m
new file mode 100644
index 0000000..2787fd9
--- /dev/null
+++ b/matlab/tools/linspace2.m
@@ -0,0 +1,25 @@
+function out = linspace2(a,b,c)
+
+%------------------------------------------------------------------------
+% out = linspace2(a,b,c)
+%
+% Generates linearly spaced vectors
+%
+% a: lower limit.
+% b: upper limit (exclusive).
+% c: number of elements.
+% out: linearly spaced vector.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+out = linspace(a,b,c+1);
+out = out(1:end-1);
diff --git a/matlab/tools/overlayImage.m b/matlab/tools/overlayImage.m
new file mode 100644
index 0000000..7c81e55
--- /dev/null
+++ b/matlab/tools/overlayImage.m
@@ -0,0 +1,24 @@
+function im = overlayImage(reconstruction, ground_truth)
+%------------------------------------------------------------------------
+% im = overlayImage(reconstruction, ground_truth)
+%
+% Produces an overlay image of two images, useful for image comparison.
+%
+% reconstruction: first input image matrix.
+% ground_truth: second input image matrix.
+% im: output 3-component image, third channel is 0.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+im(:,:,1) = reconstruction ./ max(reconstruction(:));
+im(:,:,2) = ground_truth ./ max(ground_truth(:));
+im(:,:,3) = zeros(size(reconstruction));
diff --git a/matlab/tools/rebin_fan2par.m b/matlab/tools/rebin_fan2par.m
new file mode 100644
index 0000000..da20932
--- /dev/null
+++ b/matlab/tools/rebin_fan2par.m
@@ -0,0 +1,82 @@
+function F = rebin_fan2par(RadonData, BetaDeg, D, thetaDeg)
+
+%------------------------------------------------------------------------
+% F = rebin_fan2par(RadonData, BetaDeg, D, thetaDeg)
+%
+% Deze functie zet fan beam data om naar parallelle data, door interpolatie
+% (fast resorting algorithm, zie Kak en Slaney)
+% Radondata zoals altijd: eerste coord gamma , de rijen
+% tweede coord beta, de kolommen, beide hoeken in
+% radialen
+% PixPProj: aantal pixels per projectie (voor skyscan data typisch 1000)
+% BetaDeg: vector met alle draaihoeken in graden
+% D: afstand bron - rotatiecentrum in pixels, dus afstand
+% bron-rotatiecentrum(um) gedeeld door image pixel size (um).
+% thetaDeg: vector met gewenste sinogramwaarden voor theta in graden
+% de range van thetaDeg moet steeds kleiner zijn dan die van betadeg
+% D,gamma,beta, theta zoals gebruikt in Kak & Slaney
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+NpixPProj = size(RadonData,1); % aantal pixels per projectie
+%if mod(size(Radondata,1),2)==0
+% NpixPProjNew=NpixPProj+1;
+%else
+ NpixPProjNew = NpixPProj;
+%end
+
+%% FAN-BEAM RAYS
+
+% flip sinogram, why?
+RadonData = flipdim(RadonData,2); % matlab gebruikt tegengestelde draairichting (denkik) als skyscan, of er is een of andere flipdim geweest die gecorrigeerd moet worden))
+
+% DetPixPos: distance of each detector to the ray through the origin (theta)
+DetPixPos = -(NpixPProj-1)/2:(NpixPProj-1)/2; % posities detectorpixels
+
+% GammaStralen: alpha's? (result in radians!!)
+GammaStralen = atan(DetPixPos/D); % alle met de detectorpixelposities overeenkomstige gammahoeken
+
+% put beta (theta) and gamma (alpha) for each ray in 2D matrices
+[beta gamma] = meshgrid(BetaDeg,GammaStralen);
+
+% t: minimal distance between each ray and the ray through the origin
+t = D*sin(gamma); % t-waarden overeenkomstig met de verschillende gamma's
+
+theta = gamma*180/pi + beta; % theta-waarden in graden overeenkomstig met verschillende gamma en beta waarden
+
+%% PARALLEL BEAM RAYS
+
+% DetPixPos: distance of each detector to the ray through the origin (theta)
+DetPixPos = -(NpixPProjNew-1)/2:(NpixPProjNew-1)/2; % posities detectorpixels
+
+% GammaStralen: alpha's? (result in radians!!)
+GammaStralenNew = atan(DetPixPos/D); % alle met de detectorpixelposities overeenkomstige gammahoeken
+
+% put beta (theta) and gamma (alpha) for each ray in 2D matrices
+[~, gamma] = meshgrid(BetaDeg,GammaStralenNew);
+
+% t: minimal distance between each ray and the ray through the origin
+tnew = D * sin(gamma); % t-waarden overeenkomstig met de verschillende gamma's
+
+% calculate new t
+step = (max(tnew)-min(tnew)) / (NpixPProjNew-1);
+t_para = min(tnew):step:max(tnew);
+
+[thetaNewCoord tNewCoord] = meshgrid(thetaDeg, t_para);
+
+%% Interpolate
+Interpolant = TriScatteredInterp(theta(:), t(:), RadonData(:),'nearest');
+F = Interpolant(thetaNewCoord,tNewCoord);
+
+
+
+
diff --git a/matlab/tools/sliceExtractor.m b/matlab/tools/sliceExtractor.m
new file mode 100644
index 0000000..dfc87ee
--- /dev/null
+++ b/matlab/tools/sliceExtractor.m
@@ -0,0 +1,34 @@
+function slice = sliceExtractor(data, dir, slicenr)
+
+%------------------------------------------------------------------------
+% slice = sliceExtractor(data, dir, slicenr)
+%
+% Outputs a specified slice from a three dimensional matrix/volume
+%
+% data: the 3D volume.
+% dir: the direction in which the volume is sliced.
+% slicenr: the index of the slice to retrieve.
+% slice: 2D image matrix containing the slice.
+%------------------------------------------------------------------------
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+% $Id$
+
+slicenr = round(slicenr);
+
+if strcmp(dir,'z')
+ slice = squeeze(data(:,:,slicenr));
+end
+if strcmp(dir,'x')
+ slice = squeeze(data(:,slicenr,:));
+end
+if strcmp(dir,'y')
+ slice = squeeze(data(slicenr,:,:));
+end
diff --git a/samples/s001_sinogram_par2d.m b/samples/s001_sinogram_par2d.m
new file mode 100644
index 0000000..9f50c14
--- /dev/null
+++ b/samples/s001_sinogram_par2d.m
@@ -0,0 +1,33 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+% Create a basic 256x256 square volume geometry
+vol_geom = astra_create_vol_geom(256, 256);
+
+% Create a parallel beam geometry with 180 angles between 0 and pi, and
+% 384 detector pixels of width 1.
+% For more details on available geometries, see the online help of the
+% function astra_create_proj_geom .
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+
+% Create a 256x256 phantom image using matlab's built-in phantom() function
+P = phantom(256);
+
+% Create a sinogram using the GPU.
+% Note that the first time the GPU is accessed, there may be a delay
+% of up to 10 seconds for initialization.
+[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom);
+
+figure(1); imshow(P, []);
+figure(2); imshow(sinogram, []);
+
+
+% Free memory
+astra_mex_data2d('delete', sinogram_id);
diff --git a/samples/s002_data2d.m b/samples/s002_data2d.m
new file mode 100644
index 0000000..37b5549
--- /dev/null
+++ b/samples/s002_data2d.m
@@ -0,0 +1,60 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(256, 256);
+
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+
+
+% Create volumes
+
+% initialized to zero
+v0 = astra_mex_data2d('create', '-vol', vol_geom);
+
+% initialized to 3.0
+v1 = astra_mex_data2d('create', '-vol', vol_geom, 3.0);
+
+% initialized to a matrix. A may be a single, double or logical (0/1) array.
+A = phantom(256);
+v2 = astra_mex_data2d('create', '-vol', vol_geom, A);
+
+
+% Projection data
+s0 = astra_mex_data2d('create', '-sino', proj_geom);
+% Initialization to a scalar or a matrix also works, exactly as with a volume.
+
+
+% Update data
+
+% set to zero
+astra_mex_data2d('store', v0, 0);
+
+% set to a matrix
+astra_mex_data2d('store', v2, A);
+
+
+
+% Retrieve data
+
+R = astra_mex_data2d('get', v2);
+imshow(R, []);
+
+
+% Retrieve data as a single array. Since astra internally stores
+% data as single precision, this is more efficient:
+
+R = astra_mex_data2d('get_single', v2);
+
+
+% Free memory
+astra_mex_data2d('delete', v0);
+astra_mex_data2d('delete', v1);
+astra_mex_data2d('delete', v2);
+astra_mex_data2d('delete', s0);
diff --git a/samples/s003_gpu_reconstruction.m b/samples/s003_gpu_reconstruction.m
new file mode 100644
index 0000000..749f91a
--- /dev/null
+++ b/samples/s003_gpu_reconstruction.m
@@ -0,0 +1,52 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+
+% As before, create a sinogram from a phantom
+P = phantom(256);
+[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom);
+figure(1); imshow(P, []);
+figure(2); imshow(sinogram, []);
+
+astra_mex_data2d('delete', sinogram_id);
+
+% We now re-create the sinogram data object as we would do when loading
+% an external sinogram
+sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram);
+
+% Create a data object for the reconstruction
+rec_id = astra_mex_data2d('create', '-vol', vol_geom);
+
+% Set up the parameters for a reconstruction algorithm using the GPU
+cfg = astra_struct('SIRT_CUDA');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = sinogram_id;
+
+% Available algorithms:
+% SIRT_CUDA, SART_CUDA, EM_CUDA, FBP_CUDA (see the FBP sample)
+
+
+% Create the algorithm object from the configuration structure
+alg_id = astra_mex_algorithm('create', cfg);
+
+% Run 150 iterations of the algorithm
+astra_mex_algorithm('iterate', alg_id, 150);
+
+% Get the result
+rec = astra_mex_data2d('get', rec_id);
+figure(3); imshow(rec, []);
+
+% Clean up. Note that GPU memory is tied up in the algorithm object,
+% and main RAM in the data objects.
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data2d('delete', rec_id);
+astra_mex_data2d('delete', sinogram_id);
diff --git a/samples/s004_cpu_reconstruction.m b/samples/s004_cpu_reconstruction.m
new file mode 100644
index 0000000..69414e2
--- /dev/null
+++ b/samples/s004_cpu_reconstruction.m
@@ -0,0 +1,60 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+
+% For CPU-based algorithms, a "projector" object specifies the projection
+% model used. In this case, we use the "strip" model.
+proj_id = astra_create_projector('strip', proj_geom, vol_geom);
+
+% Create a sinogram from a phantom
+P = phantom(256);
+[sinogram_id, sinogram] = astra_create_sino(P, proj_id);
+figure(1); imshow(P, []);
+figure(2); imshow(sinogram, []);
+
+astra_mex_data2d('delete', sinogram_id);
+
+% We now re-create the sinogram data object as we would do when loading
+% an external sinogram
+sinogram_id = astra_mex_data2d('create', '-sino', proj_geom, sinogram);
+
+% Create a data object for the reconstruction
+rec_id = astra_mex_data2d('create', '-vol', vol_geom);
+
+% Set up the parameters for a reconstruction algorithm using the CPU
+% The main difference with the configuration of a GPU algorithm is the
+% extra ProjectorId setting.
+cfg = astra_struct('SIRT');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = sinogram_id;
+cfg.ProjectorId = proj_id;
+
+% Available algorithms:
+% ART, SART, SIRT, CGLS, FBP
+
+
+% Create the algorithm object from the configuration structure
+alg_id = astra_mex_algorithm('create', cfg);
+
+% Run 20 iterations of the algorithm
+% This will have a runtime in the order of 10 seconds.
+astra_mex_algorithm('iterate', alg_id, 20);
+
+% Get the result
+rec = astra_mex_data2d('get', rec_id);
+figure(3); imshow(rec, []);
+
+% Clean up.
+astra_mex_projector('delete', proj_id);
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data2d('delete', rec_id);
+astra_mex_data2d('delete', sinogram_id);
diff --git a/samples/s005_3d_geometry.m b/samples/s005_3d_geometry.m
new file mode 100644
index 0000000..fa959c9
--- /dev/null
+++ b/samples/s005_3d_geometry.m
@@ -0,0 +1,98 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(64, 64, 64);
+
+
+% There are two main 3d projection geometry types: cone beam and parallel beam.
+% Each has a regular variant, and a 'vec' variant.
+% The 'vec' variants are completely free in the placement of source/detector,
+% while the regular variants assume circular trajectories around the z-axis.
+
+
+% -------------
+% Parallel beam
+% -------------
+
+
+% Circular
+
+% Parameters: width of detector column, height of detector row, #rows, #columns
+angles = linspace2(0, 2*pi, 48);
+proj_geom = astra_create_proj_geom('parallel3d', 1.0, 1.0, 32, 64, angles);
+
+
+% Free
+
+% We generate the same geometry as the circular one above.
+vectors = zeros(numel(angles), 12);
+for i = 1:numel(angles)
+ % ray direction
+ vectors(i,1) = sin(angles(i));
+ vectors(i,2) = -cos(angles(i));
+ vectors(i,3) = 0;
+
+ % center of detector
+ vectors(i,4:6) = 0;
+
+ % vector from detector pixel (0,0) to (0,1)
+ vectors(i,7) = cos(angles(i));
+ vectors(i,8) = sin(angles(i));
+ vectors(i,9) = 0;
+
+ % vector from detector pixel (0,0) to (1,0)
+ vectors(i,10) = 0;
+ vectors(i,11) = 0;
+ vectors(i,12) = 1;
+end
+
+% Parameters: #rows, #columns, vectors
+proj_geom = astra_create_proj_geom('parallel3d_vec', 32, 64, vectors);
+
+% ----------
+% Cone beam
+% ----------
+
+
+% Circular
+
+% Parameters: width of detector column, height of detector row, #rows, #columns,
+% angles, distance source-origin, distance origin-detector
+angles = linspace2(0, 2*pi, 48);
+proj_geom = astra_create_proj_geom('cone', 1.0, 1.0, 32, 64, ...
+ angles, 1000, 0);
+
+% Free
+
+vectors = zeros(numel(angles), 12);
+for i = 1:numel(angles)
+
+ % source
+ vectors(i,1) = sin(angles(i)) * 1000;
+ vectors(i,2) = -cos(angles(i)) * 1000;
+ vectors(i,3) = 0;
+
+ % center of detector
+ vectors(i,4:6) = 0;
+
+ % vector from detector pixel (0,0) to (0,1)
+ vectors(i,7) = cos(angles(i));
+ vectors(i,8) = sin(angles(i));
+ vectors(i,9) = 0;
+
+ % vector from detector pixel (0,0) to (1,0)
+ vectors(i,10) = 0;
+ vectors(i,11) = 0;
+ vectors(i,12) = 1;
+end
+
+% Parameters: #rows, #columns, vectors
+proj_geom = astra_create_proj_geom('cone_vec', 32, 64, vectors);
+
diff --git a/samples/s006_3d_data.m b/samples/s006_3d_data.m
new file mode 100644
index 0000000..b836198
--- /dev/null
+++ b/samples/s006_3d_data.m
@@ -0,0 +1,62 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+% Create a 3D volume geometry.
+% Parameter order: rows, colums, slices (y, x, z)
+vol_geom = astra_create_vol_geom(64, 48, 32);
+
+
+% Create volumes
+
+% initialized to zero
+v0 = astra_mex_data3d('create', '-vol', vol_geom);
+
+% initialized to 3.0
+v1 = astra_mex_data3d('create', '-vol', vol_geom, 3.0);
+
+% initialized to a matrix. A may be a single or double array.
+% Coordinate order: column, row, slice (x, y, z)
+A = zeros(48, 64, 32);
+v2 = astra_mex_data3d('create', '-vol', vol_geom, A);
+
+
+% Projection data
+
+% 2 projection directions, along x and y axis resp.
+V = [ 1 0 0 0 0 0 0 1 0 0 0 1 ; ...
+ 0 1 0 0 0 0 -1 0 0 0 0 1 ];
+% 32 rows (v), 64 columns (u)
+proj_geom = astra_create_proj_geom('parallel3d_vec', 32, 64, V);
+
+s0 = astra_mex_data3d('create', '-proj3d', proj_geom);
+
+% Initialization to a scalar or zero works exactly as with a volume.
+
+% Initialized to a matrix:
+% Coordinate order: column (u), angle, row (v)
+A = zeros(64, 2, 32);
+s1 = astra_mex_data3d('create', '-proj3d', proj_geom, A);
+
+
+% Retrieve data:
+R = astra_mex_data3d('get', v1);
+
+% Retrieve data as a single array. Since astra internally stores
+% data as single precision, this is more efficient:
+R = astra_mex_data3d('get_single', v1);
+
+
+
+% Delete all created data objects
+astra_mex_data3d('delete', v0);
+astra_mex_data3d('delete', v1);
+astra_mex_data3d('delete', v2);
+astra_mex_data3d('delete', s0);
+astra_mex_data3d('delete', s1);
diff --git a/samples/s007_3d_reconstruction.m b/samples/s007_3d_reconstruction.m
new file mode 100644
index 0000000..1bc9da3
--- /dev/null
+++ b/samples/s007_3d_reconstruction.m
@@ -0,0 +1,53 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(128, 128, 128);
+
+angles = linspace2(0, pi, 180);
+proj_geom = astra_create_proj_geom('parallel3d', 1.0, 1.0, 128, 192, angles);
+
+% Create a simple hollow cube phantom
+cube = zeros(128,128,128);
+cube(17:112,17:112,17:112) = 1;
+cube(33:96,33:96,33:96) = 0;
+
+% Create projection data from this
+[proj_id, proj_data] = astra_create_sino3d_cuda(cube, proj_geom, vol_geom);
+
+% Display a single projection image
+figure, imshow(squeeze(proj_data(:,20,:))',[])
+
+% Create a data object for the reconstruction
+rec_id = astra_mex_data3d('create', '-vol', vol_geom);
+
+% Set up the parameters for a reconstruction algorithm using the GPU
+cfg = astra_struct('SIRT3D_CUDA');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = proj_id;
+
+
+% Create the algorithm object from the configuration structure
+alg_id = astra_mex_algorithm('create', cfg);
+
+% Run 150 iterations of the algorithm
+% Note that this requires about 750MB of GPU memory, and has a runtime
+% in the order of 10 seconds.
+astra_mex_algorithm('iterate', alg_id, 150);
+
+% Get the result
+rec = astra_mex_data3d('get', rec_id);
+figure, imshow(squeeze(rec(:,:,65)),[]);
+
+
+% Clean up. Note that GPU memory is tied up in the algorithm object,
+% and main RAM in the data objects.
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data3d('delete', rec_id);
+astra_mex_data3d('delete', proj_id);
diff --git a/samples/s008_gpu_selection.m b/samples/s008_gpu_selection.m
new file mode 100644
index 0000000..252ba0c
--- /dev/null
+++ b/samples/s008_gpu_selection.m
@@ -0,0 +1,37 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+P = phantom(256);
+
+% Create a sinogram from a phantom, using GPU #1. (The default is #0)
+[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom, 1);
+
+
+% Set up the parameters for a reconstruction algorithm using the GPU
+rec_id = astra_mex_data2d('create', '-vol', vol_geom);
+cfg = astra_struct('SIRT_CUDA');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = sinogram_id;
+
+% Use GPU #1 for the reconstruction. (The default is #0.)
+cfg.option.GPUindex = 1;
+
+% Run 150 iterations of the algorithm
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id, 150);
+rec = astra_mex_data2d('get', rec_id);
+
+
+% Clean up.
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data2d('delete', rec_id);
+astra_mex_data2d('delete', sinogram_id);
diff --git a/samples/s009_projection_matrix.m b/samples/s009_projection_matrix.m
new file mode 100644
index 0000000..c0df79e
--- /dev/null
+++ b/samples/s009_projection_matrix.m
@@ -0,0 +1,45 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+
+% For CPU-based algorithms, a "projector" object specifies the projection
+% model used. In this case, we use the "strip" model.
+proj_id = astra_create_projector('strip', proj_geom, vol_geom);
+
+% Generate the projection matrix for this projection model.
+% This creates a matrix W where entry w_{i,j} corresponds to the
+% contribution of volume element j to detector element i.
+matrix_id = astra_mex_projector('matrix', proj_id);
+
+% Get the projection matrix as a Matlab sparse matrix.
+W = astra_mex_matrix('get', matrix_id);
+
+
+% Manually use this projection matrix to do a projection:
+P = phantom(256)';
+s = W * P(:);
+s = reshape(s, [proj_geom.DetectorCount size(proj_geom.ProjectionAngles, 2)])';
+figure(1), imshow(s,[]);
+
+% Because Matlab's matrices are stored transposed in memory compared to C++,
+% reshaping them to a vector doesn't give the right ordering for multiplication
+% with W. We have to take the transpose of the input and output to get the same
+% results (up to numerical noise) as using the toolbox directly.
+
+% Each row of the projection matrix corresponds to a detector element.
+% Detector t for angle p is for row 1 + t + p*proj_geom.DetectorCount.
+% Each column corresponds to a volume pixel.
+% Pixel (x,y) corresponds to column 1 + x + y*vol_geom.GridColCount.
+
+
+astra_mex_projector('delete', proj_id);
+astra_mex_matrix('delete', matrix_id);
diff --git a/samples/s010_supersampling.m b/samples/s010_supersampling.m
new file mode 100644
index 0000000..4436625
--- /dev/null
+++ b/samples/s010_supersampling.m
@@ -0,0 +1,58 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 3.0, 128, linspace2(0,pi,180));
+P = phantom(256);
+
+% Because the astra_create_sino_gpu wrapper does not have support for
+% all possible algorithm options, we manually create a sinogram
+phantom_id = astra_mex_data2d('create', '-vol', vol_geom, P);
+sinogram_id = astra_mex_data2d('create', '-sino', proj_geom);
+cfg = astra_struct('FP_CUDA');
+cfg.VolumeDataId = phantom_id;
+cfg.ProjectionDataId = sinogram_id;
+
+% Set up 3 rays per detector element
+cfg.option.DetectorSuperSampling = 3;
+
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('run', alg_id);
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data2d('delete', phantom_id);
+
+sinogram3 = astra_mex_data2d('get', sinogram_id);
+
+figure(1); imshow(P, []);
+figure(2); imshow(sinogram3, []);
+
+
+% Create a reconstruction, also using supersampling
+rec_id = astra_mex_data2d('create', '-vol', vol_geom);
+cfg = astra_struct('SIRT_CUDA');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = sinogram_id;
+% Set up 3 rays per detector element
+cfg.option.DetectorSuperSampling = 3;
+
+% There is also an option for supersampling during the backprojection step.
+% This should be used if your detector pixels are smaller than the voxels.
+
+% Set up 2 rays per image pixel dimension, for 4 rays total per image pixel.
+% cfg.option.PixelSuperSampling = 2;
+
+
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('iterate', alg_id, 150);
+astra_mex_algorithm('delete', alg_id);
+
+rec = astra_mex_data2d('get', rec_id);
+figure(3); imshow(rec, []);
+
diff --git a/samples/s011_object_info.m b/samples/s011_object_info.m
new file mode 100644
index 0000000..a3725f3
--- /dev/null
+++ b/samples/s011_object_info.m
@@ -0,0 +1,36 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+% Create two volume geometries
+vol_geom1 = astra_create_vol_geom(256, 256);
+vol_geom2 = astra_create_vol_geom(512, 256);
+
+% Create volumes
+v0 = astra_mex_data2d('create', '-vol', vol_geom1);
+v1 = astra_mex_data2d('create', '-vol', vol_geom2);
+v2 = astra_mex_data2d('create', '-vol', vol_geom2);
+
+% Show the currently allocated volumes
+astra_mex_data2d('info');
+
+
+astra_mex_data2d('delete', v2);
+astra_mex_data2d('info');
+
+astra_mex_data2d('clear');
+astra_mex_data2d('info');
+
+
+
+% The same clear and info command also work for other object types:
+astra_mex_algorithm('info');
+astra_mex_data3d('info');
+astra_mex_projector('info');
+astra_mex_matrix('info');
diff --git a/samples/s012_masks.m b/samples/s012_masks.m
new file mode 100644
index 0000000..b7b8df6
--- /dev/null
+++ b/samples/s012_masks.m
@@ -0,0 +1,60 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+
+% In this example we will create a reconstruction in a circular region,
+% instead of the usual rectangle.
+
+% This is done by placing a circular mask on the square reconstruction volume:
+
+c = -127.5:127.5;
+[x y] = meshgrid(-127.5:127.5,-127.5:127.5);
+mask = (x.^2 + y.^2 < 127.5^2);
+
+figure(1); imshow(mask, []);
+
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,50));
+
+% As before, create a sinogram from a phantom
+P = phantom(256);
+[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom);
+figure(2); imshow(P, []);
+figure(3); imshow(sinogram, []);
+
+% Create a data object for the reconstruction
+rec_id = astra_mex_data2d('create', '-vol', vol_geom);
+
+% Create a data object for the mask
+mask_id = astra_mex_data2d('create', '-vol', vol_geom, mask);
+
+% Set up the parameters for a reconstruction algorithm using the GPU
+cfg = astra_struct('SIRT_CUDA');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = sinogram_id;
+cfg.option.ReconstructionMaskId = mask_id;
+
+% Create the algorithm object from the configuration structure
+alg_id = astra_mex_algorithm('create', cfg);
+
+% Run 150 iterations of the algorithm
+astra_mex_algorithm('iterate', alg_id, 150);
+
+% Get the result
+rec = astra_mex_data2d('get', rec_id);
+figure(4); imshow(rec, []);
+
+% Clean up. Note that GPU memory is tied up in the algorithm object,
+% and main RAM in the data objects.
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data2d('delete', mask_id);
+astra_mex_data2d('delete', rec_id);
+astra_mex_data2d('delete', sinogram_id);
diff --git a/samples/s013_constraints.m b/samples/s013_constraints.m
new file mode 100644
index 0000000..9cb9612
--- /dev/null
+++ b/samples/s013_constraints.m
@@ -0,0 +1,47 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+% In this example we will create a reconstruction constrained to
+% greyvalues between 0 and 1
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,50));
+
+% As before, create a sinogram from a phantom
+P = phantom(256);
+[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom);
+figure(1); imshow(P, []);
+figure(2); imshow(sinogram, []);
+
+% Create a data object for the reconstruction
+rec_id = astra_mex_data2d('create', '-vol', vol_geom);
+
+% Set up the parameters for a reconstruction algorithm using the GPU
+cfg = astra_struct('SIRT_CUDA');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = sinogram_id;
+cfg.option.MinConstraint = 0;
+cfg.option.MaxConstraint = 1;
+
+% Create the algorithm object from the configuration structure
+alg_id = astra_mex_algorithm('create', cfg);
+
+% Run 150 iterations of the algorithm
+astra_mex_algorithm('iterate', alg_id, 150);
+
+% Get the result
+rec = astra_mex_data2d('get', rec_id);
+figure(3); imshow(rec, []);
+
+% Clean up. Note that GPU memory is tied up in the algorithm object,
+% and main RAM in the data objects.
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data2d('delete', rec_id);
+astra_mex_data2d('delete', sinogram_id);
diff --git a/samples/s014_FBP.m b/samples/s014_FBP.m
new file mode 100644
index 0000000..7cce28f
--- /dev/null
+++ b/samples/s014_FBP.m
@@ -0,0 +1,47 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+
+% As before, create a sinogram from a phantom
+P = phantom(256);
+[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom);
+figure(1); imshow(P, []);
+figure(2); imshow(sinogram, []);
+
+% Create a data object for the reconstruction
+rec_id = astra_mex_data2d('create', '-vol', vol_geom);
+
+% create configuration
+cfg = astra_struct('FBP_CUDA');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = sinogram_id;
+cfg.FilterType = 'Ram-Lak';
+
+% possible values for FilterType:
+% none, ram-lak, shepp-logan, cosine, hamming, hann, tukey, lanczos,
+% triangular, gaussian, barlett-hann, blackman, nuttall, blackman-harris,
+% blackman-nuttall, flat-top, kaiser, parzen
+
+
+% Create and run the algorithm object from the configuration structure
+alg_id = astra_mex_algorithm('create', cfg);
+astra_mex_algorithm('run', alg_id);
+
+% Get the result
+rec = astra_mex_data2d('get', rec_id);
+figure(3); imshow(rec, []);
+
+% Clean up. Note that GPU memory is tied up in the algorithm object,
+% and main RAM in the data objects.
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data2d('delete', rec_id);
+astra_mex_data2d('delete', sinogram_id);
diff --git a/samples/s015_fp_bp.m b/samples/s015_fp_bp.m
new file mode 100644
index 0000000..815f478
--- /dev/null
+++ b/samples/s015_fp_bp.m
@@ -0,0 +1,62 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+
+% This example demonstrates using the FP and BP primitives with Matlab's lsqr
+% solver. Calls to FP (astra_create_sino_cuda) and
+% BP (astra_create_backprojection_cuda) are wrapped in a function astra_wrap,
+% and a handle to this function is passed to lsqr.
+
+% Because in this case the inputs/outputs of FP and BP have to be vectors
+% instead of images (matrices), the calls require reshaping to and from vectors.
+
+function s015_fp_bp
+
+
+% FP/BP wrapper function
+function Y = astra_wrap(X,T)
+ if strcmp(T, 'notransp')
+ % X is passed as a vector. Reshape it into an image.
+ [sid, s] = astra_create_sino_cuda(reshape(X,[vol_geom.GridRowCount vol_geom.GridColCount])', proj_geom, vol_geom);
+ astra_mex_data2d('delete', sid);
+ % now s is the sinogram. Reshape it back into a vector
+ Y = reshape(s',[prod(size(s)) 1]);
+ else
+ % X is passed as a vector. Reshape it into a sinogram.
+ v = astra_create_backprojection_cuda(reshape(X, [proj_geom.DetectorCount size(proj_geom.ProjectionAngles,2)])', proj_geom, vol_geom);
+ % now v is the resulting volume. Reshape it back into a vector
+ Y = reshape(v',[prod(size(v)) 1]);
+ end
+end
+
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+
+% Create a 256x256 phantom image using matlab's built-in phantom() function
+P = phantom(256);
+
+% Create a sinogram using the GPU.
+[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom);
+
+% Reshape the sinogram into a vector
+b = reshape(sinogram',[prod(size(sinogram)) 1]);
+
+% Call Matlab's lsqr with ASTRA FP and BP
+Y = lsqr(@astra_wrap,b,1e-4,25);
+
+% Reshape the result into an image
+Y = reshape(Y,[vol_geom.GridRowCount vol_geom.GridColCount])';
+imshow(Y,[]);
+
+
+astra_mex_data2d('delete', sinogram_id);
+
+end
diff --git a/samples/s016_plots.m b/samples/s016_plots.m
new file mode 100644
index 0000000..1eeca58
--- /dev/null
+++ b/samples/s016_plots.m
@@ -0,0 +1,54 @@
+%------------------------------------------------------------------------
+% This file is part of the
+% All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+%
+% Copyright: iMinds-Vision Lab, University of Antwerp
+% License: Open Source under GPLv3
+% Contact: mailto:astra@ua.ac.be
+% Website: http://astra.ua.ac.be
+%------------------------------------------------------------------------
+
+vol_geom = astra_create_vol_geom(256, 256);
+proj_geom = astra_create_proj_geom('parallel', 1.0, 384, linspace2(0,pi,180));
+
+% As before, create a sinogram from a phantom
+P = phantom(256);
+[sinogram_id, sinogram] = astra_create_sino_gpu(P, proj_geom, vol_geom);
+figure(1); imshow(P, []);
+figure(2); imshow(sinogram, []);
+
+% Create a data object for the reconstruction
+rec_id = astra_mex_data2d('create', '-vol', vol_geom);
+
+% Set up the parameters for a reconstruction algorithm using the GPU
+cfg = astra_struct('SIRT_CUDA');
+cfg.ReconstructionDataId = rec_id;
+cfg.ProjectionDataId = sinogram_id;
+
+% Create the algorithm object from the configuration structure
+alg_id = astra_mex_algorithm('create', cfg);
+
+% Run 1500 iterations of the algorithm one at a time, keeping track of errors
+nIters = 1500;
+phantom_error = zeros(1, nIters);
+residual_error = zeros(1, nIters);
+for i = 1:nIters;
+ % Run a single iteration
+ astra_mex_algorithm('iterate', alg_id, 1);
+
+ residual_error(i) = astra_mex_algorithm('get_res_norm', alg_id);
+ rec = astra_mex_data2d('get', rec_id);
+ phantom_error(i) = sqrt(sumsqr(rec - P));
+end
+
+% Get the result
+rec = astra_mex_data2d('get', rec_id);
+figure(3); imshow(rec, []);
+
+figure(4); plot(residual_error)
+figure(5); plot(phantom_error)
+
+% Clean up.
+astra_mex_algorithm('delete', alg_id);
+astra_mex_data2d('delete', rec_id);
+astra_mex_data2d('delete', sinogram_id);
diff --git a/src/Algorithm.cpp b/src/Algorithm.cpp
new file mode 100644
index 0000000..38ae65d
--- /dev/null
+++ b/src/Algorithm.cpp
@@ -0,0 +1,64 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Algorithm.h"
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CAlgorithm::CAlgorithm() : m_bShouldAbort(false), configCheckData(0) {
+
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CAlgorithm::~CAlgorithm() {
+
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CAlgorithm::getInformation()
+{
+ map<string, boost::any> result;
+ result["Initialized"] = getInformation("Initialized");
+ return result;
+};
+
+//----------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CAlgorithm::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "Initialized") { return m_bIsInitialized ? "yes" : "no"; }
+ return std::string("not found");
+}
+
+} // namespace astra
diff --git a/src/ArtAlgorithm.cpp b/src/ArtAlgorithm.cpp
new file mode 100644
index 0000000..77ab5ab
--- /dev/null
+++ b/src/ArtAlgorithm.cpp
@@ -0,0 +1,331 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ArtAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CArtAlgorithm::type = "ART";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CArtAlgorithm::CArtAlgorithm()
+ : CReconstructionAlgorithm2D()
+{
+ m_fLambda = 1.0f;
+ m_iRayCount = 0;
+ m_iCurrentRay = 0;
+ m_piProjectionOrder = NULL;
+ m_piDetectorOrder = NULL;
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CArtAlgorithm::~CArtAlgorithm()
+{
+ if (m_piProjectionOrder != NULL)
+ delete[] m_piProjectionOrder;
+ if (m_piDetectorOrder != NULL)
+ delete[] m_piDetectorOrder;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CArtAlgorithm::_clear()
+{
+ CReconstructionAlgorithm2D::_clear();
+ m_piDetectorOrder = NULL;
+ m_piProjectionOrder = NULL;
+ m_iRayCount = 0;
+ m_iCurrentRay = 0;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CArtAlgorithm::clear()
+{
+ CReconstructionAlgorithm2D::clear();
+ if (m_piDetectorOrder) {
+ delete[] m_piDetectorOrder;
+ m_piDetectorOrder = NULL;
+ }
+ if (m_piProjectionOrder) {
+ delete[] m_piProjectionOrder;
+ m_piProjectionOrder = NULL;
+ }
+ m_fLambda = 1.0f;
+ m_iRayCount = 0;
+ m_iCurrentRay = 0;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CArtAlgorithm::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "ART", "Error in ReconstructionAlgorithm2D initialization");
+
+ // check ray order list
+ for (int i = 0; i < m_iRayCount; i++) {
+ if (m_piProjectionOrder[i] < 0 || m_piProjectionOrder[i] > m_pSinogram->getAngleCount()-1) {
+ ASTRA_CONFIG_CHECK(false, "ART", "Invalid value in ray order list.");
+ }
+ if (m_piDetectorOrder[i] < 0 || m_piDetectorOrder[i] > m_pSinogram->getDetectorCount()-1) {
+ ASTRA_CONFIG_CHECK(false, "ART", "Invalid value in ray order list.");
+ }
+ }
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CArtAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("ArtAlgorithm", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // ray order
+ string projOrder = _cfg.self->getOption("RayOrder", "sequential");
+ CC.markOptionParsed("RayOrder");
+ m_iCurrentRay = 0;
+ m_iRayCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount() *
+ m_pProjector->getProjectionGeometry()->getDetectorCount();
+ if (projOrder == "sequential") {
+ m_piProjectionOrder = new int[m_iRayCount];
+ m_piDetectorOrder = new int[m_iRayCount];
+ for (int i = 0; i < m_iRayCount; i++) {
+ m_piProjectionOrder[i] = (int)floor((float)i / m_pProjector->getProjectionGeometry()->getDetectorCount());
+ m_piDetectorOrder[i] = i % m_pProjector->getProjectionGeometry()->getDetectorCount();
+ }
+ } else if (projOrder == "custom") {
+ vector<float32> rayOrderList = _cfg.self->getOptionNumericalArray("RayOrderList");
+ m_iRayCount = rayOrderList.size() / 2;
+ m_piProjectionOrder = new int[m_iRayCount];
+ m_piDetectorOrder = new int[m_iRayCount];
+ for (int i = 0; i < m_iRayCount; i++) {
+ m_piProjectionOrder[i] = static_cast<int>(rayOrderList[2*i]);
+ m_piDetectorOrder[i] = static_cast<int>(rayOrderList[2*i+1]);
+ }
+ CC.markOptionParsed("RayOrderList");
+ } else {
+ return false;
+ }
+
+ m_fLambda = _cfg.self->getOptionNumerical("Lambda", 1.0f);
+ CC.markOptionParsed("Lambda");
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CArtAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // ray order
+ m_iCurrentRay = 0;
+ m_iRayCount = _pProjector->getProjectionGeometry()->getDetectorCount() *
+ _pProjector->getProjectionGeometry()->getProjectionAngleCount();
+ m_piProjectionOrder = new int[m_iRayCount];
+ m_piDetectorOrder = new int[m_iRayCount];
+ for (int i = 0; i < m_iRayCount; i++) {
+ m_piProjectionOrder[i] = (int)floor((float)i / _pProjector->getProjectionGeometry()->getDetectorCount());
+ m_piDetectorOrder[i] = i % _pProjector->getProjectionGeometry()->getDetectorCount();
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Set the relaxation factor.
+void CArtAlgorithm::setLambda(float32 _fLambda)
+{
+ m_fLambda = _fLambda;
+}
+
+//----------------------------------------------------------------------------------------
+// Set the order in which the rays will be selected
+void CArtAlgorithm::setRayOrder(int* _piProjectionOrder, int* _piDetectorOrder, int _iRayCount)
+{
+ if (m_piDetectorOrder) {
+ delete[] m_piDetectorOrder;
+ m_piDetectorOrder = NULL;
+ }
+ if (m_piProjectionOrder) {
+ delete[] m_piProjectionOrder;
+ m_piProjectionOrder = NULL;
+ }
+
+ m_iCurrentRay = 0;
+ m_iRayCount = _iRayCount;
+ m_piProjectionOrder = new int[m_iRayCount];
+ m_piDetectorOrder = new int[m_iRayCount];
+ for (int i = 0; i < m_iRayCount; i++) {
+ m_piProjectionOrder[i] = _piProjectionOrder[i];
+ m_piDetectorOrder[i] = _piDetectorOrder[i];
+ }
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CArtAlgorithm::getInformation()
+{
+ map<string, boost::any> res;
+ res["RayOrder"] = getInformation("RayOrder");
+ res["Lambda"] = getInformation("Lambda");
+ return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CArtAlgorithm::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "Lambda") { return m_fLambda; }
+ if (_sIdentifier == "RayOrder") {
+ vector<float32> res;
+ for (int i = 0; i < m_iRayCount; i++) {
+ res.push_back(m_piProjectionOrder[i]);
+ }
+ for (int i = 0; i < m_iRayCount; i++) {
+ res.push_back(m_piDetectorOrder[i]);
+ }
+ return res;
+ }
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CArtAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ assert(m_bIsInitialized);
+
+ // variables
+ int iIteration, iPixel;
+ int iUsedPixels, iProjection, iDetector;
+ float32 fRayForwardProj, fSumSquaredWeights;
+ float32 fProjectionDifference, fBackProjectionFactor;
+
+ // create a pixel buffer
+ int iPixelBufferSize = m_pProjector->getProjectionWeightsCount(0);
+ SPixelWeight* pPixels = new SPixelWeight[iPixelBufferSize];
+
+ // start iterations
+ for (iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) {
+
+ // step0: compute single weight rays
+ iProjection = m_piProjectionOrder[m_iCurrentRay];
+ iDetector = m_piDetectorOrder[m_iCurrentRay];
+ m_iCurrentRay = (m_iCurrentRay + 1) % m_iRayCount;
+
+ if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue;
+
+ m_pProjector->computeSingleRayWeights(iProjection, iDetector, pPixels, iPixelBufferSize, iUsedPixels);
+
+ // step1: forward projections
+ fRayForwardProj = 0.0f;
+ fSumSquaredWeights = 0.0f;
+ for (iPixel = iUsedPixels-1; iPixel >= 0; --iPixel) {
+ if (m_bUseReconstructionMask && m_pReconstructionMask->getDataConst()[pPixels[iPixel].m_iIndex] == 0) continue;
+
+ fRayForwardProj += pPixels[iPixel].m_fWeight * m_pReconstruction->getDataConst()[pPixels[iPixel].m_iIndex];
+ fSumSquaredWeights += pPixels[iPixel].m_fWeight * pPixels[iPixel].m_fWeight;
+ }
+ if (fSumSquaredWeights == 0) continue;
+
+ // step2: difference
+ fProjectionDifference = m_pSinogram->getData2D()[iProjection][iDetector] - fRayForwardProj;
+
+ // step3: back projection
+ fBackProjectionFactor = m_fLambda * fProjectionDifference / fSumSquaredWeights;
+ for (iPixel = iUsedPixels-1; iPixel >= 0; --iPixel) {
+
+ // pixel must be loose
+ if (m_bUseReconstructionMask && m_pReconstructionMask->getDataConst()[pPixels[iPixel].m_iIndex] == 0) continue;
+
+ // update
+ m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] += fBackProjectionFactor * pPixels[iPixel].m_fWeight;
+
+ // constraints
+ if (m_bUseMinConstraint && m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] < m_fMinValue) {
+ m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] = m_fMinValue;
+ }
+ if (m_bUseMaxConstraint && m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] > m_fMaxValue) {
+ m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] = m_fMaxValue;
+ }
+ }
+
+ }
+ delete[] pPixels;
+
+ // update statistics
+ m_pReconstruction->updateStatistics();
+}
+
+
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/AstraObjectFactory.cpp b/src/AstraObjectFactory.cpp
new file mode 100644
index 0000000..195c431
--- /dev/null
+++ b/src/AstraObjectFactory.cpp
@@ -0,0 +1,39 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/AstraObjectFactory.h"
+
+using namespace std;
+
+namespace astra {
+
+DEFINE_SINGLETON2(CAstraObjectFactory<CAlgorithm, AlgorithmTypeList>);
+DEFINE_SINGLETON2(CAstraObjectFactory<CProjector2D, Projector2DTypeList>);
+DEFINE_SINGLETON2(CAstraObjectFactory<CProjector3D, Projector3DTypeList>);
+
+} // end namespace
diff --git a/src/AstraObjectManager.cpp b/src/AstraObjectManager.cpp
new file mode 100644
index 0000000..597119d
--- /dev/null
+++ b/src/AstraObjectManager.cpp
@@ -0,0 +1,43 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/AstraObjectManager.h"
+
+
+namespace astra {
+
+int CAstraIndexManager::m_iPreviousIndex = 0;
+
+DEFINE_SINGLETON(CAstraObjectManager<CProjector2D>);
+DEFINE_SINGLETON(CAstraObjectManager<CProjector3D>);
+DEFINE_SINGLETON(CAstraObjectManager<CFloat32Data2D>);
+DEFINE_SINGLETON(CAstraObjectManager<CFloat32Data3D>);
+DEFINE_SINGLETON(CAstraObjectManager<CAlgorithm>);
+DEFINE_SINGLETON(CAstraObjectManager<CSparseMatrix>);
+
+} // end namespace
diff --git a/src/AsyncAlgorithm.cpp b/src/AsyncAlgorithm.cpp
new file mode 100644
index 0000000..431dbbc
--- /dev/null
+++ b/src/AsyncAlgorithm.cpp
@@ -0,0 +1,195 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/AsyncAlgorithm.h"
+#include "astra/AstraObjectFactory.h"
+
+#ifndef USE_PTHREAD
+#include <boost/bind.hpp>
+#endif
+
+namespace astra {
+
+CAsyncAlgorithm::CAsyncAlgorithm()
+{
+ m_bInitialized = false;
+#ifndef USE_PTHREADS
+ m_pThread = 0;
+#endif
+ m_bThreadStarted = false;
+}
+
+CAsyncAlgorithm::CAsyncAlgorithm(CAlgorithm* _pAlg)
+{
+ m_pAlg = _pAlg;
+ m_bInitialized = (m_pAlg != 0);
+#ifndef USE_PTHREADS
+ m_pThread = 0;
+#endif
+ m_bThreadStarted = false;
+ m_bDone = false;
+ m_bAutoFree = false;
+}
+
+bool CAsyncAlgorithm::initialize(const Config& _cfg)
+{
+ if (m_bInitialized && m_bThreadStarted) {
+#ifndef USE_PTHREADS
+ m_pThread->join();
+ delete m_pThread;
+#else
+ pthread_join(m_thread, 0);
+#endif
+ }
+#ifndef USE_PTHREADS
+ m_pThread = 0;
+#endif
+ m_bThreadStarted = false;
+ m_pAlg = 0;
+ m_bDone = false;
+
+ m_pAlg = CAlgorithmFactory::getSingleton().create(_cfg);
+ if (m_pAlg && !m_pAlg->isInitialized()) {
+ if (m_bAutoFree)
+ delete m_pAlg;
+ m_pAlg = 0;
+ }
+ m_bInitialized = (m_pAlg != 0);
+ m_bAutoFree = true;
+ return m_bInitialized;
+}
+
+bool CAsyncAlgorithm::initialize(CAlgorithm* _pAlg)
+{
+ if (m_bInitialized && m_bThreadStarted) {
+#ifndef USE_PTHREADS
+ m_pThread->join();
+ delete m_pThread;
+#else
+ pthread_join(m_thread, 0);
+#endif
+ }
+#ifndef USE_PTHREADS
+ m_pThread = 0;
+#endif
+ m_bThreadStarted = false;
+ m_bDone = false;
+
+ m_pAlg = _pAlg;
+ m_bInitialized = (m_pAlg != 0);
+ m_bAutoFree = false;
+ return m_bInitialized;
+}
+
+CAsyncAlgorithm::~CAsyncAlgorithm()
+{
+ if (m_bInitialized && m_bThreadStarted) {
+#ifndef USE_PTHREADS
+ m_pThread->join();
+ delete m_pThread;
+#else
+ pthread_join(m_thread, 0);
+#endif
+ }
+#ifndef USE_PTHREADS
+ m_pThread = 0;
+#endif
+ m_bThreadStarted = false;
+
+ if (m_bInitialized && m_bAutoFree) {
+ delete m_pAlg;
+ m_pAlg = 0;
+ }
+}
+
+#ifdef USE_PTHREADS
+void* runAsync_pthreads(void* data)
+{
+ CAsyncAlgorithm::AsyncThreadInfo *info = (CAsyncAlgorithm::AsyncThreadInfo*)data;
+ info->m_pAlg->run(info->m_iIterations);
+ *info->m_pDone = true;
+ return 0;
+}
+#endif
+
+void CAsyncAlgorithm::run(int _iNrIterations)
+{
+ if (!m_bInitialized)
+ return;
+
+#ifndef USE_PTHREADS
+ m_pThread = new boost::thread(
+ boost::bind(&CAsyncAlgorithm::runWrapped,
+ this, _iNrIterations));
+#else
+ m_ThreadInfo.m_iIterations = _iNrIterations;
+ m_ThreadInfo.m_pAlg = m_pAlg;
+ m_ThreadInfo.m_pDone = &this->m_bDone;
+ pthread_create(&m_thread, 0, runAsync_pthreads, &this->m_ThreadInfo);
+#endif
+}
+
+void CAsyncAlgorithm::runWrapped(int _iNrIterations)
+{
+ m_pAlg->run(_iNrIterations);
+ m_bDone = true;
+}
+
+void CAsyncAlgorithm::timedJoin(int _milliseconds)
+{
+#ifndef USE_PTHREADS
+ if (m_pThread) {
+ boost::posix_time::milliseconds rel(_milliseconds);
+ bool res = m_pThread->timed_join(rel);
+ if (res) {
+ delete m_pThread;
+ m_pThread = 0;
+ m_bThreadStarted = false;
+ }
+ }
+#else
+ if (m_bThreadStarted) {
+ struct timespec abstime;
+ clock_gettime(CLOCK_REALTIME, &abstime);
+ abstime.tv_sec += _milliseconds / 1000;
+ abstime.tv_nsec += (_milliseconds % 1000) * 1000000L;
+ int err = pthread_timedjoin_np(m_thread, 0, &abstime);
+ if (err == 0) {
+ m_bThreadStarted = false;
+ }
+ }
+#endif
+}
+
+void CAsyncAlgorithm::signalAbort()
+{
+ if (m_pAlg)
+ m_pAlg->signalAbort();
+}
+
+}
diff --git a/src/BackProjectionAlgorithm.cpp b/src/BackProjectionAlgorithm.cpp
new file mode 100644
index 0000000..cf8c9ca
--- /dev/null
+++ b/src/BackProjectionAlgorithm.cpp
@@ -0,0 +1,192 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/BackProjectionAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+
+namespace astra {
+
+#include "astra/Projector2DImpl.inl"
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CBackProjectionAlgorithm::type = "BP";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CBackProjectionAlgorithm::CBackProjectionAlgorithm()
+{
+ _clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+CBackProjectionAlgorithm::CBackProjectionAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ _clear();
+ initialize(_pProjector, _pSinogram, _pReconstruction);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CBackProjectionAlgorithm::~CBackProjectionAlgorithm()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CBackProjectionAlgorithm::_clear()
+{
+ CReconstructionAlgorithm2D::_clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CBackProjectionAlgorithm::clear()
+{
+ CReconstructionAlgorithm2D::_clear();
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CBackProjectionAlgorithm::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "BP", "Error in ReconstructionAlgorithm2D initialization");
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CBackProjectionAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("BackProjectionAlgorithm", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // init data objects and data projectors
+ _init();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CBackProjectionAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // init data objects and data projectors
+ _init();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize Data Projectors - private
+void CBackProjectionAlgorithm::_init()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CBackProjectionAlgorithm::getInformation()
+{
+ map<string, boost::any> res;
+ return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CBackProjectionAlgorithm::getInformation(std::string _sIdentifier)
+{
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CBackProjectionAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ m_bShouldAbort = false;
+
+ CDataProjectorInterface* pBackProjector;
+
+ pBackProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ DefaultBPPolicy(m_pReconstruction, m_pSinogram), // backprojection
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
+ m_pReconstruction->setData(0.0f);
+ pBackProjector->project();
+
+ ASTRA_DELETE(pBackProjector);
+}
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/CglsAlgorithm.cpp b/src/CglsAlgorithm.cpp
new file mode 100644
index 0000000..f3e1be1
--- /dev/null
+++ b/src/CglsAlgorithm.cpp
@@ -0,0 +1,297 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/CglsAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+using namespace std;
+
+namespace astra {
+
+#include "astra/Projector2DImpl.inl"
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCglsAlgorithm::type = "CGLS";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCglsAlgorithm::CCglsAlgorithm()
+{
+ _clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+CCglsAlgorithm::CCglsAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ _clear();
+ initialize(_pProjector, _pSinogram, _pReconstruction);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCglsAlgorithm::~CCglsAlgorithm()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CCglsAlgorithm::_clear()
+{
+ CReconstructionAlgorithm2D::_clear();
+ r = NULL;
+ w = NULL;
+ z = NULL;
+ p = NULL;
+ alpha = 0.0f;
+ beta = 0.0f;
+ gamma = 0.0f;
+ m_iIteration = 0;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CCglsAlgorithm::clear()
+{
+ CReconstructionAlgorithm2D::_clear();
+ ASTRA_DELETE(r);
+ ASTRA_DELETE(w);
+ ASTRA_DELETE(z);
+ ASTRA_DELETE(p);
+ alpha = 0.0f;
+ beta = 0.0f;
+ gamma = 0.0f;
+ m_iIteration = 0;
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCglsAlgorithm::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "CGLS", "Error in ReconstructionAlgorithm2D initialization");
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCglsAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CglsAlgorithm", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // member variables
+ r = new CFloat32ProjectionData2D(m_pSinogram->getGeometry());
+ w = new CFloat32ProjectionData2D(m_pSinogram->getGeometry());
+ z = new CFloat32VolumeData2D(m_pReconstruction->getGeometry());
+ p = new CFloat32VolumeData2D(m_pReconstruction->getGeometry());
+
+ alpha = 0.0f;
+ beta = 0.0f;
+ gamma = 0.0f;
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCglsAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // member variables
+ r = new CFloat32ProjectionData2D(m_pSinogram->getGeometry());
+ w = new CFloat32ProjectionData2D(m_pSinogram->getGeometry());
+ z = new CFloat32VolumeData2D(m_pReconstruction->getGeometry());
+ p = new CFloat32VolumeData2D(m_pReconstruction->getGeometry());
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCglsAlgorithm::getInformation()
+{
+ map<string, boost::any> res;
+ return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCglsAlgorithm::getInformation(std::string _sIdentifier)
+{
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCglsAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ // data projectors
+ CDataProjectorInterface* pForwardProjector;
+ CDataProjectorInterface* pBackProjector;
+
+ // forward projection data projector
+ pForwardProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ DefaultFPPolicy(p, w), // forward projection
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
+ // backprojection data projector
+ pBackProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ DefaultBPPolicy(z, r), // backprojection
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
+
+
+ int i;
+
+ if (m_iIteration == 0) {
+ // r = b;
+ r->copyData(m_pSinogram->getData());
+
+ // z = A'*b;
+ z->setData(0.0f);
+ pBackProjector->project();
+ if (m_bUseMinConstraint)
+ z->clampMin(m_fMinValue);
+ if (m_bUseMaxConstraint)
+ z->clampMax(m_fMaxValue);
+
+ // p = z;
+ p->copyData(z->getData());
+
+ // gamma = dot(z,z);
+ gamma = 0.0f;
+ for (i = 0; i < z->getSize(); ++i) {
+ gamma += z->getData()[i] * z->getData()[i];
+ }
+ m_iIteration++;
+ }
+
+
+ // start iterations
+ for (int iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) {
+
+ // w = A*p;
+ pForwardProjector->project();
+
+ // alpha = gamma/dot(w,w);
+ float32 tmp = 0;
+ for (i = 0; i < w->getSize(); ++i) {
+ tmp += w->getData()[i] * w->getData()[i];
+ }
+ alpha = gamma / tmp;
+
+ // x = x + alpha*p;
+ for (i = 0; i < m_pReconstruction->getSize(); ++i) {
+ m_pReconstruction->getData()[i] += alpha * p->getData()[i];
+ }
+
+ // r = r - alpha*w;
+ for (i = 0; i < r->getSize(); ++i) {
+ r->getData()[i] -= alpha * w->getData()[i];
+ }
+
+ // z = A'*r;
+ z->setData(0.0f);
+ pBackProjector->project();
+
+ // CHECKME: should these be here?
+ if (m_bUseMinConstraint)
+ z->clampMin(m_fMinValue);
+ if (m_bUseMaxConstraint)
+ z->clampMax(m_fMaxValue);
+
+ // beta = 1/gamma;
+ beta = 1.0f / gamma;
+
+ // gamma = dot(z,z);
+ gamma = 0;
+ for (i = 0; i < z->getSize(); ++i) {
+ gamma += z->getData()[i] * z->getData()[i];
+ }
+
+ // beta = gamma*beta;
+ beta *= gamma;
+
+ // p = z + beta*p;
+ for (i = 0; i < z->getSize(); ++i) {
+ p->getData()[i] = z->getData()[i] + beta * p->getData()[i];
+ }
+
+ m_iIteration++;
+ }
+
+}
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/ConeProjectionGeometry3D.cpp b/src/ConeProjectionGeometry3D.cpp
new file mode 100644
index 0000000..129e675
--- /dev/null
+++ b/src/ConeProjectionGeometry3D.cpp
@@ -0,0 +1,228 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ConeProjectionGeometry3D.h"
+
+#include <boost/lexical_cast.hpp>
+#include <cstring>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CConeProjectionGeometry3D::CConeProjectionGeometry3D() :
+ CProjectionGeometry3D()
+{
+ m_fOriginSourceDistance = 0.0f;
+ m_fOriginDetectorDistance = 0.0f;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CConeProjectionGeometry3D::CConeProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorWidth,
+ float32 _fDetectorHeight,
+ const float32* _pfProjectionAngles,
+ float32 _fOriginSourceDistance,
+ float32 _fOriginDetectorDistance) :
+ CProjectionGeometry3D()
+{
+ initialize(_iProjectionAngleCount,
+ _iDetectorRowCount,
+ _iDetectorColCount,
+ _fDetectorWidth,
+ _fDetectorHeight,
+ _pfProjectionAngles,
+ _fOriginSourceDistance,
+ _fOriginDetectorDistance);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CConeProjectionGeometry3D::~CConeProjectionGeometry3D()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CConeProjectionGeometry3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry3D> CC("ConeProjectionGeometry3D", this, _cfg);
+
+ // initialization of parent class
+ CProjectionGeometry3D::initialize(_cfg);
+
+ // Required: DistanceOriginDetector
+ XMLNode* node = _cfg.self->getSingleNode("DistanceOriginDetector");
+ ASTRA_CONFIG_CHECK(node, "ConeProjectionGeometry3D", "No DistanceOriginDetector tag specified.");
+ m_fOriginDetectorDistance = boost::lexical_cast<float32>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DistanceOriginDetector");
+
+ // Required: DetectorOriginSource
+ node = _cfg.self->getSingleNode("DistanceOriginSource");
+ ASTRA_CONFIG_CHECK(node, "ConeProjectionGeometry3D", "No DistanceOriginSource tag specified.");
+ m_fOriginSourceDistance = boost::lexical_cast<float32>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DistanceOriginSource");
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CConeProjectionGeometry3D::initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorWidth,
+ float32 _fDetectorHeight,
+ const float32* _pfProjectionAngles,
+ float32 _fOriginSourceDistance,
+ float32 _fOriginDetectorDistance)
+{
+ _initialize(_iProjectionAngleCount,
+ _iDetectorRowCount,
+ _iDetectorColCount,
+ _fDetectorWidth,
+ _fDetectorHeight,
+ _pfProjectionAngles);
+
+ m_fOriginSourceDistance = _fOriginSourceDistance;
+ m_fOriginDetectorDistance = _fOriginDetectorDistance;
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CProjectionGeometry3D* CConeProjectionGeometry3D::clone() const
+{
+ CConeProjectionGeometry3D* res = new CConeProjectionGeometry3D();
+ res->m_bInitialized = m_bInitialized;
+ res->m_iProjectionAngleCount = m_iProjectionAngleCount;
+ res->m_iDetectorRowCount = m_iDetectorRowCount;
+ res->m_iDetectorColCount = m_iDetectorColCount;
+ res->m_iDetectorTotCount = m_iDetectorTotCount;
+ res->m_fDetectorSpacingX = m_fDetectorSpacingX;
+ res->m_fDetectorSpacingY = m_fDetectorSpacingY;
+ res->m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ memcpy(res->m_pfProjectionAngles, m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount);
+ res->m_fOriginSourceDistance = m_fOriginSourceDistance;
+ res->m_fOriginDetectorDistance = m_fOriginDetectorDistance;
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// is equal
+bool CConeProjectionGeometry3D::isEqual(const CProjectionGeometry3D* _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // try to cast argument to CParallelProjectionGeometry3D
+ const CConeProjectionGeometry3D* pGeom2 = dynamic_cast<const CConeProjectionGeometry3D*>(_pGeom2);
+ if (pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false;
+ if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false;
+ if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false;
+ if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false;
+ if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false;
+ if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false;
+ if (m_fOriginSourceDistance != pGeom2->m_fOriginSourceDistance) return false;
+ if (m_fOriginDetectorDistance != pGeom2->m_fOriginDetectorDistance) return false;
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// is of type
+bool CConeProjectionGeometry3D::isOfType(const std::string& _sType) const
+{
+ return (_sType == "cone");
+}
+
+//----------------------------------------------------------------------------------------
+void CConeProjectionGeometry3D::toXML(XMLNode* _sNode) const
+{
+ _sNode->addAttribute("type", "cone");
+ _sNode->addChildNode("DetectorSpacingX", m_fDetectorSpacingX);
+ _sNode->addChildNode("DetectorSpacingY", m_fDetectorSpacingY);
+ _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount);
+ _sNode->addChildNode("DetectorColCount", m_iDetectorColCount);
+ _sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount);
+ _sNode->addChildNode("DistanceOriginDetector", m_fOriginDetectorDistance);
+ _sNode->addChildNode("DistanceOriginSource", m_fOriginSourceDistance);
+}
+//----------------------------------------------------------------------------------------
+
+CVector3D CConeProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const
+{
+ float32 fSrcX = -m_fOriginSourceDistance;
+ float32 fSrcY = 0.0f;
+ float32 fSrcZ = 0.0f;
+
+ float32 fDetX = m_fOriginDetectorDistance;
+ float32 fDetY = 0.0f;
+ float32 fDetZ = 0.0f;
+
+ fDetY += indexToDetectorOffsetX(_iDetectorIndex);
+ fDetZ += indexToDetectorOffsetY(_iDetectorIndex);
+
+ float32 angle = m_pfProjectionAngles[_iProjectionIndex];
+
+ #define ROTATE(name,alpha) do { float32 tX = f##name##X * cos(alpha) - f##name##Y * sin(alpha); f##name##Y = f##name##X * sin(alpha) + f##name##Y * cos(alpha); f##name##X = tX; } while(0)
+
+ ROTATE(Src, angle);
+ ROTATE(Det, angle);
+
+ #undef ROTATE
+
+ CVector3D ret(fDetX - fSrcX, fDetY - fSrcY, fDetZ - fDetZ);
+ return ret;
+}
+
+} // end namespace astra
diff --git a/src/ConeVecProjectionGeometry3D.cpp b/src/ConeVecProjectionGeometry3D.cpp
new file mode 100644
index 0000000..875a2c7
--- /dev/null
+++ b/src/ConeVecProjectionGeometry3D.cpp
@@ -0,0 +1,232 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ConeVecProjectionGeometry3D.h"
+
+#include <cstring>
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CConeVecProjectionGeometry3D::CConeVecProjectionGeometry3D() :
+ CProjectionGeometry3D()
+{
+ m_pProjectionAngles = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CConeVecProjectionGeometry3D::CConeVecProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ const SConeProjection* _pProjectionAngles
+ ) :
+ CProjectionGeometry3D()
+{
+ initialize(_iProjectionAngleCount,
+ _iDetectorRowCount,
+ _iDetectorColCount,
+ _pProjectionAngles);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CConeVecProjectionGeometry3D::~CConeVecProjectionGeometry3D()
+{
+ delete[] m_pProjectionAngles;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CConeVecProjectionGeometry3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry3D> CC("ConeVecProjectionGeometry3D", this, _cfg);
+
+ XMLNode* node;
+
+ // TODO: Fix up class hierarchy... this class doesn't fit very well.
+ // initialization of parent class
+ //CProjectionGeometry3D::initialize(_cfg);
+
+ // Required: DetectorRowCount
+ node = _cfg.self->getSingleNode("DetectorRowCount");
+ ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No DetectorRowCount tag specified.");
+ m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorRowCount");
+
+ // Required: DetectorColCount
+ node = _cfg.self->getSingleNode("DetectorColCount");
+ ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No DetectorColCount tag specified.");
+ m_iDetectorColCount = boost::lexical_cast<int>(node->getContent());
+ m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount;
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorColCount");
+
+ // Required: Vectors
+ node = _cfg.self->getSingleNode("Vectors");
+ ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No Vectors tag specified.");
+ vector<double> data = node->getContentNumericalArrayDouble();
+ CC.markNodeParsed("Vectors");
+ ASTRA_DELETE(node);
+ ASTRA_CONFIG_CHECK(data.size() % 12 == 0, "ConeVecProjectionGeometry3D", "Vectors doesn't consist of 12-tuples.");
+ m_iProjectionAngleCount = data.size() / 12;
+ m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount];
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ SConeProjection& p = m_pProjectionAngles[i];
+ p.fSrcX = data[12*i + 0];
+ p.fSrcY = data[12*i + 1];
+ p.fSrcZ = data[12*i + 2];
+ p.fDetUX = data[12*i + 6];
+ p.fDetUY = data[12*i + 7];
+ p.fDetUZ = data[12*i + 8];
+ p.fDetVX = data[12*i + 9];
+ p.fDetVY = data[12*i + 10];
+ p.fDetVZ = data[12*i + 11];
+
+ // The backend code currently expects the corner of the detector, while
+ // the matlab interface supplies the center
+ p.fDetSX = data[12*i + 3] - 0.5f * m_iDetectorRowCount * p.fDetVX - 0.5f * m_iDetectorColCount * p.fDetUX;
+ p.fDetSY = data[12*i + 4] - 0.5f * m_iDetectorRowCount * p.fDetVY - 0.5f * m_iDetectorColCount * p.fDetUY;
+ p.fDetSZ = data[12*i + 5] - 0.5f * m_iDetectorRowCount * p.fDetVZ - 0.5f * m_iDetectorColCount * p.fDetUZ;
+ }
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CConeVecProjectionGeometry3D::initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ const SConeProjection* _pProjectionAngles)
+{
+ m_iProjectionAngleCount = _iProjectionAngleCount;
+ m_iDetectorRowCount = _iDetectorRowCount;
+ m_iDetectorColCount = _iDetectorColCount;
+ m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount];
+ for (int i = 0; i < m_iProjectionAngleCount; ++i)
+ m_pProjectionAngles[i] = _pProjectionAngles[i];
+
+ // TODO: check?
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CProjectionGeometry3D* CConeVecProjectionGeometry3D::clone() const
+{
+ CConeVecProjectionGeometry3D* res = new CConeVecProjectionGeometry3D();
+ res->m_bInitialized = m_bInitialized;
+ res->m_iProjectionAngleCount = m_iProjectionAngleCount;
+ res->m_iDetectorRowCount = m_iDetectorRowCount;
+ res->m_iDetectorColCount = m_iDetectorColCount;
+ res->m_iDetectorTotCount = m_iDetectorTotCount;
+ res->m_fDetectorSpacingX = m_fDetectorSpacingX;
+ res->m_fDetectorSpacingY = m_fDetectorSpacingY;
+ res->m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount];
+ memcpy(res->m_pProjectionAngles, m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount);
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// is equal
+bool CConeVecProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // try to cast argument to CConeProjectionGeometry3D
+ const CConeVecProjectionGeometry3D* pGeom2 = dynamic_cast<const CConeVecProjectionGeometry3D*>(_pGeom2);
+ if (pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false;
+ if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false;
+ if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false;
+ if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false;
+ //if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false;
+ //if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false;
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// is of type
+bool CConeVecProjectionGeometry3D::isOfType(const std::string& _sType) const
+{
+ return (_sType == "cone3d_vec");
+}
+
+//----------------------------------------------------------------------------------------
+void CConeVecProjectionGeometry3D::toXML(XMLNode* _sNode) const
+{
+ _sNode->addAttribute("type","cone3d_vec");
+ _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount);
+ _sNode->addChildNode("DetectorColCount", m_iDetectorColCount);
+ // TODO:
+ //_sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount);
+}
+
+CVector3D CConeVecProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const
+{
+ const SConeProjection& p = m_pProjectionAngles[_iProjectionIndex];
+ int u = _iDetectorIndex % m_iDetectorColCount;
+ int v = _iDetectorIndex / m_iDetectorColCount;
+
+ return CVector3D(p.fDetSX + (u+0.5)*p.fDetUX + (v+0.5)*p.fDetVX - p.fSrcX, p.fDetSY + (u+0.5)*p.fDetUY + (v+0.5)*p.fDetVY - p.fSrcY, p.fDetSZ + (u+0.5)*p.fDetUZ + (v+0.5)*p.fDetVZ - p.fSrcZ);
+}
+
+
+//----------------------------------------------------------------------------------------
+
+bool CConeVecProjectionGeometry3D::_check()
+{
+ // TODO
+ return true;
+}
+
+} // end namespace astra
diff --git a/src/Config.cpp b/src/Config.cpp
new file mode 100644
index 0000000..8c5cbf5
--- /dev/null
+++ b/src/Config.cpp
@@ -0,0 +1,166 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Config.h"
+
+// For explicit ConfigStackCheck instantiations
+#include "astra/Algorithm.h"
+#include "astra/VolumeGeometry2D.h"
+#include "astra/VolumeGeometry3D.h"
+#include "astra/ProjectionGeometry2D.h"
+#include "astra/ProjectionGeometry3D.h"
+#include "astra/Projector2D.h"
+#include "astra/Projector3D.h"
+
+using namespace astra;
+using namespace std;
+
+//-----------------------------------------------------------------------------
+// default constructor
+Config::Config()
+{
+ self = 0;
+}
+
+//-----------------------------------------------------------------------------
+// not so default constructor
+Config::Config(XMLNode* _self)
+{
+ self = _self;
+}
+
+Config::~Config()
+{
+ delete self;
+ self = 0;
+}
+
+template <class T>
+ConfigStackCheck<T>::ConfigStackCheck(const char *_name, T* _obj, const Config& _cfg)
+ : object(_obj), cfg(&_cfg), name(_name)
+{
+ assert(object);
+ assert(cfg);
+ if (!object->configCheckData) {
+ object->configCheckData = new ConfigCheckData;
+ object->configCheckData->parseDepth = 0;
+ }
+
+ object->configCheckData->parseDepth++;
+}
+
+template <class T>
+ConfigStackCheck<T>::~ConfigStackCheck()
+{
+ assert(object->configCheckData);
+ assert(object->configCheckData->parseDepth > 0);
+
+
+ if (object->configCheckData->parseDepth == 1) {
+ // Entirely done with parsing this Config object
+
+ if (object->isInitialized())
+ stopParsing();
+
+ delete object->configCheckData;
+ object->configCheckData = 0;
+ } else {
+ object->configCheckData->parseDepth--;
+ }
+}
+
+
+// returns true if no unused nodes/options
+template <class T>
+bool ConfigStackCheck<T>::stopParsing()
+{
+ assert(object->configCheckData);
+ assert(object->configCheckData->parseDepth > 0);
+
+ if (object->configCheckData->parseDepth > 1)
+ return true;
+
+ // If this was the top-level parse function, check
+
+ std::string errors;
+
+ std::list<XMLNode*> nodes = cfg->self->getNodes();
+ for (std::list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i)
+ {
+ std::string nodeName = (*i)->getName();
+
+ if (nodeName == "Option") {
+ nodeName = (*i)->getAttribute("key", "");
+ if (object->configCheckData->parsedOptions.find(nodeName) == object->configCheckData->parsedOptions.end()) {
+ if (!errors.empty()) errors += ", ";
+ errors += nodeName;
+ }
+ } else {
+ if (object->configCheckData->parsedNodes.find(nodeName) == object->configCheckData->parsedNodes.end()) {
+ if (!errors.empty()) errors += ", ";
+ errors += nodeName;
+ }
+ }
+ }
+ for (std::list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i)
+ delete (*i);
+ nodes.clear();
+
+ if (!errors.empty()) {
+ cout << "Warning: " << name << ": unused configuration options: " << errors << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+template <class T>
+void ConfigStackCheck<T>::markNodeParsed(const std::string& nodeName)
+{
+ assert(object->configCheckData);
+ assert(object->configCheckData->parseDepth > 0);
+ object->configCheckData->parsedNodes.insert(nodeName);
+}
+
+template <class T>
+void ConfigStackCheck<T>::markOptionParsed(const std::string& nodeName)
+{
+ assert(object->configCheckData);
+ assert(object->configCheckData->parseDepth > 0);
+ object->configCheckData->parsedOptions.insert(nodeName);
+}
+
+
+template class ConfigStackCheck<CAlgorithm>;
+template class ConfigStackCheck<CProjectionGeometry2D>;
+template class ConfigStackCheck<CProjectionGeometry3D>;
+template class ConfigStackCheck<CVolumeGeometry2D>;
+template class ConfigStackCheck<CVolumeGeometry3D>;
+template class ConfigStackCheck<CProjector2D>;
+template class ConfigStackCheck<CProjector3D>;
+
diff --git a/src/ConvexHullAlgorithm.cpp b/src/ConvexHullAlgorithm.cpp
new file mode 100644
index 0000000..e769420
--- /dev/null
+++ b/src/ConvexHullAlgorithm.cpp
@@ -0,0 +1,239 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ConvexHullAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+
+namespace astra {
+
+#include "astra/Projector2DImpl.inl"
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CConvexHullAlgorithm::type = "ConvexHull";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CConvexHullAlgorithm::CConvexHullAlgorithm()
+{
+ _clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+CConvexHullAlgorithm::CConvexHullAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstructionMask)
+{
+ _clear();
+ initialize(_pProjector, _pSinogram, _pReconstructionMask);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CConvexHullAlgorithm::~CConvexHullAlgorithm()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CConvexHullAlgorithm::_clear()
+{
+ m_bIsInitialized = false;
+
+ m_pProjectionPixelWeight = NULL;
+ m_pReconstructionMask = NULL;
+ m_pSinogram = NULL;
+
+ m_pProjector = NULL;
+ m_pDataProjector = NULL;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CConvexHullAlgorithm::clear()
+{
+ m_bIsInitialized = false;
+
+ ASTRA_DELETE(m_pProjectionPixelWeight);
+ m_pReconstructionMask = NULL;
+ m_pSinogram = NULL;
+
+ m_pProjector = NULL;
+ ASTRA_DELETE(m_pDataProjector);
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CConvexHullAlgorithm::_check()
+{
+ ASTRA_CONFIG_CHECK(m_pReconstructionMask, "ConvexHull", "Invalid ReconstructionMask Object");
+ ASTRA_CONFIG_CHECK(m_pReconstructionMask->isInitialized(), "ConvexHull", "Invalid ReconstructionMask Object");
+ ASTRA_CONFIG_CHECK(m_pProjectionPixelWeight, "ConvexHull", "Invalid ProjectionPixelWeight Object");
+ ASTRA_CONFIG_CHECK(m_pProjectionPixelWeight->isInitialized(), "ConvexHull", "Invalid ProjectionPixelWeight Object");
+ ASTRA_CONFIG_CHECK(m_pSinogram, "ConvexHull", "Invalid Sinogram Object");
+ ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "ConvexHull", "Invalid Sinogram Object");
+
+ ASTRA_CONFIG_CHECK(m_pDataProjector, "ConvexHull", "Invalid Data Projector Policy");
+ ASTRA_CONFIG_CHECK(m_pProjector, "ConvexHull", "Invalid Projector Object");
+ ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ConvexHull", "Invalid Projector Object");
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CConvexHullAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // projector
+ XMLNode* node = _cfg.self->getSingleNode("ProjectorId");
+ ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ProjectorId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pProjector = CProjector2DManager::getSingleton().get(id);
+ ASTRA_DELETE(node);
+
+ // sinogram data
+ node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ProjectionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+
+ // reconstruction mask
+ node = _cfg.self->getSingleNode("ConvexHullDataId");
+ ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ReconstructionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+
+ // init data objects and data projectors
+ _init();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CConvexHullAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstructionMask)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstructionMask = _pReconstructionMask;
+
+ // init data objects and data projectors
+ _init();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize Data Projectors - private
+void CConvexHullAlgorithm::_init()
+{
+ // create data objects
+ m_pProjectionPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry());
+ m_pProjectionPixelWeight->setData(0);
+
+ // forward projection data projector
+ m_pDataProjector = dispatchDataProjector(
+ m_pProjector,
+ //SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ TotalPixelWeightBySinogramPolicy(m_pSinogram, m_pProjectionPixelWeight) // pixel weight * sinogram
+ );
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CConvexHullAlgorithm::getInformation()
+{
+ map<string, boost::any> res;
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CConvexHullAlgorithm::getInformation(std::string _sIdentifier)
+{
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CConvexHullAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ m_pReconstructionMask->setData(1.0f);
+
+ // loop angles
+ for (int iProjection = 0; iProjection < m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); ++iProjection) {
+
+ m_pProjectionPixelWeight->setData(0.0f);
+
+ // project
+ m_pDataProjector->projectSingleProjection(iProjection);
+
+ // loop values and set to zero
+ for (int iPixel = 0; iPixel < m_pReconstructionMask->getSize(); ++iPixel) {
+ if (m_pProjectionPixelWeight->getData()[iPixel] == 0) {
+ m_pReconstructionMask->getData()[iPixel] = 0;
+ }
+ }
+
+ }
+
+}
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/CudaBackProjectionAlgorithm.cpp b/src/CudaBackProjectionAlgorithm.cpp
new file mode 100644
index 0000000..7d597b8
--- /dev/null
+++ b/src/CudaBackProjectionAlgorithm.cpp
@@ -0,0 +1,96 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaBackProjectionAlgorithm.h"
+
+#include "../cuda/2d/astra.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaBackProjectionAlgorithm::type = "BP_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaBackProjectionAlgorithm::CCudaBackProjectionAlgorithm()
+{
+ m_bIsInitialized = false;
+ CCudaReconstructionAlgorithm2D::_clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaBackProjectionAlgorithm::~CCudaBackProjectionAlgorithm()
+{
+ // The actual work is done by ~CCudaReconstructionAlgorithm2D
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaBackProjectionAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaBackProjectionAlgorithm", this, _cfg);
+
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ m_pAlgo = new BPalgo();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaBackProjectionAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex, int _iPixelSuperSampling)
+{
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, 1, _iPixelSuperSampling);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ m_pAlgo = new BPalgo();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaBackProjectionAlgorithm3D.cpp b/src/CudaBackProjectionAlgorithm3D.cpp
new file mode 100644
index 0000000..b60adf1
--- /dev/null
+++ b/src/CudaBackProjectionAlgorithm3D.cpp
@@ -0,0 +1,222 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/CudaBackProjectionAlgorithm3D.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/ConeProjectionGeometry3D.h"
+#include "astra/ParallelProjectionGeometry3D.h"
+#include "astra/ParallelVecProjectionGeometry3D.h"
+#include "astra/ConeVecProjectionGeometry3D.h"
+
+#include "../cuda/3d/astra3d.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaBackProjectionAlgorithm3D::type = "BP3D_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaBackProjectionAlgorithm3D::CCudaBackProjectionAlgorithm3D()
+{
+ m_bIsInitialized = false;
+ m_iGPUIndex = 0;
+ m_iVoxelSuperSampling = 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor with initialization
+CCudaBackProjectionAlgorithm3D::CCudaBackProjectionAlgorithm3D(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjectionData,
+ CFloat32VolumeData3DMemory* _pReconstruction)
+{
+ _clear();
+ initialize(_pProjector, _pProjectionData, _pReconstruction);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaBackProjectionAlgorithm3D::~CCudaBackProjectionAlgorithm3D()
+{
+ CReconstructionAlgorithm3D::_clear();
+}
+
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CCudaBackProjectionAlgorithm3D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "BP3D_CUDA", "Error in ReconstructionAlgorithm3D initialization");
+
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaBackProjectionAlgorithm3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaBackProjectionAlgorithm3D", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm3D::initialize(_cfg)) {
+ return false;
+ }
+
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ CC.markOptionParsed("GPUindex");
+ m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1);
+ CC.markOptionParsed("VoxelSuperSampling");
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaBackProjectionAlgorithm3D::initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaBackProjectionAlgorithm3D::getInformation()
+{
+ map<string, boost::any> res;
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaBackProjectionAlgorithm3D::getInformation(std::string _sIdentifier)
+{
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaBackProjectionAlgorithm3D::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram);
+ ASTRA_ASSERT(pSinoMem);
+ CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction);
+ ASTRA_ASSERT(pReconMem);
+
+ const CProjectionGeometry3D* projgeom = pSinoMem->getGeometry();
+ const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
+ const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom);
+ const CConeVecProjectionGeometry3D* conevecgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom);
+ const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
+ const CVolumeGeometry3D& volgeom = *pReconMem->getGeometry();
+
+ if (conegeom) {
+ astraCudaConeBP(pReconMem->getData(), pSinoMem->getDataConst(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ conegeom->getProjectionCount(),
+ conegeom->getDetectorColCount(),
+ conegeom->getDetectorRowCount(),
+ conegeom->getOriginSourceDistance(),
+ conegeom->getOriginDetectorDistance(),
+ conegeom->getDetectorSpacingX(),
+ conegeom->getDetectorSpacingY(),
+ conegeom->getProjectionAngles(),
+ m_iGPUIndex, m_iVoxelSuperSampling);
+ } else if (par3dgeom) {
+ astraCudaPar3DBP(pReconMem->getData(), pSinoMem->getDataConst(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ par3dgeom->getProjectionCount(),
+ par3dgeom->getDetectorColCount(),
+ par3dgeom->getDetectorRowCount(),
+ par3dgeom->getDetectorSpacingX(),
+ par3dgeom->getDetectorSpacingY(),
+ par3dgeom->getProjectionAngles(),
+ m_iGPUIndex, m_iVoxelSuperSampling);
+ } else if (parvec3dgeom) {
+ astraCudaPar3DBP(pReconMem->getData(), pSinoMem->getDataConst(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ parvec3dgeom->getProjectionCount(),
+ parvec3dgeom->getDetectorColCount(),
+ parvec3dgeom->getDetectorRowCount(),
+ parvec3dgeom->getProjectionVectors(),
+ m_iGPUIndex, m_iVoxelSuperSampling);
+ } else if (conevecgeom) {
+ astraCudaConeBP(pReconMem->getData(), pSinoMem->getDataConst(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ conevecgeom->getProjectionCount(),
+ conevecgeom->getDetectorColCount(),
+ conevecgeom->getDetectorRowCount(),
+ conevecgeom->getProjectionVectors(),
+ m_iGPUIndex, m_iVoxelSuperSampling);
+ } else {
+ ASTRA_ASSERT(false);
+ }
+
+}
+
+
+} // namespace astra
diff --git a/src/CudaCglsAlgorithm.cpp b/src/CudaCglsAlgorithm.cpp
new file mode 100644
index 0000000..c408638
--- /dev/null
+++ b/src/CudaCglsAlgorithm.cpp
@@ -0,0 +1,98 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaCglsAlgorithm.h"
+
+#include "../cuda/2d/cgls.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaCglsAlgorithm::type = "CGLS_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaCglsAlgorithm::CCudaCglsAlgorithm()
+{
+ m_bIsInitialized = false;
+ CReconstructionAlgorithm2D::_clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaCglsAlgorithm::~CCudaCglsAlgorithm()
+{
+ // The actual work is done by ~CCudaReconstructionAlgorithm2D
+}
+
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaCglsAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaCglsAlgorithm", this, _cfg);
+
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ m_pAlgo = new astraCUDA::CGLS();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaCglsAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex, int _iDetectorSuperSampling,
+ int _iPixelSuperSampling)
+{
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ m_pAlgo = new astraCUDA::CGLS();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaCglsAlgorithm3D.cpp b/src/CudaCglsAlgorithm3D.cpp
new file mode 100644
index 0000000..07569a2
--- /dev/null
+++ b/src/CudaCglsAlgorithm3D.cpp
@@ -0,0 +1,314 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/CudaCglsAlgorithm3D.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/ConeProjectionGeometry3D.h"
+#include "astra/ParallelVecProjectionGeometry3D.h"
+#include "astra/ConeVecProjectionGeometry3D.h"
+
+#include "../cuda/3d/astra3d.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaCglsAlgorithm3D::type = "CGLS3D_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaCglsAlgorithm3D::CCudaCglsAlgorithm3D()
+{
+ m_bIsInitialized = false;
+ m_pCgls = 0;
+ m_iGPUIndex = 0;
+ m_iVoxelSuperSampling = 1;
+ m_iDetectorSuperSampling = 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor with initialization
+CCudaCglsAlgorithm3D::CCudaCglsAlgorithm3D(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjectionData,
+ CFloat32VolumeData3DMemory* _pReconstruction)
+{
+ _clear();
+ initialize(_pProjector, _pProjectionData, _pReconstruction);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaCglsAlgorithm3D::~CCudaCglsAlgorithm3D()
+{
+ delete m_pCgls;
+ m_pCgls = 0;
+
+ CReconstructionAlgorithm3D::_clear();
+}
+
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CCudaCglsAlgorithm3D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "CGLS3D", "Error in ReconstructionAlgorithm3D initialization");
+
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaCglsAlgorithm3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaCglsAlgorithm3D", this, _cfg);
+
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm3D::initialize(_cfg)) {
+ return false;
+ }
+
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ CC.markOptionParsed("GPUindex");
+ m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1);
+ CC.markOptionParsed("DetectorSuperSampling");
+ m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1);
+ CC.markOptionParsed("VoxelSuperSampling");
+
+ m_pCgls = new AstraCGLS3d();
+
+ m_bAstraCGLSInit = false;
+
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaCglsAlgorithm3D::initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ m_pCgls = new AstraCGLS3d;
+
+ m_bAstraCGLSInit = false;
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaCglsAlgorithm3D::getInformation()
+{
+ map<string, boost::any> res;
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaCglsAlgorithm3D::getInformation(std::string _sIdentifier)
+{
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaCglsAlgorithm3D::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry();
+ const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
+ const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
+ const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom);
+ const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry();
+
+ bool ok = true;
+
+ if (!m_bAstraCGLSInit) {
+
+ ok &= m_pCgls->setGPUIndex(m_iGPUIndex);
+
+ ok &= m_pCgls->setReconstructionGeometry(volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount());
+/*
+ unsigned int iProjAngles,
+ unsigned int iProjU,
+ unsigned int iProjV,
+ float fOriginSourceDistance,
+ float fOriginDetectorDistance,
+ float fDetUSize,
+ float fDetVSize,
+ const float *pfAngles)
+*/
+ fprintf(stderr, "01: %d\n", ok);
+
+ if (conegeom) {
+ ok &= m_pCgls->setConeGeometry(conegeom->getProjectionCount(),
+ conegeom->getDetectorColCount(),
+ conegeom->getDetectorRowCount(),
+ conegeom->getOriginSourceDistance(),
+ conegeom->getOriginDetectorDistance(),
+ conegeom->getDetectorSpacingX(),
+ conegeom->getDetectorSpacingY(),
+ conegeom->getProjectionAngles());
+ } else if (parvec3dgeom) {
+ ok &= m_pCgls->setPar3DGeometry(parvec3dgeom->getProjectionCount(),
+ parvec3dgeom->getDetectorColCount(),
+ parvec3dgeom->getDetectorRowCount(),
+ parvec3dgeom->getProjectionVectors());
+ } else if (conevec3dgeom) {
+ ok &= m_pCgls->setConeGeometry(conevec3dgeom->getProjectionCount(),
+ conevec3dgeom->getDetectorColCount(),
+ conevec3dgeom->getDetectorRowCount(),
+ conevec3dgeom->getProjectionVectors());
+ } else {
+ ASTRA_ASSERT(false);
+ }
+ fprintf(stderr, "02: %d\n", ok);
+
+ ok &= m_pCgls->enableSuperSampling(m_iVoxelSuperSampling, m_iDetectorSuperSampling);
+
+ if (m_bUseReconstructionMask)
+ ok &= m_pCgls->enableVolumeMask();
+#if 0
+ if (m_bUseSinogramMask)
+ ok &= m_pCgls->enableSinogramMask();
+#endif
+
+ ASTRA_ASSERT(ok);
+ fprintf(stderr, "03: %d\n", ok);
+
+ ok &= m_pCgls->init();
+ fprintf(stderr, "04: %d\n", ok);
+
+ ASTRA_ASSERT(ok);
+
+ m_bAstraCGLSInit = true;
+
+ }
+
+ CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram);
+ ASTRA_ASSERT(pSinoMem);
+
+ ok = m_pCgls->setSinogram(pSinoMem->getDataConst(), m_pSinogram->getGeometry()->getDetectorColCount());
+
+ fprintf(stderr, "1: %d\n", ok);
+ ASTRA_ASSERT(ok);
+
+ if (m_bUseReconstructionMask) {
+ CFloat32VolumeData3DMemory* pRMaskMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstructionMask);
+ ASTRA_ASSERT(pRMaskMem);
+ ok &= m_pCgls->setVolumeMask(pRMaskMem->getDataConst(), volgeom.getGridColCount());
+ }
+#if 0
+ if (m_bUseSinogramMask) {
+ CFloat32ProjectionData3DMemory* pSMaskMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogramMask);
+ ASTRA_ASSERT(pSMaskMem);
+ ok &= m_pCgls->setSinogramMask(pSMaskMem->getDataConst(), m_pSinogramMask->getGeometry()->getDetectorColCount());
+ }
+#endif
+ fprintf(stderr, "2: %d\n", ok);
+
+ CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction);
+ ASTRA_ASSERT(pReconMem);
+ ok &= m_pCgls->setStartReconstruction(pReconMem->getDataConst(),
+ volgeom.getGridColCount());
+
+ ASTRA_ASSERT(ok);
+ fprintf(stderr, "3: %d\n", ok);
+
+#if 0
+ if (m_bUseMinConstraint)
+ ok &= m_pCgls->setMinConstraint(m_fMinValue);
+ if (m_bUseMaxConstraint)
+ ok &= m_pCgls->setMaxConstraint(m_fMaxValue);
+#endif
+ fprintf(stderr, "4: %d\n", ok);
+
+ ok &= m_pCgls->iterate(_iNrIterations);
+ ASTRA_ASSERT(ok);
+ fprintf(stderr, "5: %d\n", ok);
+
+ ok &= m_pCgls->getReconstruction(pReconMem->getData(),
+ volgeom.getGridColCount());
+ fprintf(stderr, "6: %d\n", ok);
+ ASTRA_ASSERT(ok);
+
+
+}
+//----------------------------------------------------------------------------------------
+void CCudaCglsAlgorithm3D::signalAbort()
+{
+ if (m_bIsInitialized && m_pCgls) {
+ m_pCgls->signalAbort();
+ }
+}
+
+bool CCudaCglsAlgorithm3D::getResidualNorm(float32& _fNorm)
+{
+ if (!m_bIsInitialized || !m_pCgls)
+ return false;
+
+ _fNorm = m_pCgls->computeDiffNorm();
+
+ return true;
+}
+
+
+
+} // namespace astra
diff --git a/src/CudaDartMaskAlgorithm.cpp b/src/CudaDartMaskAlgorithm.cpp
new file mode 100644
index 0000000..9c9b83f
--- /dev/null
+++ b/src/CudaDartMaskAlgorithm.cpp
@@ -0,0 +1,166 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaDartMaskAlgorithm.h"
+
+#include "../cuda/2d/darthelper.h"
+#include "../cuda/2d/algo.h"
+
+#include "astra/AstraObjectManager.h"
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaDartMaskAlgorithm::type = "DARTMASK_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaDartMaskAlgorithm::CCudaDartMaskAlgorithm()
+{
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaDartMaskAlgorithm::~CCudaDartMaskAlgorithm()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaDartMaskAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg);
+
+ // reconstruction data
+ XMLNode* node = _cfg.self->getSingleNode("SegmentationDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No SegmentationDataId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pSegmentation = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("SegmentationDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("MaskDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No MaskDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("MaskDataId");
+
+ // Option: GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUindex");
+ if (!_cfg.self->hasOption("GPUindex"))
+ CC.markOptionParsed("GPUIndex");
+
+ // Option: Connectivity
+ m_iConn = (unsigned int)_cfg.self->getOptionNumerical("Connectivity", 8);
+ CC.markOptionParsed("Connectivity");
+
+ // Option: Threshold
+ m_iThreshold = (unsigned int)_cfg.self->getOptionNumerical("Threshold", 1);
+ CC.markOptionParsed("Threshold");
+
+ // Option: Radius
+ m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1);
+ CC.markOptionParsed("Radius");
+
+ _check();
+
+ if (!m_bIsInitialized)
+ return false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn)
+//{
+// return false;
+//}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaDartMaskAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ const CVolumeGeometry2D& volgeom = *m_pSegmentation->getGeometry();
+ unsigned int width = volgeom.getGridColCount();
+ unsigned int height = volgeom.getGridRowCount();
+
+ astraCUDA::setGPUIndex(m_iGPUIndex);
+ astraCUDA::dartMask(m_pMask->getData(), m_pSegmentation->getDataConst(), m_iConn, m_iRadius, m_iThreshold, width, height);
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaDartMaskAlgorithm::_check()
+{
+
+ // connectivity: 4 of 8
+
+ // gpuindex >= 0
+
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaDartMaskAlgorithm::getInformation()
+{
+ map<string,boost::any> res;
+ // TODO: add PDART-specific options
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+}
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaDartMaskAlgorithm::getInformation(std::string _sIdentifier)
+{
+ return NULL;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaDartMaskAlgorithm3D.cpp b/src/CudaDartMaskAlgorithm3D.cpp
new file mode 100644
index 0000000..7965587
--- /dev/null
+++ b/src/CudaDartMaskAlgorithm3D.cpp
@@ -0,0 +1,168 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaDartMaskAlgorithm3D.h"
+
+#include "../cuda/3d/darthelper3d.h"
+#include "../cuda/3d/dims3d.h"
+
+#include "astra/AstraObjectManager.h"
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaDartMaskAlgorithm3D::type = "DARTMASK3D_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaDartMaskAlgorithm3D::CCudaDartMaskAlgorithm3D()
+{
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaDartMaskAlgorithm3D::~CCudaDartMaskAlgorithm3D()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaDartMaskAlgorithm3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg);
+
+ // reconstruction data
+ XMLNode* node = _cfg.self->getSingleNode("SegmentationDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No SegmentationDataId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pSegmentation = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("SegmentationDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("MaskDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No MaskDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pMask = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("MaskDataId");
+
+ // Option: GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUindex");
+ if (!_cfg.self->hasOption("GPUindex"))
+ CC.markOptionParsed("GPUIndex");
+
+ // Option: Connectivity
+ m_iConn = (unsigned int)_cfg.self->getOptionNumerical("Connectivity", 8);
+ CC.markOptionParsed("Connectivity");
+
+ // Option: Threshold
+ m_iThreshold = (unsigned int)_cfg.self->getOptionNumerical("Threshold", 1);
+ CC.markOptionParsed("Threshold");
+
+ // Option: Radius
+ m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1);
+ CC.markOptionParsed("Radius");
+
+ _check();
+
+ if (!m_bIsInitialized)
+ return false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+//bool CCudaDartMaskAlgorithm3D::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn)
+//{
+// return false;
+//}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaDartMaskAlgorithm3D::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ const CVolumeGeometry3D& volgeom = *m_pSegmentation->getGeometry();
+ astraCUDA3d::SDimensions3D dims;
+ dims.iVolX = volgeom.getGridColCount();
+ dims.iVolY = volgeom.getGridRowCount();
+ dims.iVolZ = volgeom.getGridSliceCount();
+
+ astraCUDA3d::setGPUIndex(m_iGPUIndex);
+ astraCUDA3d::dartMasking(m_pMask->getData(), m_pSegmentation->getDataConst(), m_iConn, m_iRadius, m_iThreshold, dims);
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaDartMaskAlgorithm3D::_check()
+{
+
+ // connectivity: 4 of 8
+
+ // gpuindex >= 0
+
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaDartMaskAlgorithm3D::getInformation()
+{
+ map<string,boost::any> res;
+ // TODO: add PDART-specific options
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+}
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaDartMaskAlgorithm3D::getInformation(std::string _sIdentifier)
+{
+ return NULL;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaDartSmoothingAlgorithm.cpp b/src/CudaDartSmoothingAlgorithm.cpp
new file mode 100644
index 0000000..91cde6d
--- /dev/null
+++ b/src/CudaDartSmoothingAlgorithm.cpp
@@ -0,0 +1,158 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaDartSmoothingAlgorithm.h"
+
+#include "../cuda/2d/darthelper.h"
+#include "../cuda/2d/algo.h"
+
+#include "astra/AstraObjectManager.h"
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaDartSmoothingAlgorithm::type = "DARTSMOOTHING_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaDartSmoothingAlgorithm::CCudaDartSmoothingAlgorithm()
+{
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaDartSmoothingAlgorithm::~CCudaDartSmoothingAlgorithm()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaDartSmoothingAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaDartSmoothingAlgorithm", this, _cfg);
+
+ // reconstruction data
+ XMLNode* node = _cfg.self->getSingleNode("InDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No InDataId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pIn = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("InDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("OutDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No OutDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pOut = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("OutDataId");
+
+ // Option: GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUindex");
+ if (!_cfg.self->hasOption("GPUindex"))
+ CC.markOptionParsed("GPUIndex");
+
+ // Option: Radius
+ m_fB = (float)_cfg.self->getOptionNumerical("Intensity", 0.3f);
+ CC.markOptionParsed("Intensity");
+
+ // Option: Radius
+ m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1);
+ CC.markOptionParsed("Radius");
+
+
+ _check();
+
+ if (!m_bIsInitialized)
+ return false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn)
+//{
+// return false;
+//}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaDartSmoothingAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ const CVolumeGeometry2D& volgeom = *m_pIn->getGeometry();
+ unsigned int width = volgeom.getGridColCount();
+ unsigned int height = volgeom.getGridRowCount();
+
+ astraCUDA::setGPUIndex(m_iGPUIndex);
+
+ astraCUDA::dartSmoothing(m_pOut->getData(), m_pIn->getDataConst(), m_fB, m_iRadius, width, height);
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaDartSmoothingAlgorithm::_check()
+{
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaDartSmoothingAlgorithm::getInformation()
+{
+ map<string,boost::any> res;
+ // TODO: add PDART-specific options
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+}
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaDartSmoothingAlgorithm::getInformation(std::string _sIdentifier)
+{
+ return NULL;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaDartSmoothingAlgorithm3D.cpp b/src/CudaDartSmoothingAlgorithm3D.cpp
new file mode 100644
index 0000000..50ef847
--- /dev/null
+++ b/src/CudaDartSmoothingAlgorithm3D.cpp
@@ -0,0 +1,160 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaDartSmoothingAlgorithm3D.h"
+
+#include "../cuda/3d/darthelper3d.h"
+#include "../cuda/3d/dims3d.h"
+
+#include "astra/AstraObjectManager.h"
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaDartSmoothingAlgorithm3D::type = "DARTSMOOTHING3D_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaDartSmoothingAlgorithm3D::CCudaDartSmoothingAlgorithm3D()
+{
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaDartSmoothingAlgorithm3D::~CCudaDartSmoothingAlgorithm3D()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaDartSmoothingAlgorithm3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaDartSmoothingAlgorithm", this, _cfg);
+
+ // reconstruction data
+ XMLNode* node = _cfg.self->getSingleNode("InDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No InDataId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pIn = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("InDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("OutDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No OutDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pOut = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("OutDataId");
+
+ // Option: GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUindex");
+ if (!_cfg.self->hasOption("GPUindex"))
+ CC.markOptionParsed("GPUIndex");
+
+ // Option: Intensity
+ m_fB = (float)_cfg.self->getOptionNumerical("Intensity", 0.3f);
+ CC.markOptionParsed("Intensity");
+
+ // Option: Radius
+ m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1);
+ CC.markOptionParsed("Radius");
+
+ _check();
+
+ if (!m_bIsInitialized)
+ return false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+//bool CCudaDartSmoothingAlgorithm3D::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn)
+//{
+// return false;
+//}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaDartSmoothingAlgorithm3D::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ const CVolumeGeometry3D& volgeom = *m_pIn->getGeometry();
+ astraCUDA3d::SDimensions3D dims;
+ dims.iVolX = volgeom.getGridColCount();
+ dims.iVolY = volgeom.getGridRowCount();
+ dims.iVolZ = volgeom.getGridSliceCount();
+
+ astraCUDA3d::setGPUIndex(m_iGPUIndex);
+ astraCUDA3d::dartSmoothing(m_pOut->getData(), m_pIn->getDataConst(), m_fB, m_iRadius, dims);
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaDartSmoothingAlgorithm3D::_check()
+{
+ // geometry of inData must match that of outData
+
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaDartSmoothingAlgorithm3D::getInformation()
+{
+ map<string,boost::any> res;
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+}
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaDartSmoothingAlgorithm3D::getInformation(std::string _sIdentifier)
+{
+ return NULL;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaDataOperationAlgorithm.cpp b/src/CudaDataOperationAlgorithm.cpp
new file mode 100644
index 0000000..ed2ac94
--- /dev/null
+++ b/src/CudaDataOperationAlgorithm.cpp
@@ -0,0 +1,208 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaDataOperationAlgorithm.h"
+
+#include "../cuda/2d/dataop.h"
+#include "../cuda/2d/algo.h"
+#include "../cuda/2d/darthelper.h"
+#include "../cuda/2d/arith.h"
+
+#include "astra/AstraObjectManager.h"
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaDataOperationAlgorithm::type = "DataOperation_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaDataOperationAlgorithm::CCudaDataOperationAlgorithm()
+{
+ m_pMask = NULL;
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaDataOperationAlgorithm::~CCudaDataOperationAlgorithm()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaDataOperationAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CCudaDataOperationAlgorithm", this, _cfg);
+
+ // operation
+ XMLNode* node = _cfg.self->getSingleNode("Operation");
+ ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No Operation tag specified.");
+ m_sOperation = node->getContent();
+ m_sOperation.erase(std::remove(m_sOperation.begin(), m_sOperation.end(), ' '), m_sOperation.end());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("Operation");
+
+ // data
+ node = _cfg.self->getSingleNode("DataId");
+ ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No DataId tag specified.");
+ vector<string> data = node->getContentArray();
+ for (vector<string>::iterator it = data.begin(); it != data.end(); it++){
+ int id = boost::lexical_cast<int>(*it);
+ m_pData.push_back(dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id)));
+ }
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DataId");
+
+ // scalar
+ node = _cfg.self->getSingleNode("Scalar");
+ ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No Scalar tag specified.");
+ m_fScalar = node->getContentNumericalArray();
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("Scalar");
+
+ // Option: GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUindex");
+ if (!_cfg.self->hasOption("GPUindex"))
+ CC.markOptionParsed("GPUIndex");
+
+ if (_cfg.self->hasOption("MaskId")) {
+ int id = boost::lexical_cast<int>(_cfg.self->getOption("MaskId"));
+ m_pMask = dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("MaskId");
+
+ _check();
+
+ if (!m_bIsInitialized)
+ return false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn)
+//{
+// return false;
+//}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaDataOperationAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ astraCUDA::setGPUIndex(m_iGPUIndex);
+
+ if (m_sOperation == "$1*s1" || m_sOperation == "$1.*s1") // data * scalar
+ {
+ unsigned int width = m_pData[0]->getWidth();
+ unsigned int height = m_pData[0]->getHeight();
+ if (m_pMask == NULL)
+ astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), m_fScalar[0], width, height);
+ else
+ astraCUDA::processVolCopy<astraCUDA::opMulMask,astraCUDA::VOL>(m_pData[0]->getData(), m_pMask->getDataConst(), m_fScalar[0], width, height);
+ }
+ else if (m_sOperation == "$1/s1" || m_sOperation == "$1./s1") // data / scalar
+ {
+ unsigned int width = m_pData[0]->getWidth();
+ unsigned int height = m_pData[0]->getHeight();
+ if (m_pMask == NULL)
+ astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), 1.0f/m_fScalar[0], width, height);
+ else
+ astraCUDA::processVolCopy<astraCUDA::opMulMask,astraCUDA::VOL>(m_pData[0]->getData(), m_pMask->getDataConst(), 1.0f/m_fScalar[0], width, height);
+ }
+ else if (m_sOperation == "$1+s1") // data + scalar
+ {
+ unsigned int width = m_pData[0]->getWidth();
+ unsigned int height = m_pData[0]->getHeight();
+ astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), m_fScalar[0], width, height);
+ }
+ else if (m_sOperation == "$1-s1") // data - scalar
+ {
+ unsigned int width = m_pData[0]->getWidth();
+ unsigned int height = m_pData[0]->getHeight();
+ astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), -m_fScalar[0], width, height);
+ }
+ else if (m_sOperation == "$1.*$2") // data .* data
+ {
+ unsigned int width = m_pData[0]->getWidth();
+ unsigned int height = m_pData[0]->getHeight();
+ astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), m_pData[1]->getDataConst(), width, height);
+ }
+ else if (m_sOperation == "$1+$2") // data + data
+ {
+ unsigned int width = m_pData[0]->getWidth();
+ unsigned int height = m_pData[0]->getHeight();
+ astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), m_pData[1]->getDataConst(), width, height);
+ }
+
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaDataOperationAlgorithm::_check()
+{
+ // s*: 1 data + 1 scalar
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaDataOperationAlgorithm::getInformation()
+{
+ map<string,boost::any> res;
+ // TODO: add PDART-specific options
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+}
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaDataOperationAlgorithm::getInformation(std::string _sIdentifier)
+{
+ return NULL;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaEMAlgorithm.cpp b/src/CudaEMAlgorithm.cpp
new file mode 100644
index 0000000..44dd0fd
--- /dev/null
+++ b/src/CudaEMAlgorithm.cpp
@@ -0,0 +1,97 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaEMAlgorithm.h"
+
+#include "../cuda/2d/em.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaEMAlgorithm::type = "EM_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaEMAlgorithm::CCudaEMAlgorithm()
+{
+ m_bIsInitialized = false;
+ CCudaReconstructionAlgorithm2D::_clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaEMAlgorithm::~CCudaEMAlgorithm()
+{
+ // The actual work is done by ~CCudaReconstructionAlgorithm2D
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaEMAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaEMAlgorithm", this, _cfg);
+
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ m_pAlgo = new astraCUDA::EM();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaEMAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex, int _iDetectorSuperSampling,
+ int _iPixelSuperSampling)
+{
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ m_pAlgo = new astraCUDA::EM();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaFDKAlgorithm3D.cpp b/src/CudaFDKAlgorithm3D.cpp
new file mode 100644
index 0000000..8f9e7b8
--- /dev/null
+++ b/src/CudaFDKAlgorithm3D.cpp
@@ -0,0 +1,192 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/CudaFDKAlgorithm3D.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/ConeProjectionGeometry3D.h"
+
+#include "../cuda/3d/astra3d.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaFDKAlgorithm3D::type = "FDK_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaFDKAlgorithm3D::CCudaFDKAlgorithm3D()
+{
+ m_bIsInitialized = false;
+ m_iGPUIndex = 0;
+ m_iVoxelSuperSampling = 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor with initialization
+CCudaFDKAlgorithm3D::CCudaFDKAlgorithm3D(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjectionData,
+ CFloat32VolumeData3DMemory* _pReconstruction)
+{
+ _clear();
+ initialize(_pProjector, _pProjectionData, _pReconstruction);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaFDKAlgorithm3D::~CCudaFDKAlgorithm3D()
+{
+ CReconstructionAlgorithm3D::_clear();
+}
+
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CCudaFDKAlgorithm3D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "CUDA_FDK", "Error in ReconstructionAlgorithm3D initialization");
+
+ const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry();
+ ASTRA_CONFIG_CHECK(dynamic_cast<const CConeProjectionGeometry3D*>(projgeom), "CUDA_FDK", "Error setting FDK geometry");
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaFDKAlgorithm3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaFDKAlgorithm3D", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm3D::initialize(_cfg)) {
+ return false;
+ }
+
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ CC.markOptionParsed("GPUindex");
+ m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1);
+ CC.markOptionParsed("VoxelSuperSampling");
+
+ m_bShortScan = _cfg.self->getOptionBool("ShortScan", false);
+ CC.markOptionParsed("ShortScan");
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaFDKAlgorithm3D::initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaFDKAlgorithm3D::getInformation()
+{
+ map<string, boost::any> res;
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaFDKAlgorithm3D::getInformation(std::string _sIdentifier)
+{
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaFDKAlgorithm3D::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry();
+ const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
+ const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry();
+
+ ASTRA_ASSERT(conegeom);
+
+ CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram);
+ ASTRA_ASSERT(pSinoMem);
+ CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction);
+ ASTRA_ASSERT(pReconMem);
+
+
+ bool ok = true;
+
+ ok = astraCudaFDK(pReconMem->getData(), pSinoMem->getDataConst(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ conegeom->getProjectionCount(),
+ conegeom->getDetectorColCount(),
+ conegeom->getDetectorRowCount(),
+ conegeom->getOriginSourceDistance(),
+ conegeom->getOriginDetectorDistance(),
+ conegeom->getDetectorSpacingX(),
+ conegeom->getDetectorSpacingY(),
+ conegeom->getProjectionAngles(),
+ m_bShortScan, m_iGPUIndex, m_iVoxelSuperSampling);
+
+ ASTRA_ASSERT(ok);
+
+}
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/CudaFilteredBackProjectionAlgorithm.cpp b/src/CudaFilteredBackProjectionAlgorithm.cpp
new file mode 100644
index 0000000..75a1534
--- /dev/null
+++ b/src/CudaFilteredBackProjectionAlgorithm.cpp
@@ -0,0 +1,442 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <astra/CudaFilteredBackProjectionAlgorithm.h>
+#include <boost/lexical_cast.hpp>
+#include <cstring>
+
+#include "astra/AstraObjectManager.h"
+
+#include <astra/Logger.h>
+
+using namespace std;
+using namespace astra;
+
+string CCudaFilteredBackProjectionAlgorithm::type = "FBP_CUDA";
+
+CCudaFilteredBackProjectionAlgorithm::CCudaFilteredBackProjectionAlgorithm()
+{
+ m_bIsInitialized = false;
+ CReconstructionAlgorithm2D::_clear();
+ m_pFBP = 0;
+ m_pfFilter = NULL;
+ m_fFilterParameter = -1.0f;
+ m_fFilterD = 1.0f;
+}
+
+CCudaFilteredBackProjectionAlgorithm::~CCudaFilteredBackProjectionAlgorithm()
+{
+ if(m_pfFilter != NULL)
+ {
+ delete [] m_pfFilter;
+ m_pfFilter = NULL;
+ }
+
+ if(m_pFBP != NULL)
+ {
+ delete m_pFBP;
+ m_pFBP = NULL;
+ }
+}
+
+bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaFilteredBackProjectionAlgorithm", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized)
+ {
+ clear();
+ }
+
+ // sinogram data
+ XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaFBP", "No ProjectionDataId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("ReconstructionDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaFBP", "No ReconstructionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ReconstructionDataId");
+
+ // filter type
+ node = _cfg.self->getSingleNode("FilterType");
+ if(node != NULL)
+ {
+ m_eFilter = _convertStringToFilter(node->getContent().c_str());
+ }
+ else
+ {
+ m_eFilter = FILTER_RAMLAK;
+ }
+ CC.markNodeParsed("FilterType");
+ ASTRA_DELETE(node);
+
+ // filter
+ node = _cfg.self->getSingleNode("FilterSinogramId");
+ if(node != NULL)
+ {
+ int id = boost::lexical_cast<int>(node->getContent());
+ const CFloat32ProjectionData2D * pFilterData = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ m_iFilterWidth = pFilterData->getGeometry()->getDetectorCount();
+ int iFilterProjectionCount = pFilterData->getGeometry()->getProjectionAngleCount();
+
+ m_pfFilter = new float[m_iFilterWidth * iFilterProjectionCount];
+ memcpy(m_pfFilter, pFilterData->getDataConst(), sizeof(float) * m_iFilterWidth * iFilterProjectionCount);
+ }
+ else
+ {
+ m_iFilterWidth = 0;
+ m_pfFilter = NULL;
+ }
+ CC.markNodeParsed("FilterSinogramId"); // TODO: Only for some types!
+ ASTRA_DELETE(node);
+
+ // filter parameter
+ node = _cfg.self->getSingleNode("FilterParameter");
+ if(node != NULL)
+ {
+ float fParameter = boost::lexical_cast<float>(node->getContent());
+ m_fFilterParameter = fParameter;
+ }
+ else
+ {
+ m_fFilterParameter = -1.0f;
+ }
+ CC.markNodeParsed("FilterParameter"); // TODO: Only for some types!
+ ASTRA_DELETE(node);
+
+ // D value
+ node = _cfg.self->getSingleNode("FilterD");
+ if(node != NULL)
+ {
+ float fD = boost::lexical_cast<float>(node->getContent());
+ m_fFilterD = fD;
+ }
+ else
+ {
+ m_fFilterD = 1.0f;
+ }
+ CC.markNodeParsed("FilterD"); // TODO: Only for some types!
+ ASTRA_DELETE(node);
+
+ // GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ CC.markOptionParsed("GPUindex");
+
+ // Pixel supersampling factor
+ m_iPixelSuperSampling = (int)_cfg.self->getOptionNumerical("PixelSuperSampling", 1);
+ CC.markOptionParsed("PixelSuperSampling");
+
+
+ m_pFBP = new AstraFBP;
+ m_bAstraFBPInit = false;
+
+ // success
+ m_bIsInitialized = true;
+ return m_bIsInitialized;
+}
+
+bool CCudaFilteredBackProjectionAlgorithm::initialize(CFloat32ProjectionData2D * _pSinogram, CFloat32VolumeData2D * _pReconstruction, E_FBPFILTER _eFilter, const float * _pfFilter /* = NULL */, int _iFilterWidth /* = 0 */, int _iGPUIndex /* = 0 */, float _fFilterParameter /* = -1.0f */)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized)
+ {
+ clear();
+ }
+
+ // required classes
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+ m_iGPUIndex = _iGPUIndex;
+
+ m_eFilter = _eFilter;
+ m_iFilterWidth = _iFilterWidth;
+
+ // success
+ m_bIsInitialized = true;
+
+ m_pFBP = new AstraFBP;
+
+ m_bAstraFBPInit = false;
+
+ if(_pfFilter != NULL)
+ {
+ int iFilterElementCount = 0;
+
+ if((_eFilter != FILTER_SINOGRAM) && (_eFilter != FILTER_RSINOGRAM))
+ {
+ iFilterElementCount = _iFilterWidth;
+ }
+ else
+ {
+ iFilterElementCount = m_pSinogram->getAngleCount();
+ }
+
+ m_pfFilter = new float[iFilterElementCount];
+ memcpy(m_pfFilter, _pfFilter, iFilterElementCount * sizeof(float));
+ }
+ else
+ {
+ m_pfFilter = NULL;
+ }
+
+ m_fFilterParameter = _fFilterParameter;
+
+ return m_bIsInitialized;
+}
+
+void CCudaFilteredBackProjectionAlgorithm::run(int _iNrIterations /* = 0 */)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ if (!m_bAstraFBPInit) {
+
+ const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
+ const CParallelProjectionGeometry2D& projgeom = *dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry());
+
+ bool ok = true;
+
+ // TODO: off-center geometry, non-square pixels
+ ok &= m_pFBP->setReconstructionGeometry(volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getPixelLengthX());
+ // TODO: off-center geometry
+ ok &= m_pFBP->setProjectionGeometry(projgeom.getProjectionAngleCount(),
+ projgeom.getDetectorCount(),
+ projgeom.getProjectionAngles(),
+ projgeom.getDetectorWidth());
+
+ ok &= m_pFBP->setPixelSuperSampling(m_iPixelSuperSampling);
+
+ ASTRA_ASSERT(ok);
+
+ const float *pfTOffsets = m_pSinogram->getGeometry()->getExtraDetectorOffset();
+ if (pfTOffsets)
+ ok &= m_pFBP->setTOffsets(pfTOffsets);
+ ASTRA_ASSERT(ok);
+
+ ok &= m_pFBP->init(m_iGPUIndex);
+ ASTRA_ASSERT(ok);
+
+ ok &= m_pFBP->setSinogram(m_pSinogram->getDataConst(), projgeom.getDetectorCount());
+ ASTRA_ASSERT(ok);
+
+ ok &= m_pFBP->setFilter(m_eFilter, m_pfFilter, m_iFilterWidth, m_fFilterD, m_fFilterParameter);
+ ASTRA_ASSERT(ok);
+
+ m_bAstraFBPInit = true;
+ }
+
+ bool ok = m_pFBP->run();
+ ASTRA_ASSERT(ok);
+
+ const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
+ ok &= m_pFBP->getReconstruction(m_pReconstruction->getData(), volgeom.getGridColCount());
+
+ ASTRA_ASSERT(ok);
+}
+
+bool CCudaFilteredBackProjectionAlgorithm::check()
+{
+ // check pointers
+ ASTRA_CONFIG_CHECK(m_pSinogram, "FBP_CUDA", "Invalid Projection Data Object.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction, "FBP_CUDA", "Invalid Reconstruction Data Object.");
+
+ if((m_eFilter == FILTER_PROJECTION) || (m_eFilter == FILTER_SINOGRAM) || (m_eFilter == FILTER_RPROJECTION) || (m_eFilter == FILTER_RSINOGRAM))
+ {
+ ASTRA_CONFIG_CHECK(m_pfFilter, "FBP_CUDA", "Invalid filter pointer.");
+ }
+
+ // check initializations
+ ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "FBP_CUDA", "Projection Data Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "FBP_CUDA", "Reconstruction Data Object Not Initialized.");
+
+ // check gpu index
+ ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FBP_CUDA", "GPUIndex must be a non-negative integer.");
+ // check pixel supersampling
+ ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 0, "FBP_CUDA", "PixelSuperSampling must be a non-negative integer.");
+
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+static int calcNextPowerOfTwo(int _iValue)
+{
+ int iOutput = 1;
+
+ while(iOutput < _iValue)
+ {
+ iOutput *= 2;
+ }
+
+ return iOutput;
+}
+
+int CCudaFilteredBackProjectionAlgorithm::calcIdealRealFilterWidth(int _iDetectorCount)
+{
+ return calcNextPowerOfTwo(_iDetectorCount);
+}
+
+int CCudaFilteredBackProjectionAlgorithm::calcIdealFourierFilterWidth(int _iDetectorCount)
+{
+ return (calcNextPowerOfTwo(_iDetectorCount) / 2 + 1);
+}
+
+static bool stringCompareLowerCase(const char * _stringA, const char * _stringB)
+{
+ int iCmpReturn = 0;
+
+#ifdef _MSC_VER
+ iCmpReturn = _stricmp(_stringA, _stringB);
+#else
+ iCmpReturn = strcasecmp(_stringA, _stringB);
+#endif
+
+ return (iCmpReturn == 0);
+}
+
+E_FBPFILTER CCudaFilteredBackProjectionAlgorithm::_convertStringToFilter(const char * _filterType)
+{
+ E_FBPFILTER output = FILTER_NONE;
+
+ if(stringCompareLowerCase(_filterType, "ram-lak"))
+ {
+ output = FILTER_RAMLAK;
+ }
+ else if(stringCompareLowerCase(_filterType, "shepp-logan"))
+ {
+ output = FILTER_SHEPPLOGAN;
+ }
+ else if(stringCompareLowerCase(_filterType, "cosine"))
+ {
+ output = FILTER_COSINE;
+ }
+ else if(stringCompareLowerCase(_filterType, "hamming"))
+ {
+ output = FILTER_HAMMING;
+ }
+ else if(stringCompareLowerCase(_filterType, "hann"))
+ {
+ output = FILTER_HANN;
+ }
+ else if(stringCompareLowerCase(_filterType, "none"))
+ {
+ output = FILTER_NONE;
+ }
+ else if(stringCompareLowerCase(_filterType, "tukey"))
+ {
+ output = FILTER_TUKEY;
+ }
+ else if(stringCompareLowerCase(_filterType, "lanczos"))
+ {
+ output = FILTER_LANCZOS;
+ }
+ else if(stringCompareLowerCase(_filterType, "triangular"))
+ {
+ output = FILTER_TRIANGULAR;
+ }
+ else if(stringCompareLowerCase(_filterType, "gaussian"))
+ {
+ output = FILTER_GAUSSIAN;
+ }
+ else if(stringCompareLowerCase(_filterType, "barlett-hann"))
+ {
+ output = FILTER_BARTLETTHANN;
+ }
+ else if(stringCompareLowerCase(_filterType, "blackman"))
+ {
+ output = FILTER_BLACKMAN;
+ }
+ else if(stringCompareLowerCase(_filterType, "nuttall"))
+ {
+ output = FILTER_NUTTALL;
+ }
+ else if(stringCompareLowerCase(_filterType, "blackman-harris"))
+ {
+ output = FILTER_BLACKMANHARRIS;
+ }
+ else if(stringCompareLowerCase(_filterType, "blackman-nuttall"))
+ {
+ output = FILTER_BLACKMANNUTTALL;
+ }
+ else if(stringCompareLowerCase(_filterType, "flat-top"))
+ {
+ output = FILTER_FLATTOP;
+ }
+ else if(stringCompareLowerCase(_filterType, "kaiser"))
+ {
+ output = FILTER_KAISER;
+ }
+ else if(stringCompareLowerCase(_filterType, "parzen"))
+ {
+ output = FILTER_PARZEN;
+ }
+ else if(stringCompareLowerCase(_filterType, "projection"))
+ {
+ output = FILTER_PROJECTION;
+ }
+ else if(stringCompareLowerCase(_filterType, "sinogram"))
+ {
+ output = FILTER_SINOGRAM;
+ }
+ else if(stringCompareLowerCase(_filterType, "rprojection"))
+ {
+ output = FILTER_RPROJECTION;
+ }
+ else if(stringCompareLowerCase(_filterType, "rsinogram"))
+ {
+ output = FILTER_RSINOGRAM;
+ }
+ else
+ {
+ cerr << "Failed to convert \"" << _filterType << "\" into a filter." << endl;
+ }
+
+ return output;
+}
+
+void CCudaFilteredBackProjectionAlgorithm::testGenFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount, cufftComplex * _pFilter, int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount)
+{
+ genFilter(_eFilter, _fD, _iProjectionCount, _pFilter, _iFFTRealDetectorCount, _iFFTFourierDetectorCount);
+}
+
+int CCudaFilteredBackProjectionAlgorithm::getGPUCount()
+{
+ return 0;
+}
diff --git a/src/CudaForwardProjectionAlgorithm.cpp b/src/CudaForwardProjectionAlgorithm.cpp
new file mode 100644
index 0000000..965c4af
--- /dev/null
+++ b/src/CudaForwardProjectionAlgorithm.cpp
@@ -0,0 +1,276 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/CudaForwardProjectionAlgorithm.h"
+
+#ifdef ASTRA_CUDA
+
+#include "../cuda/2d/astra.h"
+
+#include <driver_types.h>
+#include <cuda_runtime_api.h>
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+#include "astra/FanFlatProjectionGeometry2D.h"
+#include "astra/FanFlatVecProjectionGeometry2D.h"
+#include "astra/CudaProjector2D.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaForwardProjectionAlgorithm::type = "FP_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaForwardProjectionAlgorithm::CCudaForwardProjectionAlgorithm()
+{
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaForwardProjectionAlgorithm::~CCudaForwardProjectionAlgorithm()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaForwardProjectionAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaForwardProjectionAlgorithm", this, _cfg);
+
+ // sinogram data
+ XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "FP_CUDA", "No ProjectionDataId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionDataId");
+
+ // volume data
+ node = _cfg.self->getSingleNode("VolumeDataId");
+ ASTRA_CONFIG_CHECK(node, "FP_CUDA", "No VolumeDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pVolume = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("VolumeDataId");
+
+ // GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUindex");
+ if (!_cfg.self->hasOption("GPUindex"))
+ CC.markOptionParsed("GPUIndex");
+
+ // Detector supersampling factor
+ m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1);
+ CC.markOptionParsed("DetectorSuperSampling");
+
+
+ // This isn't used yet, but passing it is not something to warn about
+ node = _cfg.self->getSingleNode("ProjectorId");
+ if (node) {
+ id = boost::lexical_cast<int>(node->getContent());
+ CProjector2D *projector = CProjector2DManager::getSingleton().get(id);
+ if (!dynamic_cast<CCudaProjector2D*>(projector)) {
+ cout << "Warning: non-CUDA Projector2D passed to FP_CUDA" << std::endl;
+ }
+ delete node;
+ }
+ CC.markNodeParsed("ProjectorId");
+
+
+
+ // return success
+ return check();
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaForwardProjectionAlgorithm::initialize(CProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry,
+ CFloat32VolumeData2D* _pVolume,
+ CFloat32ProjectionData2D* _pSinogram,
+ int _iGPUindex, int _iDetectorSuperSampling)
+{
+ // store classes
+ //m_pProjectionGeometry = _pProjectionGeometry;
+ //m_pReconstructionGeometry = _pReconstructionGeometry;
+ m_pVolume = _pVolume;
+ m_pSinogram = _pSinogram;
+
+ m_iDetectorSuperSampling = _iDetectorSuperSampling;
+ m_iGPUIndex = _iGPUindex;
+
+ // return success
+ return check();
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaForwardProjectionAlgorithm::check()
+{
+ // check pointers
+ ASTRA_CONFIG_CHECK(m_pSinogram, "FP_CUDA", "No valid projection data object found.");
+ ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "FP_CUDA", "Projection data not initialized.");
+ ASTRA_CONFIG_CHECK(m_pVolume, "FP_CUDA", "No valid volume data object found.");
+ ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "FP_CUDA", "Volume data not initialized.");
+
+ // check restrictions
+ //int iImageSideBlocks = m_pReconstructionGeometry->getGridColCount() / G_BLOCKIMAGESIZE;
+ //ASTRA_CONFIG_CHECK((iImageSideBlocks * G_BLOCKIMAGESIZE) == m_pVolume->getWidth(), "FP_CUDA", "Volume Width must be a multiple of G_BLOCKIMAGESIZE");
+ //ASTRA_CONFIG_CHECK((iImageSideBlocks * G_BLOCKIMAGESIZE) == m_pVolume->getHeight(), "FP_CUDA", "Volume Height must be a multiple of G_BLOCKIMAGESIZE");
+ //ASTRA_CONFIG_CHECK(m_pProjectionGeometry->getDetectorCount() == (m_pVolume->getWidth() * 3 / 2), "SIRT_CUDA", "Number of detectors must be 1.5 times the width of the image");
+
+ ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FP_CUDA", "GPUIndex must be a non-negative integer.");
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+void CCudaForwardProjectionAlgorithm::setGPUIndex(int _iGPUIndex)
+{
+ m_iGPUIndex = _iGPUIndex;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaForwardProjectionAlgorithm::getInformation()
+{
+ map<string, boost::any> res;
+ res["ProjectionGeometry"] = getInformation("ProjectionGeometry");
+ res["ReconstructionGeometry"] = getInformation("ReconstructionGeometry");
+ res["ProjectionDataId"] = getInformation("ProjectionDataId");
+ res["VolumeDataId"] = getInformation("VolumeDataId");
+ res["GPUindex"] = getInformation("GPUindex");
+ res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling");
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaForwardProjectionAlgorithm::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); }
+ if (_sIdentifier == "ReconstructionGeometry") { return string("not implemented"); }
+ if (_sIdentifier == "ProjectionDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "VolumeDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pVolume);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "GPUindex") { return m_iGPUIndex; }
+ if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; }
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Run
+void CCudaForwardProjectionAlgorithm::run(int)
+{
+ // check initialized
+ assert(m_bIsInitialized);
+
+ CVolumeGeometry2D* pVolGeom = m_pVolume->getGeometry();
+ const CParallelProjectionGeometry2D* parProjGeom = dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry());
+ const CFanFlatProjectionGeometry2D* fanProjGeom = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pSinogram->getGeometry());
+ const CFanFlatVecProjectionGeometry2D* fanVecProjGeom = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pSinogram->getGeometry());
+
+ bool ok = false;
+ if (parProjGeom) {
+ ok = astraCudaFP(m_pVolume->getDataConst(), m_pSinogram->getData(),
+ pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(),
+ parProjGeom->getProjectionAngleCount(),
+ parProjGeom->getDetectorCount(),
+ parProjGeom->getProjectionAngles(),
+ parProjGeom->getExtraDetectorOffset(), parProjGeom->getDetectorWidth() / pVolGeom->getPixelLengthX(),
+ m_iDetectorSuperSampling, m_iGPUIndex);
+
+ } else if (fanProjGeom) {
+
+ ok = astraCudaFanFP(m_pVolume->getDataConst(), m_pSinogram->getData(),
+ pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(),
+ fanProjGeom->getProjectionAngleCount(),
+ fanProjGeom->getDetectorCount(),
+ fanProjGeom->getProjectionAngles(),
+ fanProjGeom->getOriginSourceDistance(),
+ fanProjGeom->getOriginDetectorDistance(),
+ pVolGeom->getPixelLengthX(),
+ fanProjGeom->getDetectorWidth(),
+ m_iDetectorSuperSampling, m_iGPUIndex);
+
+ } else if (fanVecProjGeom) {
+
+ // Rescale projs to fPixelSize == 1
+ float fPixelSize = pVolGeom->getPixelLengthX();
+ const astraCUDA::SFanProjection* projs;
+ projs = fanVecProjGeom->getProjectionVectors();
+
+ astraCUDA::SFanProjection* scaledProjs = new astraCUDA::SFanProjection[fanVecProjGeom->getProjectionAngleCount()];
+#define SCALE(name,i,alpha) do { scaledProjs[i].f##name##X = projs[i].f##name##X * alpha; scaledProjs[i].f##name##Y = projs[i].f##name##Y * alpha; } while (0)
+ for (unsigned int i = 0; i < fanVecProjGeom->getProjectionAngleCount(); ++i) {
+ SCALE(Src,i,1.0f/fPixelSize);
+ SCALE(DetS,i,1.0f/fPixelSize);
+ SCALE(DetU,i,1.0f/fPixelSize);
+ }
+
+
+ ok = astraCudaFanFP(m_pVolume->getDataConst(), m_pSinogram->getData(),
+ pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(),
+ fanVecProjGeom->getProjectionAngleCount(),
+ fanVecProjGeom->getDetectorCount(),
+ scaledProjs,
+ /* 1.0f / pVolGeom->getPixelLengthX(), */
+ m_iDetectorSuperSampling, m_iGPUIndex);
+
+ delete[] scaledProjs;
+
+ } else {
+
+ ASTRA_ASSERT(false);
+
+ }
+
+ ASTRA_ASSERT(ok);
+
+}
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaForwardProjectionAlgorithm3D.cpp b/src/CudaForwardProjectionAlgorithm3D.cpp
new file mode 100644
index 0000000..e9289f1
--- /dev/null
+++ b/src/CudaForwardProjectionAlgorithm3D.cpp
@@ -0,0 +1,311 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/CudaForwardProjectionAlgorithm3D.h"
+
+#ifdef ASTRA_CUDA
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/CudaProjector3D.h"
+#include "astra/ConeProjectionGeometry3D.h"
+#include "astra/ParallelProjectionGeometry3D.h"
+#include "astra/ParallelVecProjectionGeometry3D.h"
+#include "astra/ConeVecProjectionGeometry3D.h"
+
+#include "../cuda/3d/astra3d.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaForwardProjectionAlgorithm3D::type = "FP3D_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaForwardProjectionAlgorithm3D::CCudaForwardProjectionAlgorithm3D()
+{
+ m_bIsInitialized = false;
+ m_iGPUIndex = 0;
+ m_iDetectorSuperSampling = 1;
+ m_pProjector = 0;
+ m_pProjections = 0;
+ m_pVolume = 0;
+
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaForwardProjectionAlgorithm3D::~CCudaForwardProjectionAlgorithm3D()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaForwardProjectionAlgorithm3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaForwardProjectionAlgorithm3D", this, _cfg);
+
+ XMLNode* node;
+ int id;
+
+ // sinogram data
+ node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No ProjectionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pProjections = dynamic_cast<CFloat32ProjectionData3DMemory*>(CData3DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("VolumeDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No VolumeDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pVolume = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("VolumeDataId");
+
+ // optional: projector
+ node = _cfg.self->getSingleNode("ProjectorId");
+ if (node) {
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pProjector = CProjector3DManager::getSingleton().get(id);
+ ASTRA_DELETE(node);
+ } else {
+ m_pProjector = 0; // TODO: or manually construct default projector?
+ }
+ CC.markNodeParsed("ProjectorId");
+
+ // GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ CC.markOptionParsed("GPUindex");
+ m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1);
+ CC.markOptionParsed("DetectorSuperSampling");
+
+ // success
+ m_bIsInitialized = check();
+
+ if (!m_bIsInitialized)
+ return false;
+
+ return true;
+}
+
+
+bool CCudaForwardProjectionAlgorithm3D::initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjections,
+ CFloat32VolumeData3DMemory* _pVolume,
+ int _iGPUindex, int _iDetectorSuperSampling)
+{
+ m_pProjector = _pProjector;
+
+ // required classes
+ m_pProjections = _pProjections;
+ m_pVolume = _pVolume;
+
+ m_iDetectorSuperSampling = _iDetectorSuperSampling;
+ m_iGPUIndex = _iGPUindex;
+
+ // success
+ m_bIsInitialized = check();
+
+ if (!m_bIsInitialized)
+ return false;
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaForwardProjectionAlgorithm3D::check()
+{
+ // check pointers
+ //ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object.");
+ ASTRA_CONFIG_CHECK(m_pProjections, "FP3D_CUDA", "Invalid Projection Data Object.");
+ ASTRA_CONFIG_CHECK(m_pVolume, "FP3D_CUDA", "Invalid Volume Data Object.");
+
+ // check initializations
+ //ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pProjections->isInitialized(), "FP3D_CUDA", "Projection Data Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "FP3D_CUDA", "Volume Data Object Not Initialized.");
+
+ ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "FP3D_CUDA", "DetectorSuperSampling must be a positive integer.");
+ ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FP3D_CUDA", "GPUIndex must be a non-negative integer.");
+
+ // check compatibility between projector and data classes
+// ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "SIRT_CUDA", "Projection Data not compatible with the specified Projector.");
+// ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "SIRT_CUDA", "Reconstruction Data not compatible with the specified Projector.");
+
+ // todo: turn some of these back on
+
+// ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "SIRT_CUDA", "ProjectionGeometry not specified.");
+// ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SIRT_CUDA", "ProjectionGeometry not initialized.");
+// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry, "SIRT_CUDA", "ReconstructionGeometry not specified.");
+// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry->isInitialized(), "SIRT_CUDA", "ReconstructionGeometry not initialized.");
+
+ // check dimensions
+ //ASTRA_CONFIG_CHECK(m_pSinogram->getAngleCount() == m_pProjectionGeometry->getProjectionAngleCount(), "SIRT_CUDA", "Sinogram data object size mismatch.");
+ //ASTRA_CONFIG_CHECK(m_pSinogram->getDetectorCount() == m_pProjectionGeometry->getDetectorCount(), "SIRT_CUDA", "Sinogram data object size mismatch.");
+ //ASTRA_CONFIG_CHECK(m_pReconstruction->getWidth() == m_pReconstructionGeometry->getGridColCount(), "SIRT_CUDA", "Reconstruction data object size mismatch.");
+ //ASTRA_CONFIG_CHECK(m_pReconstruction->getHeight() == m_pReconstructionGeometry->getGridRowCount(), "SIRT_CUDA", "Reconstruction data object size mismatch.");
+
+ // check restrictions
+ // TODO: check restrictions built into cuda code
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+
+void CCudaForwardProjectionAlgorithm3D::setGPUIndex(int _iGPUIndex)
+{
+ m_iGPUIndex = _iGPUIndex;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaForwardProjectionAlgorithm3D::getInformation()
+{
+ map<string,boost::any> res;
+ res["ProjectionGeometry"] = getInformation("ProjectionGeometry");
+ res["VolumeGeometry"] = getInformation("VolumeGeometry");
+ res["ProjectionDataId"] = getInformation("ProjectionDataId");
+ res["VolumeDataId"] = getInformation("VolumeDataId");
+ res["GPUindex"] = getInformation("GPUindex");
+ res["GPUindex"] = getInformation("GPUindex");
+ res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling");
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+}
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaForwardProjectionAlgorithm3D::getInformation(std::string _sIdentifier)
+{
+ // TODO: store these so we can return them?
+ if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); }
+ if (_sIdentifier == "VolumeGeometry") { return string("not implemented"); }
+ if (_sIdentifier == "GPUindex") { return m_iGPUIndex; }
+ if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; }
+
+ if (_sIdentifier == "ProjectionDataId") {
+ int iIndex = CData3DManager::getSingleton().getIndex(m_pProjections);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "VolumeDataId") {
+ int iIndex = CData3DManager::getSingleton().getIndex(m_pVolume);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ return CAlgorithm::getInformation(_sIdentifier);
+}
+
+//----------------------------------------------------------------------------------------
+// Run
+void CCudaForwardProjectionAlgorithm3D::run(int)
+{
+ // check initialized
+ assert(m_bIsInitialized);
+
+ const CProjectionGeometry3D* projgeom = m_pProjections->getGeometry();
+ const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
+ const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom);
+ const CConeVecProjectionGeometry3D* conevecgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom);
+ const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
+ const CVolumeGeometry3D& volgeom = *m_pVolume->getGeometry();
+
+ Cuda3DProjectionKernel projKernel = ker3d_default;
+ if (m_pProjector) {
+ CCudaProjector3D* projector = dynamic_cast<CCudaProjector3D*>(m_pProjector);
+ projKernel = projector->getProjectionKernel();
+ }
+
+ if (conegeom) {
+ astraCudaConeFP(m_pVolume->getDataConst(), m_pProjections->getData(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ conegeom->getProjectionCount(),
+ conegeom->getDetectorColCount(),
+ conegeom->getDetectorRowCount(),
+ conegeom->getOriginSourceDistance(),
+ conegeom->getOriginDetectorDistance(),
+ conegeom->getDetectorSpacingX(),
+ conegeom->getDetectorSpacingY(),
+ conegeom->getProjectionAngles(),
+ m_iGPUIndex, m_iDetectorSuperSampling);
+ } else if (par3dgeom) {
+ astraCudaPar3DFP(m_pVolume->getDataConst(), m_pProjections->getData(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ par3dgeom->getProjectionCount(),
+ par3dgeom->getDetectorColCount(),
+ par3dgeom->getDetectorRowCount(),
+ par3dgeom->getDetectorSpacingX(),
+ par3dgeom->getDetectorSpacingY(),
+ par3dgeom->getProjectionAngles(),
+ m_iGPUIndex, m_iDetectorSuperSampling,
+ projKernel);
+ } else if (parvec3dgeom) {
+ astraCudaPar3DFP(m_pVolume->getDataConst(), m_pProjections->getData(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ parvec3dgeom->getProjectionCount(),
+ parvec3dgeom->getDetectorColCount(),
+ parvec3dgeom->getDetectorRowCount(),
+ parvec3dgeom->getProjectionVectors(),
+ m_iGPUIndex, m_iDetectorSuperSampling,
+ projKernel);
+ } else if (conevecgeom) {
+ astraCudaConeFP(m_pVolume->getDataConst(), m_pProjections->getData(),
+ volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount(),
+ conevecgeom->getProjectionCount(),
+ conevecgeom->getDetectorColCount(),
+ conevecgeom->getDetectorRowCount(),
+ conevecgeom->getProjectionVectors(),
+ m_iGPUIndex, m_iDetectorSuperSampling);
+ } else {
+ ASTRA_ASSERT(false);
+ }
+
+}
+
+
+}
+
+#endif
diff --git a/src/CudaProjector2D.cpp b/src/CudaProjector2D.cpp
new file mode 100644
index 0000000..731a3e1
--- /dev/null
+++ b/src/CudaProjector2D.cpp
@@ -0,0 +1,122 @@
+/*
+-----------------------------------------------------------------------
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox")
+
+Copyright: IBBT-Vision Lab, University of Antwerp
+Contact: mailto:wim.vanaarle@ua.ac.be
+Website: http://astra.ua.ac.be
+-----------------------------------------------------------------------
+$Id$
+*/
+#include "astra/CudaProjector2D.h"
+
+
+namespace astra
+{
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CCudaProjector2D::type = "cuda";
+
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CCudaProjector2D::CCudaProjector2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaProjector2D::~CCudaProjector2D()
+{
+ if (m_bIsInitialized) clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Clear for constructors
+void CCudaProjector2D::_clear()
+{
+ m_pProjectionGeometry = NULL;
+ m_pVolumeGeometry = NULL;
+ m_bIsInitialized = false;
+
+ m_projectionKernel = ker2d_default;
+}
+
+//----------------------------------------------------------------------------------------
+// Clear
+void CCudaProjector2D::clear()
+{
+ ASTRA_DELETE(m_pProjectionGeometry);
+ ASTRA_DELETE(m_pVolumeGeometry);
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaProjector2D::_check()
+{
+ // projection geometry
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "CudaProjector2D", "ProjectionGeometry2D not initialized.");
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "CudaProjector2D", "ProjectionGeometry2D not initialized.");
+
+ // volume geometry
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "CudaProjector2D", "VolumeGeometry2D not initialized.");
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "CudaProjector2D", "VolumeGeometry2D not initialized.");
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CCudaProjector2D::initialize(const Config& _cfg)
+{
+ assert(_cfg.self);
+ ConfigStackCheck<CProjector2D> CC("CudaProjector2D", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // TODO: Check the projection geometry is a supported type
+
+ XMLNode* node = _cfg.self->getSingleNode("ProjectionKernel");
+ m_projectionKernel = ker2d_default;
+ if (node) {
+ std::string sProjKernel = node->getContent();
+
+ if (sProjKernel == "default") {
+
+ } else {
+ return false;
+ }
+ }
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionKernel");
+
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+/*
+bool CProjector2D::initialize(astra::CProjectionGeometry2D *, astra::CVolumeGeometry2D *)
+{
+ ASTRA_ASSERT(false);
+
+ return false;
+}
+*/
+
+std::string CCudaProjector2D::description() const
+{
+ return "";
+}
+
+} // end namespace
diff --git a/src/CudaProjector3D.cpp b/src/CudaProjector3D.cpp
new file mode 100644
index 0000000..4687825
--- /dev/null
+++ b/src/CudaProjector3D.cpp
@@ -0,0 +1,153 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/CudaProjector3D.h"
+
+
+namespace astra
+{
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CCudaProjector3D::type = "cuda3d";
+
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CCudaProjector3D::CCudaProjector3D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaProjector3D::~CCudaProjector3D()
+{
+ if (m_bIsInitialized) clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Clear for constructors
+void CCudaProjector3D::_clear()
+{
+ m_pProjectionGeometry = NULL;
+ m_pVolumeGeometry = NULL;
+ m_bIsInitialized = false;
+
+ m_projectionKernel = ker3d_default;
+}
+
+//----------------------------------------------------------------------------------------
+// Clear
+void CCudaProjector3D::clear()
+{
+ ASTRA_DELETE(m_pProjectionGeometry);
+ ASTRA_DELETE(m_pVolumeGeometry);
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaProjector3D::_check()
+{
+ // projection geometry
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "CudaProjector3D", "ProjectionGeometry3D not initialized.");
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "CudaProjector3D", "ProjectionGeometry3D not initialized.");
+
+ // volume geometry
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "CudaProjector3D", "VolumeGeometry3D not initialized.");
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "CudaProjector3D", "VolumeGeometry3D not initialized.");
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CCudaProjector3D::initialize(const Config& _cfg)
+{
+ assert(_cfg.self);
+ ConfigStackCheck<CProjector3D> CC("CudaProjector3D", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector3D::initialize(_cfg)) {
+ return false;
+ }
+
+ // TODO: These should go to the parent.
+
+ // ProjectionGeometry
+ XMLNode* node = _cfg.self->getSingleNode("ProjectionGeometry");
+ // TODO: Implement
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionGeometry");
+
+ // ReconstructionGeometry
+ node = _cfg.self->getSingleNode("VolumeGeometry");
+ // TODO: Implement
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("VolumeGeometry");
+
+ node = _cfg.self->getSingleNode("ProjectionKernel");
+ m_projectionKernel = ker3d_default;
+ if (node) {
+ std::string sProjKernel = node->getContent();
+
+ if (sProjKernel == "default") {
+
+ } else if (sProjKernel == "sum_square_weights") {
+ m_projectionKernel = ker3d_sum_square_weights;
+ } else {
+ return false;
+ }
+ }
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionKernel");
+
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+/*
+bool CProjector3D::initialize(astra::CProjectionGeometry3D *, astra::CVolumeGeometry3D *)
+{
+ ASTRA_ASSERT(false);
+
+ return false;
+}
+*/
+
+std::string CCudaProjector3D::description() const
+{
+ return "";
+}
+
+} // end namespace
diff --git a/src/CudaReconstructionAlgorithm2D.cpp b/src/CudaReconstructionAlgorithm2D.cpp
new file mode 100644
index 0000000..d567158
--- /dev/null
+++ b/src/CudaReconstructionAlgorithm2D.cpp
@@ -0,0 +1,518 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaReconstructionAlgorithm2D.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+#include "astra/FanFlatProjectionGeometry2D.h"
+#include "astra/FanFlatVecProjectionGeometry2D.h"
+#include "astra/CudaProjector2D.h"
+
+#include "../cuda/2d/algo.h"
+
+#include <ctime>
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaReconstructionAlgorithm2D::CCudaReconstructionAlgorithm2D()
+{
+ _clear();
+}
+
+
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaReconstructionAlgorithm2D::~CCudaReconstructionAlgorithm2D()
+{
+ delete m_pAlgo;
+ m_pAlgo = 0;
+ m_bAlgoInit = false;
+}
+
+void CCudaReconstructionAlgorithm2D::clear()
+{
+ delete m_pAlgo;
+ _clear();
+}
+
+void CCudaReconstructionAlgorithm2D::_clear()
+{
+ m_bIsInitialized = false;
+ m_pAlgo = 0;
+ m_bAlgoInit = false;
+ CReconstructionAlgorithm2D::_clear();
+
+ m_iGPUIndex = 0;
+ m_iDetectorSuperSampling = 1;
+ m_iPixelSuperSampling = 1;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaReconstructionAlgorithm2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaReconstructionAlgorithm2D", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // sinogram data
+ XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaSirt2", "No ProjectionDataId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("ReconstructionDataId");
+ ASTRA_CONFIG_CHECK(node, "CudaSirt2", "No ReconstructionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ReconstructionDataId");
+
+ // fixed mask
+ if (_cfg.self->hasOption("ReconstructionMaskId")) {
+ m_bUseReconstructionMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId"));
+ m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("ReconstructionMaskId");
+ // fixed mask
+ if (_cfg.self->hasOption("SinogramMaskId")) {
+ m_bUseSinogramMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId"));
+ m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("SinogramMaskId");
+
+ // Constraints - NEW
+ if (_cfg.self->hasOption("MinConstraint")) {
+ m_bUseMinConstraint = true;
+ m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f);
+ CC.markOptionParsed("MinConstraint");
+ } else {
+ // Constraint - OLD
+ m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false);
+ CC.markOptionParsed("UseMinConstraint");
+ if (m_bUseMinConstraint) {
+ m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f);
+ CC.markOptionParsed("MinConstraintValue");
+ }
+ }
+ if (_cfg.self->hasOption("MaxConstraint")) {
+ m_bUseMaxConstraint = true;
+ m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f);
+ CC.markOptionParsed("MaxConstraint");
+ } else {
+ // Constraint - OLD
+ m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false);
+ CC.markOptionParsed("UseMaxConstraint");
+ if (m_bUseMaxConstraint) {
+ m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f);
+ CC.markOptionParsed("MaxConstraintValue");
+ }
+ }
+
+ // GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUindex");
+ if (!_cfg.self->hasOption("GPUindex"))
+ CC.markOptionParsed("GPUIndex");
+
+ // Detector supersampling factor
+ m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1);
+ CC.markOptionParsed("DetectorSuperSampling");
+
+ // Pixel supersampling factor
+ m_iPixelSuperSampling = (int)_cfg.self->getOptionNumerical("PixelSuperSampling", 1);
+ CC.markOptionParsed("PixelSuperSampling");
+
+
+ // This isn't used yet, but passing it is not something to warn about
+ node = _cfg.self->getSingleNode("ProjectorId");
+ if (node) {
+ id = boost::lexical_cast<int>(node->getContent());
+ CProjector2D *projector = CProjector2DManager::getSingleton().get(id);
+ if (!dynamic_cast<CCudaProjector2D*>(projector)) {
+ cout << "Warning: non-CUDA Projector2D passed to FP_CUDA" << std::endl;
+ }
+ delete node;
+ }
+ CC.markNodeParsed("ProjectorId");
+
+
+ return _check();
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ return initialize(_pProjector, _pSinogram, _pReconstruction, 0, 1);
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex,
+ int _iDetectorSuperSampling,
+ int _iPixelSuperSampling)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ m_pProjector = 0;
+
+ // required classes
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ m_iDetectorSuperSampling = _iDetectorSuperSampling;
+ m_iPixelSuperSampling = _iPixelSuperSampling;
+ m_iGPUIndex = _iGPUindex;
+
+ return _check();
+}
+
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaReconstructionAlgorithm2D::_check()
+{
+ // TODO: CLEAN UP
+
+
+ // check pointers
+ //ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object.");
+ ASTRA_CONFIG_CHECK(m_pSinogram, "SIRT_CUDA", "Invalid Projection Data Object.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction, "SIRT_CUDA", "Invalid Reconstruction Data Object.");
+
+ // check initializations
+ //ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "SIRT_CUDA", "Projection Data Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "SIRT_CUDA", "Reconstruction Data Object Not Initialized.");
+
+ ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "SIRT_CUDA", "DetectorSuperSampling must be a positive integer.");
+ ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 1, "SIRT_CUDA", "PixelSuperSampling must be a positive integer.");
+ ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "SIRT_CUDA", "GPUIndex must be a non-negative integer.");
+
+ // check compatibility between projector and data classes
+// ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "SIRT_CUDA", "Projection Data not compatible with the specified Projector.");
+// ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "SIRT_CUDA", "Reconstruction Data not compatible with the specified Projector.");
+
+ // todo: turn some of these back on
+
+// ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "SIRT_CUDA", "ProjectionGeometry not specified.");
+// ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SIRT_CUDA", "ProjectionGeometry not initialized.");
+// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry, "SIRT_CUDA", "ReconstructionGeometry not specified.");
+// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry->isInitialized(), "SIRT_CUDA", "ReconstructionGeometry not initialized.");
+
+ // check dimensions
+ //ASTRA_CONFIG_CHECK(m_pSinogram->getAngleCount() == m_pProjectionGeometry->getProjectionAngleCount(), "SIRT_CUDA", "Sinogram data object size mismatch.");
+ //ASTRA_CONFIG_CHECK(m_pSinogram->getDetectorCount() == m_pProjectionGeometry->getDetectorCount(), "SIRT_CUDA", "Sinogram data object size mismatch.");
+ //ASTRA_CONFIG_CHECK(m_pReconstruction->getWidth() == m_pReconstructionGeometry->getGridColCount(), "SIRT_CUDA", "Reconstruction data object size mismatch.");
+ //ASTRA_CONFIG_CHECK(m_pReconstruction->getHeight() == m_pReconstructionGeometry->getGridRowCount(), "SIRT_CUDA", "Reconstruction data object size mismatch.");
+
+ // check restrictions
+ // TODO: check restrictions built into cuda code
+
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+void CCudaReconstructionAlgorithm2D::setGPUIndex(int _iGPUIndex)
+{
+ m_iGPUIndex = _iGPUIndex;
+}
+
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaReconstructionAlgorithm2D::getInformation()
+{
+ // TODO: Verify and clean up
+
+ map<string,boost::any> res;
+ res["ProjectionGeometry"] = getInformation("ProjectionGeometry");
+ res["ReconstructionGeometry"] = getInformation("ReconstructionGeometry");
+ res["ProjectionDataId"] = getInformation("ProjectionDataId");
+ res["ReconstructionDataId"] = getInformation("ReconstructionDataId");
+ res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId");
+ res["GPUindex"] = getInformation("GPUindex");
+ res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling");
+ res["PixelSuperSampling"] = getInformation("PixelSuperSampling");
+ res["UseMinConstraint"] = getInformation("UseMinConstraint");
+ res["MinConstraintValue"] = getInformation("MinConstraintValue");
+ res["UseMaxConstraint"] = getInformation("UseMaxConstraint");
+ res["MaxConstraintValue"] = getInformation("MaxConstraintValue");
+ return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res);
+}
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaReconstructionAlgorithm2D::getInformation(std::string _sIdentifier)
+{
+ // TODO: Verify and clean up
+
+ if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); }
+ if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; }
+ if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); }
+ if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; }
+
+ // TODO: store these so we can return them?
+ if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); }
+ if (_sIdentifier == "ReconstructionGeometry") { return string("not implemented"); }
+ if (_sIdentifier == "GPUindex") { return m_iGPUIndex; }
+ if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; }
+ if (_sIdentifier == "PixelSuperSampling") { return m_iPixelSuperSampling; }
+
+ if (_sIdentifier == "ProjectionDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "ReconstructionDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "ReconstructionMaskId") {
+ if (!m_bUseReconstructionMask) return string("not used");
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ return CReconstructionAlgorithm2D::getInformation(_sIdentifier);
+}
+
+bool CCudaReconstructionAlgorithm2D::setupGeometry()
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+ ASTRA_ASSERT(!m_bAlgoInit);
+
+ bool ok;
+
+ // TODO: Probably not the best place for this...
+ ok = m_pAlgo->setGPUIndex(m_iGPUIndex);
+ if (!ok) return false;
+
+ astraCUDA::SDimensions dims;
+
+ const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
+
+ // TODO: off-center geometry, non-square pixels
+ dims.iVolWidth = volgeom.getGridColCount();
+ dims.iVolHeight = volgeom.getGridRowCount();
+ float fPixelSize = volgeom.getPixelLengthX();
+
+ dims.iRaysPerDet = m_iDetectorSuperSampling;
+ dims.iRaysPerPixelDim = m_iPixelSuperSampling;
+
+
+ const CParallelProjectionGeometry2D* parProjGeom = dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry());
+ const CFanFlatProjectionGeometry2D* fanProjGeom = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pSinogram->getGeometry());
+ const CFanFlatVecProjectionGeometry2D* fanVecProjGeom = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pSinogram->getGeometry());
+
+ if (parProjGeom) {
+
+ dims.iProjAngles = parProjGeom->getProjectionAngleCount();
+ dims.iProjDets = parProjGeom->getDetectorCount();
+ dims.fDetScale = parProjGeom->getDetectorWidth() / fPixelSize;
+
+ ok = m_pAlgo->setGeometry(dims, parProjGeom->getProjectionAngles());
+
+ } else if (fanProjGeom) {
+
+ dims.iProjAngles = fanProjGeom->getProjectionAngleCount();
+ dims.iProjDets = fanProjGeom->getDetectorCount();
+ dims.fDetScale = fanProjGeom->getDetectorWidth() / fPixelSize;
+ float fOriginSourceDistance = fanProjGeom->getOriginSourceDistance();
+ float fOriginDetectorDistance = fanProjGeom->getOriginDetectorDistance();
+
+ const float* angles = fanProjGeom->getProjectionAngles();
+
+ astraCUDA::SFanProjection* projs;
+ projs = new astraCUDA::SFanProjection[dims.iProjAngles];
+
+ float fSrcX0 = 0.0f;
+ float fSrcY0 = -fOriginSourceDistance / fPixelSize;
+ float fDetUX0 = dims.fDetScale;
+ float fDetUY0 = 0.0f;
+ float fDetSX0 = dims.iProjDets * fDetUX0 / -2.0f;
+ float fDetSY0 = fOriginDetectorDistance / fPixelSize;
+
+#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = f##name##X0 * cos(alpha) - f##name##Y0 * sin(alpha); projs[i].f##name##Y = f##name##X0 * sin(alpha) + f##name##Y0 * cos(alpha); } while(0)
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i) {
+ ROTATE0(Src, i, angles[i]);
+ ROTATE0(DetS, i, angles[i]);
+ ROTATE0(DetU, i, angles[i]);
+ }
+
+#undef ROTATE0
+
+ ok = m_pAlgo->setFanGeometry(dims, projs);
+ delete[] projs;
+
+ } else if (fanVecProjGeom) {
+
+ dims.iProjAngles = fanVecProjGeom->getProjectionAngleCount();
+ dims.iProjDets = fanVecProjGeom->getDetectorCount();
+ dims.fDetScale = fanVecProjGeom->getDetectorWidth() / fPixelSize;
+
+ const astraCUDA::SFanProjection* projs;
+ projs = fanVecProjGeom->getProjectionVectors();
+
+ // Rescale projs to fPixelSize == 1
+
+ astraCUDA::SFanProjection* scaledProjs = new astraCUDA::SFanProjection[dims.iProjAngles];
+#define SCALE(name,i,alpha) do { scaledProjs[i].f##name##X = projs[i].f##name##X * alpha; scaledProjs[i].f##name##Y = projs[i].f##name##Y * alpha; } while (0)
+ for (unsigned int i = 0; i < dims.iProjAngles; ++i) {
+ SCALE(Src,i,1.0f/fPixelSize);
+ SCALE(DetS,i,1.0f/fPixelSize);
+ SCALE(DetU,i,1.0f/fPixelSize);
+ }
+
+ ok = m_pAlgo->setFanGeometry(dims, scaledProjs);
+
+ delete[] scaledProjs;
+
+ } else {
+
+ ASTRA_ASSERT(false);
+
+ }
+ if (!ok) return false;
+
+
+ if (m_bUseReconstructionMask)
+ ok &= m_pAlgo->enableVolumeMask();
+ if (!ok) return false;
+ if (m_bUseSinogramMask)
+ ok &= m_pAlgo->enableSinogramMask();
+ if (!ok) return false;
+
+ const float *pfTOffsets = m_pSinogram->getGeometry()->getExtraDetectorOffset();
+ if (pfTOffsets)
+ ok &= m_pAlgo->setTOffsets(pfTOffsets);
+ if (!ok) return false;
+
+ ok &= m_pAlgo->init();
+ if (!ok) return false;
+
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaReconstructionAlgorithm2D::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ bool ok = true;
+ const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
+
+ if (!m_bAlgoInit) {
+
+ ok = setupGeometry();
+ ASTRA_ASSERT(ok);
+
+ ok = m_pAlgo->allocateBuffers();
+ ASTRA_ASSERT(ok);
+
+ m_bAlgoInit = true;
+ }
+
+ float fPixelSize = volgeom.getPixelLengthX();
+ float fSinogramScale = 1.0f/(fPixelSize*fPixelSize);
+
+ ok = m_pAlgo->copyDataToGPU(m_pSinogram->getDataConst(), m_pSinogram->getGeometry()->getDetectorCount(), fSinogramScale,
+ m_pReconstruction->getDataConst(), volgeom.getGridColCount(),
+ m_bUseReconstructionMask ? m_pReconstructionMask->getDataConst() : 0, volgeom.getGridColCount(),
+ m_bUseSinogramMask ? m_pSinogramMask->getDataConst() : 0, m_pSinogram->getGeometry()->getDetectorCount());
+
+ ASTRA_ASSERT(ok);
+
+ if (m_bUseMinConstraint)
+ ok &= m_pAlgo->setMinConstraint(m_fMinValue);
+ if (m_bUseMaxConstraint)
+ ok &= m_pAlgo->setMaxConstraint(m_fMaxValue);
+
+ ok &= m_pAlgo->iterate(_iNrIterations);
+ ASTRA_ASSERT(ok);
+
+ ok &= m_pAlgo->getReconstruction(m_pReconstruction->getData(),
+ volgeom.getGridColCount());
+
+ ASTRA_ASSERT(ok);
+}
+
+void CCudaReconstructionAlgorithm2D::signalAbort()
+{
+ if (m_bIsInitialized && m_pAlgo) {
+ m_pAlgo->signalAbort();
+ }
+}
+
+bool CCudaReconstructionAlgorithm2D::getResidualNorm(float32& _fNorm)
+{
+ if (!m_bIsInitialized || !m_pAlgo)
+ return false;
+
+ _fNorm = m_pAlgo->computeDiffNorm();
+
+ return true;
+}
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaRoiSelectAlgorithm.cpp b/src/CudaRoiSelectAlgorithm.cpp
new file mode 100644
index 0000000..f835c59
--- /dev/null
+++ b/src/CudaRoiSelectAlgorithm.cpp
@@ -0,0 +1,149 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaRoiSelectAlgorithm.h"
+
+#include "../cuda/2d/darthelper.h"
+#include "../cuda/2d/algo.h"
+
+#include "astra/AstraObjectManager.h"
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaRoiSelectAlgorithm::type = "RoiSelect_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaRoiSelectAlgorithm::CCudaRoiSelectAlgorithm()
+{
+ m_fRadius = 0.0f;
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaRoiSelectAlgorithm::~CCudaRoiSelectAlgorithm()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaRoiSelectAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg);
+
+ // reconstruction data
+ XMLNode* node = _cfg.self->getSingleNode("DataId");
+ ASTRA_CONFIG_CHECK(node, "CudaRoiSelect", "No DataId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pData = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DataId");
+
+ // Option: GPU number
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex);
+ CC.markOptionParsed("GPUindex");
+ if (!_cfg.self->hasOption("GPUindex"))
+ CC.markOptionParsed("GPUIndex");
+
+ // Option: Radius
+ m_fRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 0.0f);
+ CC.markOptionParsed("Radius");
+
+ _check();
+
+ if (!m_bIsInitialized)
+ return false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn)
+//{
+// return false;
+//}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaRoiSelectAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ const CVolumeGeometry2D& volgeom = *m_pData->getGeometry();
+ unsigned int width = volgeom.getGridColCount();
+ unsigned int height = volgeom.getGridRowCount();
+
+ if (m_fRadius == 0){
+ m_fRadius = (width < height) ? width : height;
+ }
+
+ astraCUDA::setGPUIndex(m_iGPUIndex);
+ astraCUDA::roiSelect(m_pData->getData(), m_fRadius, width, height);
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CCudaRoiSelectAlgorithm::_check()
+{
+
+ // success
+ m_bIsInitialized = true;
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaRoiSelectAlgorithm::getInformation()
+{
+ map<string,boost::any> res;
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+}
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaRoiSelectAlgorithm::getInformation(std::string _sIdentifier)
+{
+ return NULL;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaSartAlgorithm.cpp b/src/CudaSartAlgorithm.cpp
new file mode 100644
index 0000000..610793f
--- /dev/null
+++ b/src/CudaSartAlgorithm.cpp
@@ -0,0 +1,136 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaSartAlgorithm.h"
+
+#include "../cuda/2d/sart.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaSartAlgorithm::type = "SART_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaSartAlgorithm::CCudaSartAlgorithm()
+{
+ m_bIsInitialized = false;
+ CCudaReconstructionAlgorithm2D::_clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaSartAlgorithm::~CCudaSartAlgorithm()
+{
+ // The actual work is done by ~CCudaReconstructionAlgorithm2D
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaSartAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaSartAlgorithm", this, _cfg);
+
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ astraCUDA::SART *sart = new astraCUDA::SART();
+
+ m_pAlgo = sart;
+ m_bAlgoInit = false;
+
+ // projection order
+ int projectionCount = m_pSinogram->getGeometry()->getProjectionAngleCount();
+ int* projectionOrder = NULL;
+ string projOrder = _cfg.self->getOption("ProjectionOrder", "random");
+ CC.markOptionParsed("ProjectionOrder");
+ if (projOrder == "sequential") {
+ projectionOrder = new int[projectionCount];
+ for (int i = 0; i < projectionCount; i++) {
+ projectionOrder[i] = i;
+ }
+ sart->setProjectionOrder(projectionOrder, projectionCount);
+ delete[] projectionOrder;
+ } else if (projOrder == "random") {
+ projectionOrder = new int[projectionCount];
+ for (int i = 0; i < projectionCount; i++) {
+ projectionOrder[i] = i;
+ }
+ for (int i = 0; i < projectionCount-1; i++) {
+ int k = (rand() % (projectionCount - i));
+ int t = projectionOrder[i];
+ projectionOrder[i] = projectionOrder[i + k];
+ projectionOrder[i + k] = t;
+ }
+ sart->setProjectionOrder(projectionOrder, projectionCount);
+ delete[] projectionOrder;
+ } else if (projOrder == "custom") {
+ vector<float32> projOrderList = _cfg.self->getOptionNumericalArray("ProjectionOrderList");
+ projectionOrder = new int[projOrderList.size()];
+ for (int i = 0; i < projOrderList.size(); i++) {
+ projectionOrder[i] = static_cast<int>(projOrderList[i]);
+ }
+ sart->setProjectionOrder(projectionOrder, projectionCount);
+ delete[] projectionOrder;
+ CC.markOptionParsed("ProjectionOrderList");
+ }
+
+
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaSartAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex, int _iDetectorSuperSampling)
+{
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, 1);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ m_pAlgo = new astraCUDA::SART();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaSirtAlgorithm.cpp b/src/CudaSirtAlgorithm.cpp
new file mode 100644
index 0000000..a2a30eb
--- /dev/null
+++ b/src/CudaSirtAlgorithm.cpp
@@ -0,0 +1,154 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifdef ASTRA_CUDA
+
+#include "astra/CudaSirtAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+#include "astra/AstraObjectManager.h"
+
+#include "../cuda/2d/sirt.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaSirtAlgorithm::type = "SIRT_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaSirtAlgorithm::CCudaSirtAlgorithm()
+{
+ m_bIsInitialized = false;
+ CCudaReconstructionAlgorithm2D::_clear();
+
+ m_pMinMask = 0;
+ m_pMaxMask = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaSirtAlgorithm::~CCudaSirtAlgorithm()
+{
+ // The actual work is done by ~CCudaReconstructionAlgorithm2D
+
+ m_pMinMask = 0;
+ m_pMaxMask = 0;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaSirtAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaSirtAlgorithm", this, _cfg);
+
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg);
+
+ if (!m_bIsInitialized)
+ return false;
+
+ // min/max masks
+ if (_cfg.self->hasOption("MinMaskId")) {
+ int id = boost::lexical_cast<int>(_cfg.self->getOption("MinMaskId"));
+ m_pMinMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("MinMaskId");
+ if (_cfg.self->hasOption("MaxMaskId")) {
+ int id = boost::lexical_cast<int>(_cfg.self->getOption("MaxMaskId"));
+ m_pMaxMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("MaxMaskId");
+
+
+ m_pAlgo = new astraCUDA::SIRT();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaSirtAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int _iGPUindex, int _iDetectorSuperSampling,
+ int _iPixelSuperSampling)
+{
+ m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling);
+
+ if (!m_bIsInitialized)
+ return false;
+
+
+
+ m_pAlgo = new astraCUDA::SIRT();
+ m_bAlgoInit = false;
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaSirtAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ if (!m_bAlgoInit) {
+ // We only override the initialisation step to copy the min/max masks
+
+ bool ok = setupGeometry();
+ ASTRA_ASSERT(ok);
+
+ ok = m_pAlgo->allocateBuffers();
+ ASTRA_ASSERT(ok);
+
+ if (m_pMinMask || m_pMaxMask) {
+ const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
+ astraCUDA::SIRT* pSirt = dynamic_cast<astraCUDA::SIRT*>(m_pAlgo);
+ const float *pfMinMaskData = 0;
+ const float *pfMaxMaskData = 0;
+ if (m_pMinMask) pfMinMaskData = m_pMinMask->getDataConst();
+ if (m_pMaxMask) pfMaxMaskData = m_pMaxMask->getDataConst();
+ ok = pSirt->uploadMinMaxMasks(pfMinMaskData, pfMaxMaskData, volgeom.getGridColCount());
+ ASTRA_ASSERT(ok);
+ }
+
+ m_bAlgoInit = true;
+ }
+
+ CCudaReconstructionAlgorithm2D::run(_iNrIterations);
+}
+
+
+} // namespace astra
+
+#endif // ASTRA_CUDA
diff --git a/src/CudaSirtAlgorithm3D.cpp b/src/CudaSirtAlgorithm3D.cpp
new file mode 100644
index 0000000..f23d0f6
--- /dev/null
+++ b/src/CudaSirtAlgorithm3D.cpp
@@ -0,0 +1,306 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/CudaSirtAlgorithm3D.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+#include "astra/ConeProjectionGeometry3D.h"
+#include "astra/ParallelProjectionGeometry3D.h"
+#include "astra/ParallelVecProjectionGeometry3D.h"
+#include "astra/ConeVecProjectionGeometry3D.h"
+
+#include "../cuda/3d/astra3d.h"
+
+using namespace std;
+
+namespace astra {
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CCudaSirtAlgorithm3D::type = "SIRT3D_CUDA";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CCudaSirtAlgorithm3D::CCudaSirtAlgorithm3D()
+{
+ m_bIsInitialized = false;
+ m_pSirt = 0;
+ m_iGPUIndex = 0;
+ m_iVoxelSuperSampling = 1;
+ m_iDetectorSuperSampling = 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor with initialization
+CCudaSirtAlgorithm3D::CCudaSirtAlgorithm3D(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pProjectionData,
+ CFloat32VolumeData3DMemory* _pReconstruction)
+{
+ _clear();
+ initialize(_pProjector, _pProjectionData, _pReconstruction);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CCudaSirtAlgorithm3D::~CCudaSirtAlgorithm3D()
+{
+ delete m_pSirt;
+ m_pSirt = 0;
+
+ CReconstructionAlgorithm3D::_clear();
+}
+
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CCudaSirtAlgorithm3D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "SIRT3D", "Error in ReconstructionAlgorithm3D initialization");
+
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CCudaSirtAlgorithm3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("CudaSirtAlgorithm3D", this, _cfg);
+
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm3D::initialize(_cfg)) {
+ return false;
+ }
+
+ m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0);
+ CC.markOptionParsed("GPUindex");
+ m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1);
+ CC.markOptionParsed("DetectorSuperSampling");
+ m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1);
+ CC.markOptionParsed("VoxelSuperSampling");
+
+ m_pSirt = new AstraSIRT3d();
+
+ m_bAstraSIRTInit = false;
+
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CCudaSirtAlgorithm3D::initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3DMemory* _pSinogram,
+ CFloat32VolumeData3DMemory* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ m_pSirt = new AstraSIRT3d;
+
+ m_bAstraSIRTInit = false;
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CCudaSirtAlgorithm3D::getInformation()
+{
+ map<string, boost::any> res;
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CCudaSirtAlgorithm3D::getInformation(std::string _sIdentifier)
+{
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CCudaSirtAlgorithm3D::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry();
+ const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom);
+ const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom);
+ const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom);
+ const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom);
+ const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry();
+
+ bool ok = true;
+
+ if (!m_bAstraSIRTInit) {
+
+ ok &= m_pSirt->setGPUIndex(m_iGPUIndex);
+
+ ok &= m_pSirt->setReconstructionGeometry(volgeom.getGridColCount(),
+ volgeom.getGridRowCount(),
+ volgeom.getGridSliceCount());
+ fprintf(stderr, "01: %d\n", ok);
+
+ if (conegeom) {
+ ok &= m_pSirt->setConeGeometry(conegeom->getProjectionCount(),
+ conegeom->getDetectorColCount(),
+ conegeom->getDetectorRowCount(),
+ conegeom->getOriginSourceDistance(),
+ conegeom->getOriginDetectorDistance(),
+ conegeom->getDetectorSpacingX(),
+ conegeom->getDetectorSpacingY(),
+ conegeom->getProjectionAngles());
+ } else if (par3dgeom) {
+ ok &= m_pSirt->setPar3DGeometry(par3dgeom->getProjectionCount(),
+ par3dgeom->getDetectorColCount(),
+ par3dgeom->getDetectorRowCount(),
+ par3dgeom->getDetectorSpacingX(),
+ par3dgeom->getDetectorSpacingY(),
+ par3dgeom->getProjectionAngles());
+ } else if (parvec3dgeom) {
+ ok &= m_pSirt->setPar3DGeometry(parvec3dgeom->getProjectionCount(),
+ parvec3dgeom->getDetectorColCount(),
+ parvec3dgeom->getDetectorRowCount(),
+ parvec3dgeom->getProjectionVectors());
+ } else if (conevec3dgeom) {
+ ok &= m_pSirt->setConeGeometry(conevec3dgeom->getProjectionCount(),
+ conevec3dgeom->getDetectorColCount(),
+ conevec3dgeom->getDetectorRowCount(),
+ conevec3dgeom->getProjectionVectors());
+ } else {
+ ASTRA_ASSERT(false);
+ }
+ fprintf(stderr, "02: %d\n", ok);
+
+ ok &= m_pSirt->enableSuperSampling(m_iVoxelSuperSampling, m_iDetectorSuperSampling);
+
+ if (m_bUseReconstructionMask)
+ ok &= m_pSirt->enableVolumeMask();
+ if (m_bUseSinogramMask)
+ ok &= m_pSirt->enableSinogramMask();
+
+ ASTRA_ASSERT(ok);
+ fprintf(stderr, "03: %d\n", ok);
+
+ ok &= m_pSirt->init();
+ fprintf(stderr, "04: %d\n", ok);
+
+ ASTRA_ASSERT(ok);
+
+ m_bAstraSIRTInit = true;
+
+ }
+
+ CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram);
+ ASTRA_ASSERT(pSinoMem);
+
+ ok = m_pSirt->setSinogram(pSinoMem->getDataConst(), m_pSinogram->getGeometry()->getDetectorColCount());
+
+ fprintf(stderr, "1: %d\n", ok);
+ ASTRA_ASSERT(ok);
+
+ if (m_bUseReconstructionMask) {
+ CFloat32VolumeData3DMemory* pRMaskMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstructionMask);
+ ASTRA_ASSERT(pRMaskMem);
+ ok &= m_pSirt->setVolumeMask(pRMaskMem->getDataConst(), volgeom.getGridColCount());
+ }
+ if (m_bUseSinogramMask) {
+ CFloat32ProjectionData3DMemory* pSMaskMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogramMask);
+ ASTRA_ASSERT(pSMaskMem);
+ ok &= m_pSirt->setSinogramMask(pSMaskMem->getDataConst(), m_pSinogramMask->getGeometry()->getDetectorColCount());
+ }
+ fprintf(stderr, "2: %d\n", ok);
+
+ CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction);
+ ASTRA_ASSERT(pReconMem);
+ ok &= m_pSirt->setStartReconstruction(pReconMem->getDataConst(),
+ volgeom.getGridColCount());
+
+ ASTRA_ASSERT(ok);
+ fprintf(stderr, "3: %d\n", ok);
+
+ if (m_bUseMinConstraint)
+ ok &= m_pSirt->setMinConstraint(m_fMinValue);
+ if (m_bUseMaxConstraint)
+ ok &= m_pSirt->setMaxConstraint(m_fMaxValue);
+ fprintf(stderr, "4: %d\n", ok);
+
+ ok &= m_pSirt->iterate(_iNrIterations);
+ ASTRA_ASSERT(ok);
+ fprintf(stderr, "5: %d\n", ok);
+
+ ok &= m_pSirt->getReconstruction(pReconMem->getData(),
+ volgeom.getGridColCount());
+ fprintf(stderr, "6: %d\n", ok);
+ ASTRA_ASSERT(ok);
+
+
+}
+//----------------------------------------------------------------------------------------
+void CCudaSirtAlgorithm3D::signalAbort()
+{
+ if (m_bIsInitialized && m_pSirt) {
+ m_pSirt->signalAbort();
+ }
+}
+
+bool CCudaSirtAlgorithm3D::getResidualNorm(float32& _fNorm)
+{
+ if (!m_bIsInitialized || !m_pSirt)
+ return false;
+
+ _fNorm = m_pSirt->computeDiffNorm();
+
+ return true;
+}
+
+
+} // namespace astra
diff --git a/src/DataProjector.cpp b/src/DataProjector.cpp
new file mode 100644
index 0000000..d4b2f84
--- /dev/null
+++ b/src/DataProjector.cpp
@@ -0,0 +1,36 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/DataProjector.h"
+
+namespace astra {
+
+ // EMPTY
+
+
+} // end namespace astra
diff --git a/src/DataProjectorPolicies.cpp b/src/DataProjectorPolicies.cpp
new file mode 100644
index 0000000..2535706
--- /dev/null
+++ b/src/DataProjectorPolicies.cpp
@@ -0,0 +1,36 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/DataProjectorPolicies.h"
+
+namespace astra {
+
+ // EMPTY
+
+
+} // end namespace astra
diff --git a/src/FanFlatBeamLineKernelProjector2D.cpp b/src/FanFlatBeamLineKernelProjector2D.cpp
new file mode 100644
index 0000000..0891801
--- /dev/null
+++ b/src/FanFlatBeamLineKernelProjector2D.cpp
@@ -0,0 +1,179 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/FanFlatBeamLineKernelProjector2D.h"
+
+#include <cmath>
+#include <cstring>
+#include <boost/lexical_cast.hpp>
+
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+using namespace astra;
+
+#include "astra/FanFlatBeamLineKernelProjector2D.inl"
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CFanFlatBeamLineKernelProjector2D::type = "line_fanflat";
+
+
+//----------------------------------------------------------------------------------------
+// default constructor
+CFanFlatBeamLineKernelProjector2D::CFanFlatBeamLineKernelProjector2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// constructor
+CFanFlatBeamLineKernelProjector2D::CFanFlatBeamLineKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry)
+
+{
+ _clear();
+ initialize(_pProjectionGeometry, _pReconstructionGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// destructor
+CFanFlatBeamLineKernelProjector2D::~CFanFlatBeamLineKernelProjector2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CFanFlatBeamLineKernelProjector2D::_clear()
+{
+ CProjector2D::_clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CFanFlatBeamLineKernelProjector2D::clear()
+{
+ CProjector2D::clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CFanFlatBeamLineKernelProjector2D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CProjector2D::_check(), "FanFlatBeamLineKernelProjector2D", "Error in Projector2D initialization");
+
+ ASTRA_CONFIG_CHECK(dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry) || dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry), "FanFlatBeamLineKernelProjector2D", "Unsupported projection geometry");
+
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "FanFlatBeamLineKernelProjector2D", "Pixel height must equal pixel width.");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CFanFlatBeamLineKernelProjector2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize
+bool CFanFlatBeamLineKernelProjector2D::initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // hardcopy geometries
+ m_pProjectionGeometry = _pProjectionGeometry->clone();
+ m_pVolumeGeometry = _pVolumeGeometry->clone();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Get maximum amount of weights on a single ray
+int CFanFlatBeamLineKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex)
+{
+ int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount());
+ return maxDim * 2 + 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Single Ray Weights
+void CFanFlatBeamLineKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+ StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount);
+ projectSingleRay(_iProjectionIndex, _iDetectorIndex, p);
+ _iStoredPixelCount = p.getStoredPixelCount();
+}
+
+//----------------------------------------------------------------------------------------
+// Splat a single point
+std::vector<SDetector2D> CFanFlatBeamLineKernelProjector2D::projectPoint(int _iRow, int _iCol)
+{
+ std::vector<SDetector2D> res;
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+//Result is always in [-PI/2; PI/2]
+float32 CFanFlatBeamLineKernelProjector2D::angleBetweenVectors(float32 _fAX, float32 _fAY, float32 _fBX, float32 _fBY)
+{
+ float32 sinAB = (_fAX*_fBY - _fAY*_fBX)/sqrt((_fAX*_fAX + _fAY*_fAY)*(_fBX*_fBX + _fBY*_fBY));
+ return asin(sinAB);
+}
+
+//----------------------------------------------------------------------------------------
diff --git a/src/FanFlatBeamStripKernelProjector2D.cpp b/src/FanFlatBeamStripKernelProjector2D.cpp
new file mode 100644
index 0000000..87ae8d6
--- /dev/null
+++ b/src/FanFlatBeamStripKernelProjector2D.cpp
@@ -0,0 +1,223 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/FanFlatBeamStripKernelProjector2D.h"
+
+#include <cmath>
+#include <boost/lexical_cast.hpp>
+
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+using namespace astra;
+
+#include "astra/FanFlatBeamStripKernelProjector2D.inl"
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CFanFlatBeamStripKernelProjector2D::type = "strip_fanflat";
+
+//----------------------------------------------------------------------------------------
+// default constructor
+CFanFlatBeamStripKernelProjector2D::CFanFlatBeamStripKernelProjector2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// constructor
+CFanFlatBeamStripKernelProjector2D::CFanFlatBeamStripKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry)
+
+{
+ _clear();
+ initialize(_pProjectionGeometry, _pReconstructionGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// destructor
+CFanFlatBeamStripKernelProjector2D::~CFanFlatBeamStripKernelProjector2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CFanFlatBeamStripKernelProjector2D::_clear()
+{
+ CProjector2D::_clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CFanFlatBeamStripKernelProjector2D::clear()
+{
+ CProjector2D::clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CFanFlatBeamStripKernelProjector2D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CProjector2D::_check(), "FanFlatBeamStripKernelProjector2D", "Error in Projector2D initialization");
+
+ ASTRA_CONFIG_CHECK(dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry), "FanFlatBeamLineKernelProjector2D", "Unsupported projection geometry");
+
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "FanFlatBeamStripKernelProjector2D", "Pixel height must equal pixel width.");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CFanFlatBeamStripKernelProjector2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize
+bool CFanFlatBeamStripKernelProjector2D::initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // hardcopy geometries
+ m_pProjectionGeometry = _pProjectionGeometry->clone();
+ m_pVolumeGeometry = _pVolumeGeometry->clone();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Get maximum amount of weights on a single ray
+int CFanFlatBeamStripKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex)
+{
+ int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount());
+ return maxDim * 10 + 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Single Ray Weights
+void CFanFlatBeamStripKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+ StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount);
+ projectSingleRay(_iProjectionIndex, _iDetectorIndex, p);
+ _iStoredPixelCount = p.getStoredPixelCount();
+}
+
+//----------------------------------------------------------------------------------------
+// Splat a single point
+std::vector<SDetector2D> CFanFlatBeamStripKernelProjector2D::projectPoint(int _iRow, int _iCol)
+{
+ //float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ //float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ //float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ //float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ //float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ //float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ //float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ //float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+
+ std::vector<SDetector2D> res;
+ //// loop projectors and detectors
+ //for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) {
+
+ // // get projection angle
+ // float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection);
+ // if (theta >= 7*PIdiv4) theta -= 2*PI;
+ // bool inverse = false;
+ // if (theta >= 3*PIdiv4) {
+ // theta -= PI;
+ // inverse = true;
+ // }
+
+ // // calculate distance from the center of the voxel to the ray though the origin
+ // float32 tUL = xUL * cos(theta) + yUL * sin(theta);
+ // float32 tUR = xUR * cos(theta) + yUR * sin(theta);
+ // float32 tLL = xLL * cos(theta) + yLL * sin(theta);
+ // float32 tLR = xLR * cos(theta) + yLR * sin(theta);
+ // if (inverse) {
+ // tUL *= -1.0f;
+ // tUR *= -1.0f;
+ // tLL *= -1.0f;
+ // tLR *= -1.0f;
+ // }
+ // float32 tMin = min(tUL, min(tUR, min(tLL,tLR)));
+ // float32 tMax = max(tUL, max(tUR, max(tLL,tLR)));
+
+ // // calculate the offset on the detectorarray (in indices)
+ // int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin));
+ // int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax));
+
+ // // add affected detectors to the list
+ // for (int i = dmin; i <= dmax; ++i) {
+ // if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) {
+ // SDetector2D det;
+ // det.m_iAngleIndex = iProjection;
+ // det.m_iDetectorIndex = i;
+ // det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i;
+ // res.push_back(det);
+ // }
+ // }
+ //}
+
+ //// return result vector
+ return res;
+
+}
+
+//----------------------------------------------------------------------------------------
diff --git a/src/FanFlatProjectionGeometry2D.cpp b/src/FanFlatProjectionGeometry2D.cpp
new file mode 100644
index 0000000..b74536a
--- /dev/null
+++ b/src/FanFlatProjectionGeometry2D.cpp
@@ -0,0 +1,209 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/FanFlatProjectionGeometry2D.h"
+
+#include <cstring>
+#include <sstream>
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor. Sets all variables to zero.
+CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D()
+{
+ _clear();
+ m_fOriginSourceDistance = 0.0f;
+ m_fOriginDetectorDistance = 0.0f;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ float32 _fOriginSourceDistance,
+ float32 _fOriginDetectorDistance)
+{
+ this->initialize(_iProjectionAngleCount,
+ _iDetectorCount,
+ _fDetectorWidth,
+ _pfProjectionAngles,
+ _fOriginSourceDistance,
+ _fOriginDetectorDistance);
+}
+
+//----------------------------------------------------------------------------------------
+// Copy Constructor
+CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D(const CFanFlatProjectionGeometry2D& _projGeom)
+{
+ _clear();
+ this->initialize(_projGeom.m_iProjectionAngleCount,
+ _projGeom.m_iDetectorCount,
+ _projGeom.m_fDetectorWidth,
+ _projGeom.m_pfProjectionAngles,
+ _projGeom.m_fOriginSourceDistance,
+ _projGeom.m_fOriginDetectorDistance);
+}
+
+//----------------------------------------------------------------------------------------
+// Assignment operator.
+CFanFlatProjectionGeometry2D& CFanFlatProjectionGeometry2D::operator=(const CFanFlatProjectionGeometry2D& _other)
+{
+ if (m_bInitialized)
+ delete[] m_pfProjectionAngles;
+ m_bInitialized = _other.m_bInitialized;
+ if (m_bInitialized) {
+ m_iProjectionAngleCount = _other.m_iProjectionAngleCount;
+ m_iDetectorCount = _other.m_iDetectorCount;
+ m_fDetectorWidth = _other.m_fDetectorWidth;
+ m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ memcpy(m_pfProjectionAngles, _other.m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount);
+ m_fOriginSourceDistance = _other.m_fOriginSourceDistance;
+ m_fOriginDetectorDistance = _other.m_fOriginDetectorDistance;
+ }
+ return *this;
+}
+//----------------------------------------------------------------------------------------
+// Destructor.
+CFanFlatProjectionGeometry2D::~CFanFlatProjectionGeometry2D()
+{
+
+}
+
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CFanFlatProjectionGeometry2D::initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ float32 _fOriginSourceDistance,
+ float32 _fOriginDetectorDistance)
+{
+ m_fOriginSourceDistance = _fOriginSourceDistance;
+ m_fOriginDetectorDistance = _fOriginDetectorDistance;
+ _initialize(_iProjectionAngleCount,
+ _iDetectorCount,
+ _fDetectorWidth,
+ _pfProjectionAngles);
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization with a Config object
+bool CFanFlatProjectionGeometry2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry2D> CC("FanFlatProjectionGeometry2D", this, _cfg);
+
+ // initialization of parent class
+ CProjectionGeometry2D::initialize(_cfg);
+
+ // Required: DistanceOriginDetector
+ XMLNode* node = _cfg.self->getSingleNode("DistanceOriginDetector");
+ ASTRA_CONFIG_CHECK(node, "FanFlatProjectionGeometry2D", "No DistanceOriginDetector tag specified.");
+ m_fOriginDetectorDistance = boost::lexical_cast<float32>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DistanceOriginDetector");
+
+ // Required: DetectorOriginSource
+ node = _cfg.self->getSingleNode("DistanceOriginSource");
+ ASTRA_CONFIG_CHECK(node, "FanFlatProjectionGeometry2D", "No DistanceOriginSource tag specified.");
+ m_fOriginSourceDistance = boost::lexical_cast<float32>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DistanceOriginSource");
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CProjectionGeometry2D* CFanFlatProjectionGeometry2D::clone()
+{
+ return new CFanFlatProjectionGeometry2D(*this);
+}
+
+//----------------------------------------------------------------------------------------
+// is equal
+bool CFanFlatProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // try to cast argument to CFanFlatProjectionGeometry2D
+ CFanFlatProjectionGeometry2D* pGeom2 = dynamic_cast<CFanFlatProjectionGeometry2D*>(_pGeom2);
+ if (pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false;
+ if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false;
+ if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false;
+ if (m_fOriginSourceDistance != pGeom2->m_fOriginSourceDistance) return false;
+ if (m_fOriginDetectorDistance != pGeom2->m_fOriginDetectorDistance) return false;
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Is of type
+bool CFanFlatProjectionGeometry2D::isOfType(const std::string& _sType)
+{
+ return (_sType == "fanflat");
+}
+
+CVector3D CFanFlatProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */)
+{
+ CVector3D vOutput(0.0f, 0.0f, 0.0f);
+
+ // not implemented
+ ASTRA_ASSERT(false);
+
+ return vOutput;
+}
+
+//----------------------------------------------------------------------------------------
+
+
+} // namespace astra
diff --git a/src/FanFlatVecProjectionGeometry2D.cpp b/src/FanFlatVecProjectionGeometry2D.cpp
new file mode 100644
index 0000000..e42a4f1
--- /dev/null
+++ b/src/FanFlatVecProjectionGeometry2D.cpp
@@ -0,0 +1,232 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/FanFlatVecProjectionGeometry2D.h"
+
+#include <cstring>
+#include <sstream>
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor. Sets all variables to zero.
+CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D()
+{
+ _clear();
+ m_pProjectionAngles = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ const SFanProjection* _pProjectionAngles)
+{
+ this->initialize(_iProjectionAngleCount,
+ _iDetectorCount,
+ _pProjectionAngles);
+}
+
+//----------------------------------------------------------------------------------------
+// Copy Constructor
+CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D(const CFanFlatVecProjectionGeometry2D& _projGeom)
+{
+ _clear();
+ this->initialize(_projGeom.m_iProjectionAngleCount,
+ _projGeom.m_iDetectorCount,
+ _projGeom.m_pProjectionAngles);
+}
+
+//----------------------------------------------------------------------------------------
+// Assignment operator.
+CFanFlatVecProjectionGeometry2D& CFanFlatVecProjectionGeometry2D::operator=(const CFanFlatVecProjectionGeometry2D& _other)
+{
+ if (m_bInitialized)
+ delete[] m_pProjectionAngles;
+ m_bInitialized = _other.m_bInitialized;
+ if (m_bInitialized) {
+ m_iProjectionAngleCount = _other.m_iProjectionAngleCount;
+ m_iDetectorCount = _other.m_iDetectorCount;
+ m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount];
+ memcpy(m_pProjectionAngles, _other.m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount);
+ }
+ return *this;
+}
+//----------------------------------------------------------------------------------------
+// Destructor.
+CFanFlatVecProjectionGeometry2D::~CFanFlatVecProjectionGeometry2D()
+{
+ // TODO
+ delete[] m_pProjectionAngles;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CFanFlatVecProjectionGeometry2D::initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ const SFanProjection* _pProjectionAngles)
+{
+ m_iProjectionAngleCount = _iProjectionAngleCount;
+ m_iDetectorCount = _iDetectorCount;
+ m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount];
+ for (int i = 0; i < m_iProjectionAngleCount; ++i)
+ m_pProjectionAngles[i] = _pProjectionAngles[i];
+
+ // TODO: check?
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization with a Config object
+bool CFanFlatVecProjectionGeometry2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry2D> CC("FanFlatVecProjectionGeometry2D", this, _cfg);
+
+ XMLNode* node;
+
+ // TODO: Fix up class hierarchy... this class doesn't fit very well.
+ // initialization of parent class
+ //CProjectionGeometry2D::initialize(_cfg);
+
+ // Required: DetectorCount
+ node = _cfg.self->getSingleNode("DetectorCount");
+ ASTRA_CONFIG_CHECK(node, "FanFlatVecProjectionGeometry3D", "No DetectorRowCount tag specified.");
+ m_iDetectorCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorCount");
+
+ // Required: Vectors
+ node = _cfg.self->getSingleNode("Vectors");
+ ASTRA_CONFIG_CHECK(node, "FanFlatVecProjectionGeometry3D", "No Vectors tag specified.");
+ vector<float32> data = node->getContentNumericalArray();
+ CC.markNodeParsed("Vectors");
+ ASTRA_DELETE(node);
+ ASTRA_CONFIG_CHECK(data.size() % 6 == 0, "FanFlatVecProjectionGeometry3D", "Vectors doesn't consist of 6-tuples.");
+ m_iProjectionAngleCount = data.size() / 6;
+ m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount];
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ SFanProjection& p = m_pProjectionAngles[i];
+ p.fSrcX = data[6*i + 0];
+ p.fSrcY = data[6*i + 1];
+ p.fDetUX = data[6*i + 4];
+ p.fDetUY = data[6*i + 5];
+
+ // The backend code currently expects the corner of the detector, while
+ // the matlab interface supplies the center
+ p.fDetSX = data[6*i + 2] - 0.5f * m_iDetectorCount * p.fDetUX;
+ p.fDetSY = data[6*i + 3] - 0.5f * m_iDetectorCount * p.fDetUY;
+ }
+
+
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CProjectionGeometry2D* CFanFlatVecProjectionGeometry2D::clone()
+{
+ return new CFanFlatVecProjectionGeometry2D(*this);
+}
+
+//----------------------------------------------------------------------------------------
+// is equal
+bool CFanFlatVecProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // try to cast argument to CFanFlatVecProjectionGeometry2D
+ CFanFlatVecProjectionGeometry2D* pGeom2 = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(_pGeom2);
+ if (pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false;
+ if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false;
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Is of type
+bool CFanFlatVecProjectionGeometry2D::isOfType(const std::string& _sType)
+{
+ return (_sType == "fanflat_vec");
+}
+
+//----------------------------------------------------------------------------------------
+
+CVector3D CFanFlatVecProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */)
+{
+ CVector3D vOutput(0.0f, 0.0f, 0.0f);
+
+ // not implemented
+ ASTRA_ASSERT(false);
+
+ return vOutput;
+}
+
+//----------------------------------------------------------------------------------------
+
+void CFanFlatVecProjectionGeometry2D::getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const
+{
+ // not implemented
+ ASTRA_ASSERT(false);
+}
+
+//----------------------------------------------------------------------------------------
+
+bool CFanFlatVecProjectionGeometry2D::_check()
+{
+ // TODO
+ return true;
+}
+
+
+//----------------------------------------------------------------------------------------
+
+
+} // namespace astra
diff --git a/src/FilteredBackProjectionAlgorithm.cpp b/src/FilteredBackProjectionAlgorithm.cpp
new file mode 100644
index 0000000..8063f7b
--- /dev/null
+++ b/src/FilteredBackProjectionAlgorithm.cpp
@@ -0,0 +1,336 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/FilteredBackProjectionAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include <iostream>
+#include <iomanip>
+#include <math.h>
+
+#include "astra/AstraObjectManager.h"
+#include "astra/ParallelBeamLineKernelProjector2D.h"
+#include "astra/Fourier.h"
+#include "astra/DataProjector.h"
+
+using namespace std;
+
+namespace astra {
+
+#include "astra/Projector2DImpl.inl"
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CFilteredBackProjectionAlgorithm::type = "FBP";
+const int FFT = 1;
+const int IFFT = -1;
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CFilteredBackProjectionAlgorithm::CFilteredBackProjectionAlgorithm()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CFilteredBackProjectionAlgorithm::~CFilteredBackProjectionAlgorithm()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CFilteredBackProjectionAlgorithm::_clear()
+{
+ m_pProjector = NULL;
+ m_pSinogram = NULL;
+ m_pReconstruction = NULL;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CFilteredBackProjectionAlgorithm::clear()
+{
+ m_pProjector = NULL;
+ m_pSinogram = NULL;
+ m_pReconstruction = NULL;
+ m_bIsInitialized = false;
+}
+
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // projector
+ XMLNode* node = _cfg.self->getSingleNode("ProjectorId");
+ ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ProjectorId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pProjector = CProjector2DManager::getSingleton().get(id);
+ ASTRA_DELETE(node);
+
+ // sinogram data
+ node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ProjectionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+
+ // volume data
+ node = _cfg.self->getSingleNode("ReconstructionDataId");
+ ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ReconstructionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+
+ node = _cfg.self->getSingleNode("ProjectionIndex");
+ if (node)
+ {
+ vector<float32> projectionIndex = node->getContentNumericalArray();
+
+ int angleCount = projectionIndex.size();
+ int detectorCount = m_pProjector->getProjectionGeometry()->getDetectorCount();
+
+ float32 * sinogramData2D = new float32[angleCount* detectorCount];
+ float32 ** sinogramData = new float32*[angleCount];
+ for (int i = 0; i < angleCount; i++)
+ {
+ sinogramData[i] = &(sinogramData2D[i * detectorCount]);
+ }
+
+ float32 * projectionAngles = new float32[angleCount];
+ float32 detectorWidth = m_pProjector->getProjectionGeometry()->getDetectorWidth();
+
+ for (int i = 0; i < angleCount; i ++) {
+ if (projectionIndex[i] > m_pProjector->getProjectionGeometry()->getProjectionAngleCount() -1 )
+ {
+ cout << "Invalid Projection Index" << endl;
+ return false;
+ } else {
+ int orgIndex = (int)projectionIndex[i];
+
+ for (int iDetector=0; iDetector < detectorCount; iDetector++)
+ {
+ sinogramData2D[i*detectorCount+ iDetector] = m_pSinogram->getData2D()[orgIndex][iDetector];
+ }
+// sinogramData[i] = m_pSinogram->getSingleProjectionData(projectionIndex[i]);
+ projectionAngles[i] = m_pProjector->getProjectionGeometry()->getProjectionAngle((int)projectionIndex[i] );
+
+ }
+ }
+
+ CParallelProjectionGeometry2D * pg = new CParallelProjectionGeometry2D(angleCount, detectorCount,detectorWidth,projectionAngles);
+ m_pProjector = new CParallelBeamLineKernelProjector2D(pg,m_pReconstruction->getGeometry());
+ m_pSinogram = new CFloat32ProjectionData2D(pg, sinogramData2D);
+ }
+ ASTRA_DELETE(node);
+
+ // TODO: check that the angles are linearly spaced between 0 and pi
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Get Information - all
+map<string,boost::any> CFilteredBackProjectionAlgorithm::getInformation()
+{
+ map<string, boost::any> result;
+ result["ProjectorId"] = getInformation("ProjectorId");
+ result["ProjectionDataId"] = getInformation("ProjectionDataId");
+ result["VolumeDataId"] = getInformation("VolumeDataId");
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), result);
+};
+
+//---------------------------------------------------------------------------------------
+// Get Information - specific
+boost::any CFilteredBackProjectionAlgorithm::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "ProjectorId") {
+ int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ } else if (_sIdentifier == "ProjectionDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ } else if (_sIdentifier == "VolumeDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Initialize
+bool CFilteredBackProjectionAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32VolumeData2D* _pVolume,
+ CFloat32ProjectionData2D* _pSinogram)
+{
+ // store classes
+ m_pProjector = _pProjector;
+ m_pReconstruction = _pVolume;
+ m_pSinogram = _pSinogram;
+
+
+ // TODO: check that the angles are linearly spaced between 0 and pi
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CFilteredBackProjectionAlgorithm::_check()
+{
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "FBP", "Error in ReconstructionAlgorithm2D initialization");
+
+ // success
+ return true;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CFilteredBackProjectionAlgorithm::run(int _iNrIterations)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ // Filter sinogram
+ CFloat32ProjectionData2D filteredSinogram(m_pSinogram->getGeometry(), m_pSinogram->getData());
+ performFiltering(&filteredSinogram);
+
+ // Back project
+ m_pReconstruction->setData(0.0f);
+ projectData(m_pProjector,
+ DefaultBPPolicy(m_pReconstruction, &filteredSinogram));
+
+ // Scale data
+ int iAngleCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount();
+ (*m_pReconstruction) *= (PI/2)/iAngleCount;
+
+ m_pReconstruction->updateStatistics();
+}
+
+
+//----------------------------------------------------------------------------------------
+void CFilteredBackProjectionAlgorithm::performFiltering(CFloat32ProjectionData2D * _pFilteredSinogram)
+{
+ ASTRA_ASSERT(_pFilteredSinogram != NULL);
+ ASTRA_ASSERT(_pFilteredSinogram->getAngleCount() == m_pSinogram->getAngleCount());
+ ASTRA_ASSERT(_pFilteredSinogram->getDetectorCount() == m_pSinogram->getDetectorCount());
+
+
+ int iAngleCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount();
+ int iDetectorCount = m_pProjector->getProjectionGeometry()->getDetectorCount();
+
+
+ // We'll zero-pad to the smallest power of two at least 64 and
+ // at least 2*iDetectorCount
+ int zpDetector = 64;
+ int nextPow2 = 5;
+ while (zpDetector < iDetectorCount*2) {
+ zpDetector *= 2;
+ nextPow2++;
+ }
+
+ // Create filter
+ float32* filter = new float32[zpDetector];
+
+ for (int iDetector = 0; iDetector <= zpDetector/2; iDetector++)
+ filter[iDetector] = (2.0f * iDetector)/zpDetector;
+
+ for (int iDetector = zpDetector/2+1; iDetector < zpDetector; iDetector++)
+ filter[iDetector] = (2.0f * (zpDetector - iDetector)) / zpDetector;
+
+
+ float32* pfRe = new float32[iAngleCount * zpDetector];
+ float32* pfIm = new float32[iAngleCount * zpDetector];
+
+ // Copy and zero-pad data
+ for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
+ float32* pfReRow = pfRe + iAngle * zpDetector;
+ float32* pfImRow = pfIm + iAngle * zpDetector;
+ float32* pfDataRow = _pFilteredSinogram->getData() + iAngle * iDetectorCount;
+ for (int iDetector = 0; iDetector < iDetectorCount; ++iDetector) {
+ pfReRow[iDetector] = pfDataRow[iDetector];
+ pfImRow[iDetector] = 0.0f;
+ }
+ for (int iDetector = iDetectorCount; iDetector < zpDetector; ++iDetector) {
+ pfReRow[iDetector] = 0.0f;
+ pfImRow[iDetector] = 0.0f;
+ }
+ }
+
+ // in-place FFT
+ for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
+ float32* pfReRow = pfRe + iAngle * zpDetector;
+ float32* pfImRow = pfIm + iAngle * zpDetector;
+
+ fastTwoPowerFourierTransform1D(zpDetector, pfReRow, pfImRow, pfReRow, pfImRow, 1, 1, false);
+ }
+
+ // Filter
+ for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
+ float32* pfReRow = pfRe + iAngle * zpDetector;
+ float32* pfImRow = pfIm + iAngle * zpDetector;
+ for (int iDetector = 0; iDetector < zpDetector; ++iDetector) {
+ pfReRow[iDetector] *= filter[iDetector];
+ pfImRow[iDetector] *= filter[iDetector];
+ }
+ }
+
+ // in-place inverse FFT
+ for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
+ float32* pfReRow = pfRe + iAngle * zpDetector;
+ float32* pfImRow = pfIm + iAngle * zpDetector;
+
+ fastTwoPowerFourierTransform1D(zpDetector, pfReRow, pfImRow, pfReRow, pfImRow, 1, 1, true);
+ }
+
+ // Copy data back
+ for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) {
+ float32* pfReRow = pfRe + iAngle * zpDetector;
+ float32* pfDataRow = _pFilteredSinogram->getData() + iAngle * iDetectorCount;
+ for (int iDetector = 0; iDetector < iDetectorCount; ++iDetector)
+ pfDataRow[iDetector] = pfReRow[iDetector];
+ }
+
+ delete[] pfRe;
+ delete[] pfIm;
+ delete[] filter;
+}
+
+}
diff --git a/src/Float32Data.cpp b/src/Float32Data.cpp
new file mode 100644
index 0000000..47bbcc9
--- /dev/null
+++ b/src/Float32Data.cpp
@@ -0,0 +1,50 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32Data.h"
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CFloat32Data::CFloat32Data()
+{
+
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CFloat32Data::~CFloat32Data()
+{
+
+}
+
+
+} // end namespace
diff --git a/src/Float32Data2D.cpp b/src/Float32Data2D.cpp
new file mode 100644
index 0000000..e51935f
--- /dev/null
+++ b/src/Float32Data2D.cpp
@@ -0,0 +1,523 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32Data2D.h"
+#include <iostream>
+#include <cstring>
+
+#ifdef _MSC_VER
+#include <malloc.h>
+#else
+#include <cstdlib>
+#endif
+
+namespace astra {
+
+
+ //----------------------------------------------------------------------------------------
+ // Constructors
+//----------------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CFloat32Data2D::CFloat32Data2D()
+{
+ _clear();
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32Data2D class, allocating (but not initializing) the data block.
+CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight)
+{
+ m_bInitialized = false;
+ _initialize(_iWidth, _iHeight);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32Data2D class with initialization of the data block.
+CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight, const float32* _pfData)
+{
+ m_bInitialized = false;
+ _initialize(_iWidth, _iHeight, _pfData);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32Data2D class with initialization of the data block.
+CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight, float32 _fScalar)
+{
+ m_bInitialized = false;
+ _initialize(_iWidth, _iHeight, _fScalar);
+}
+
+//----------------------------------------------------------------------------------------
+// Copy constructor
+CFloat32Data2D::CFloat32Data2D(const CFloat32Data2D& _other)
+{
+ m_bInitialized = false;
+ *this = _other;
+}
+
+//----------------------------------------------------------------------------------------
+// Assignment operator
+CFloat32Data2D& CFloat32Data2D::operator=(const CFloat32Data2D& _dataIn)
+{
+ ASTRA_ASSERT(_dataIn.m_bInitialized);
+
+ if (m_bInitialized) {
+ if (m_iWidth == _dataIn.m_iWidth && m_iHeight == _dataIn.m_iHeight) {
+ // Same dimensions, so no need to re-allocate memory
+
+ m_fGlobalMin = _dataIn.m_fGlobalMin;
+ m_fGlobalMax = _dataIn.m_fGlobalMax;
+ m_fGlobalMean = _dataIn.m_fGlobalMean;
+
+ ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight);
+ ASTRA_ASSERT(m_pfData);
+
+ memcpy(m_pfData, _dataIn.m_pfData, m_iSize * sizeof(float32));
+ } else {
+ // Re-allocate data
+ _unInit();
+ _initialize(_dataIn.getWidth(), _dataIn.getHeight(), _dataIn.getDataConst());
+ }
+ } else {
+ _initialize(_dataIn.getWidth(), _dataIn.getHeight(), _dataIn.getDataConst());
+ }
+
+ return (*this);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor. Free allocated memory
+CFloat32Data2D::~CFloat32Data2D()
+{
+ if (m_bInitialized)
+ {
+ _unInit();
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Initializes an instance of the CFloat32Data2D class, allocating (but not initializing) the data block.
+bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight)
+{
+ // basic checks
+ ASTRA_ASSERT(_iWidth > 0);
+ ASTRA_ASSERT(_iHeight > 0);
+
+ if (m_bInitialized)
+ {
+ _unInit();
+ }
+
+ // calculate size
+ m_iWidth = _iWidth;
+ m_iHeight = _iHeight;
+ m_iSize = (size_t)m_iWidth * m_iHeight;
+
+ // allocate memory for the data, but do not fill it
+ m_pfData = 0;
+ m_ppfData2D = 0;
+ _allocateData();
+
+ // set minmax to default values
+ m_fGlobalMin = 0.0;
+ m_fGlobalMax = 0.0;
+ m_fGlobalMean = 0.0;
+
+ // initialization complete
+ return true;
+
+}
+
+//----------------------------------------------------------------------------------------
+// Initializes an instance of the CFloat32Data2D class with initialization of the data block.
+bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight, const float32 *_pfData)
+{
+ // basic checks
+ ASTRA_ASSERT(_iWidth > 0);
+ ASTRA_ASSERT(_iHeight > 0);
+ ASTRA_ASSERT(_pfData != NULL);
+
+ if (m_bInitialized)
+ {
+ _unInit();
+ }
+
+ // calculate size
+ m_iWidth = _iWidth;
+ m_iHeight = _iHeight;
+ m_iSize = (size_t)m_iWidth * m_iHeight;
+
+ // allocate memory for the data
+ m_pfData = 0;
+ m_ppfData2D = 0;
+ _allocateData();
+
+ // fill the data block with a copy of the input data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i) {
+ m_pfData[i] = _pfData[i];
+ }
+
+ // initialization complete
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Initializes an instance of the CFloat32Data2D class with a scalar initialization of the data block.
+bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight, float32 _fScalar)
+{
+ // basic checks
+ ASTRA_ASSERT(_iWidth > 0);
+ ASTRA_ASSERT(_iHeight > 0);
+
+ if (m_bInitialized) {
+ _unInit();
+ }
+
+ // calculate size
+ m_iWidth = _iWidth;
+ m_iHeight = _iHeight;
+ m_iSize = (size_t)m_iWidth * m_iHeight;
+
+ // allocate memory for the data
+ m_pfData = 0;
+ m_ppfData2D = 0;
+ _allocateData();
+
+ // fill the data block with a copy of the input data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i)
+ {
+ m_pfData[i] = _fScalar;
+ }
+
+ // initialization complete
+ return true;
+}
+
+
+ //----------------------------------------------------------------------------------------
+ // Memory Allocation
+//----------------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------------
+// Allocate memory for m_pfData and m_ppfData2D arrays.
+void CFloat32Data2D::_allocateData()
+{
+ // basic checks
+ ASTRA_ASSERT(!m_bInitialized);
+
+ ASTRA_ASSERT(m_iSize > 0);
+ ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight);
+ ASTRA_ASSERT(m_pfData == NULL);
+ ASTRA_ASSERT(m_ppfData2D == NULL);
+
+ // allocate contiguous block
+#ifdef _MSC_VER
+ m_pfData = (float32*)_aligned_malloc(m_iSize * sizeof(float32), 16);
+#else
+ int ret = posix_memalign((void**)&m_pfData, 16, m_iSize * sizeof(float32));
+ ASTRA_ASSERT(ret == 0);
+#endif
+
+ // create array of pointers to each row of the data block
+ m_ppfData2D = new float32*[m_iHeight];
+ for (int iy = 0; iy < m_iHeight; iy++)
+ {
+ m_ppfData2D[iy] = &(m_pfData[iy * m_iWidth]);
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Free memory for m_pfData and m_ppfData2D arrays.
+void CFloat32Data2D::_freeData()
+{
+ // basic checks
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_ppfData2D != NULL);
+
+ // free memory for index table
+ delete[] m_ppfData2D;
+ // free memory for data block
+#ifdef _MSC_VER
+ _aligned_free(m_pfData);
+#else
+ free(m_pfData);
+#endif
+}
+
+
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+void CFloat32Data2D::_clear()
+{
+ m_iWidth = 0;
+ m_iHeight = 0;
+ m_iSize = 0;
+
+ m_pfData = NULL;
+ m_ppfData2D = NULL;
+
+ m_fGlobalMin = 0.0f;
+ m_fGlobalMax = 0.0f;
+}
+
+//----------------------------------------------------------------------------------------
+// Un-initialize the object, bringing it back in the unitialized state.
+void CFloat32Data2D::_unInit()
+{
+ ASTRA_ASSERT(m_bInitialized);
+
+ _freeData();
+ _clear();
+ m_bInitialized = false;
+}
+//----------------------------------------------------------------------------------------
+
+
+
+ //----------------------------------------------------------------------------------------
+ // Data Operations
+//----------------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------------
+// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData.
+void CFloat32Data2D::copyData(const float32* _pfData)
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_pfData != NULL);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+
+ // copy data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i) {
+ m_pfData[i] = _pfData[i];
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// scale m_pfData from 0 to 255.
+
+void CFloat32Data2D::scale()
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+
+ _computeGlobalMinMax();
+ for (size_t i = 0; i < m_iSize; i++)
+ {
+ // do checks
+ m_pfData[i]= (m_pfData[i] - m_fGlobalMin) / (m_fGlobalMax - m_fGlobalMin) * 255; ;
+ }
+
+
+}
+
+//----------------------------------------------------------------------------------------
+// Set each element of the data to a specific scalar value
+void CFloat32Data2D::setData(float32 _fScalar)
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+
+ // copy data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i)
+ {
+ m_pfData[i] = _fScalar;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Clear Data
+void CFloat32Data2D::clearData()
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+
+ // set data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i) {
+ m_pfData[i] = 0.0f;
+ }
+}
+//----------------------------------------------------------------------------------------
+
+
+
+ //----------------------------------------------------------------------------------------
+ // Statistics Operations
+//----------------------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------------------
+// Update data statistics, such as minimum and maximum value, after the data has been modified.
+void CFloat32Data2D::updateStatistics()
+{
+ _computeGlobalMinMax();
+}
+
+//----------------------------------------------------------------------------------------
+// Find the minimum and maximum data value.
+void CFloat32Data2D::_computeGlobalMinMax()
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+
+ // initial values
+ m_fGlobalMin = m_pfData[0];
+ m_fGlobalMax = m_pfData[0];
+ m_fGlobalMean = 0.0f;
+
+ // loop
+ for (size_t i = 0; i < m_iSize; i++)
+ {
+ // do checks
+ float32 v = m_pfData[i];
+ if (v < m_fGlobalMin) {
+ m_fGlobalMin = v;
+ }
+ if (v > m_fGlobalMax) {
+ m_fGlobalMax = v;
+ }
+ m_fGlobalMean +=v;
+ }
+ m_fGlobalMean /= m_iSize;
+}
+//----------------------------------------------------------------------------------------
+
+
+CFloat32Data2D& CFloat32Data2D::clampMin(float32& _fMin)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ for (size_t i = 0; i < m_iSize; i++) {
+ if (m_pfData[i] < _fMin)
+ m_pfData[i] = _fMin;
+ }
+ return (*this);
+}
+
+CFloat32Data2D& CFloat32Data2D::clampMax(float32& _fMax)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ for (size_t i = 0; i < m_iSize; i++) {
+ if (m_pfData[i] > _fMax)
+ m_pfData[i] = _fMax;
+ }
+ return (*this);
+}
+
+
+//----------------------------------------------------------------------------------------
+// Operator Overloading
+//----------------------------------------------------------------------------------------
+CFloat32Data2D& CFloat32Data2D::operator+=(const CFloat32Data2D& v)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(v.m_bInitialized);
+ ASTRA_ASSERT(getSize() == v.getSize());
+ for (size_t i = 0; i < m_iSize; i++) {
+ m_pfData[i] += v.m_pfData[i];
+ }
+ return (*this);
+}
+
+CFloat32Data2D& CFloat32Data2D::operator-=(const CFloat32Data2D& v)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(v.m_bInitialized);
+ ASTRA_ASSERT(getSize() == v.getSize());
+ for (size_t i = 0; i < m_iSize; i++) {
+ m_pfData[i] -= v.m_pfData[i];
+ }
+ return (*this);
+}
+
+CFloat32Data2D& CFloat32Data2D::operator*=(const CFloat32Data2D& v)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(v.m_bInitialized);
+ ASTRA_ASSERT(getSize() == v.getSize());
+ for (size_t i = 0; i < m_iSize; i++) {
+ m_pfData[i] *= v.m_pfData[i];
+ }
+ return (*this);
+}
+
+CFloat32Data2D& CFloat32Data2D::operator*=(const float32& f)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ for (size_t i = 0; i < m_iSize; i++) {
+ m_pfData[i] *= f;
+ }
+ return (*this);
+}
+
+CFloat32Data2D& CFloat32Data2D::operator/=(const float32& f)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ for (size_t i = 0; i < m_iSize; i++) {
+ m_pfData[i] /= f;
+ }
+ return (*this);
+}
+
+CFloat32Data2D& CFloat32Data2D::operator+=(const float32& f)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ for (size_t i = 0; i < m_iSize; i++) {
+ m_pfData[i] += f;
+ }
+ return (*this);
+}
+
+CFloat32Data2D& CFloat32Data2D::operator-=(const float32& f)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ for (size_t i = 0; i < m_iSize; i++) {
+ m_pfData[i] -= f;
+ }
+ return (*this);
+}
+
+
+
+
+} // end namespace astra
diff --git a/src/Float32Data3D.cpp b/src/Float32Data3D.cpp
new file mode 100644
index 0000000..4280b3b
--- /dev/null
+++ b/src/Float32Data3D.cpp
@@ -0,0 +1,55 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32Data3D.h"
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CFloat32Data3D::CFloat32Data3D()
+{
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CFloat32Data3D::~CFloat32Data3D()
+{
+
+}
+//----------------------------------------------------------------------------------------
+
+bool CFloat32Data3D::_data3DSizesEqual(const CFloat32Data3D * _pA, const CFloat32Data3D * _pB)
+{
+ return ((_pA->m_iWidth == _pB->m_iWidth) && (_pA->m_iHeight == _pB->m_iHeight) && (_pA->m_iDepth == _pB->m_iDepth));
+}
+
+} // end namespace astra
diff --git a/src/Float32Data3DMemory.cpp b/src/Float32Data3DMemory.cpp
new file mode 100644
index 0000000..386770c
--- /dev/null
+++ b/src/Float32Data3DMemory.cpp
@@ -0,0 +1,356 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32Data3DMemory.h"
+#include <iostream>
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CFloat32Data3DMemory::CFloat32Data3DMemory()
+{
+ _clear();
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor. Free allocated memory
+CFloat32Data3DMemory::~CFloat32Data3DMemory()
+{
+ if (m_bInitialized)
+ {
+ _unInit();
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Initializes an instance of the CFloat32Data2D class, allocating (but not initializing) the data block.
+bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth)
+{
+ // basic checks
+ ASTRA_ASSERT(_iWidth > 0);
+ ASTRA_ASSERT(_iHeight > 0);
+ ASTRA_ASSERT(_iDepth > 0);
+
+ if (m_bInitialized)
+ {
+ _unInit();
+ }
+
+ // calculate size
+ m_iWidth = _iWidth;
+ m_iHeight = _iHeight;
+ m_iDepth = _iDepth;
+ m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth;
+
+ // allocate memory for the data, but do not fill it
+ m_pfData = NULL;
+ m_ppfDataRowInd = NULL;
+ m_pppfDataSliceInd = NULL;
+ _allocateData();
+
+ // set minmax to default values
+ m_fGlobalMin = 0.0;
+ m_fGlobalMax = 0.0;
+
+ // initialization complete
+ return true;
+
+}
+
+//----------------------------------------------------------------------------------------
+// Initializes an instance of the CFloat32Data2D class with initialization of the data block.
+bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth, const float32* _pfData)
+{
+ // basic checks
+ ASTRA_ASSERT(_iWidth > 0);
+ ASTRA_ASSERT(_iHeight > 0);
+ ASTRA_ASSERT(_iDepth > 0);
+ ASTRA_ASSERT(_pfData != NULL);
+
+ if (m_bInitialized) {
+ _unInit();
+ }
+
+ // calculate size
+ m_iWidth = _iWidth;
+ m_iHeight = _iHeight;
+ m_iDepth = _iDepth;
+ m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth;
+
+ // allocate memory for the data, but do not fill it
+ m_pfData = NULL;
+ m_ppfDataRowInd = NULL;
+ m_pppfDataSliceInd = NULL;
+ _allocateData();
+
+ // fill the data block with a copy of the input data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i)
+ {
+ m_pfData[i] = _pfData[i];
+ }
+
+ // initialization complete
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Initializes an instance of the CFloat32Data2D class with initialization of the data block.
+bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth, float32 _fScalar)
+{
+ // basic checks
+ ASTRA_ASSERT(_iWidth > 0);
+ ASTRA_ASSERT(_iHeight > 0);
+ ASTRA_ASSERT(_iDepth > 0);
+
+ if (m_bInitialized) {
+ _unInit();
+ }
+
+ // calculate size
+ m_iWidth = _iWidth;
+ m_iHeight = _iHeight;
+ m_iDepth = _iDepth;
+ m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth;
+
+ // allocate memory for the data, but do not fill it
+ m_pfData = NULL;
+ m_ppfDataRowInd = NULL;
+ m_pppfDataSliceInd = NULL;
+ _allocateData();
+
+ // fill the data block with a copy of the input data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i)
+ {
+ m_pfData[i] = _fScalar;
+ }
+
+ // initialization complete
+ return true;
+}
+//----------------------------------------------------------------------------------------
+
+
+//----------------------------------------------------------------------------------------
+// Allocate memory for m_pfData and m_ppfData2D arrays.
+void CFloat32Data3DMemory::_allocateData()
+{
+ // basic checks
+ ASTRA_ASSERT(!m_bInitialized);
+
+ ASTRA_ASSERT(m_iSize > 0);
+ ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight * m_iDepth);
+ ASTRA_ASSERT(m_pfData == NULL);
+ ASTRA_ASSERT(m_ppfDataRowInd == NULL);
+ ASTRA_ASSERT(m_pppfDataSliceInd == NULL);
+
+ // allocate contiguous block
+#ifdef _MSC_VER
+ m_pfData = (float32*)_aligned_malloc(m_iSize * sizeof(float32), 16);
+#else
+ int ret = posix_memalign((void**)&m_pfData, 16, m_iSize * sizeof(float32));
+ ASTRA_ASSERT(ret == 0);
+#endif
+ ASTRA_ASSERT(((size_t)m_pfData & 15) == 0);
+
+ // create array of pointers to each row of the data block
+ m_ppfDataRowInd = new float32*[m_iHeight*m_iDepth];
+ for (int iy = 0; iy < m_iHeight*m_iDepth; iy++)
+ {
+ m_ppfDataRowInd[iy] = &(m_pfData[iy * m_iWidth]);
+ }
+
+ // create array of pointers to each row of the data block
+ m_pppfDataSliceInd = new float32**[m_iDepth];
+ for (int iy = 0; iy < m_iDepth; iy++)
+ {
+ m_pppfDataSliceInd[iy] = &(m_ppfDataRowInd[iy * m_iHeight]);
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Free memory for m_pfData and m_ppfData2D arrays.
+void CFloat32Data3DMemory::_freeData()
+{
+ // basic checks
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_ppfDataRowInd != NULL);
+ ASTRA_ASSERT(m_pppfDataSliceInd != NULL);
+
+ // free memory for index table
+ delete[] m_pppfDataSliceInd;
+ // free memory for index table
+ delete[] m_ppfDataRowInd;
+ // free memory for data block
+#ifdef _MSC_VER
+ _aligned_free(m_pfData);
+#else
+ free(m_pfData);
+#endif
+}
+
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+void CFloat32Data3DMemory::_clear()
+{
+ m_iWidth = 0;
+ m_iHeight = 0;
+ m_iDepth = 0;
+ m_iSize = 0;
+
+ m_pfData = NULL;
+ m_ppfDataRowInd = NULL;
+ m_pppfDataSliceInd = NULL;
+
+ //m_fGlobalMin = 0.0f;
+ //m_fGlobalMax = 0.0f;
+}
+
+//----------------------------------------------------------------------------------------
+// Un-initialize the object, bringing it back in the unitialized state.
+void CFloat32Data3DMemory::_unInit()
+{
+ ASTRA_ASSERT(m_bInitialized);
+
+ _freeData();
+ _clear();
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Update data statistics, such as minimum and maximum value, after the data has been modified.
+void CFloat32Data3DMemory::updateStatistics()
+{
+ _computeGlobalMinMax();
+}
+
+//----------------------------------------------------------------------------------------
+// Find the minimum and maximum data value.
+void CFloat32Data3DMemory::_computeGlobalMinMax()
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+
+ // initial values
+ m_fGlobalMin = m_pfData[0];
+ m_fGlobalMax = m_pfData[0];
+
+ // loop
+ size_t i;
+ float32 v;
+ for (i = 0; i < m_iSize; ++i)
+ {
+ v = m_pfData[i];
+ if (v < m_fGlobalMin) m_fGlobalMin = v;
+ if (v > m_fGlobalMax) m_fGlobalMax = v;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData.
+void CFloat32Data3DMemory::copyData(const float32* _pfData, size_t _iSize)
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(_pfData != NULL);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+ ASTRA_ASSERT(m_iSize == _iSize);
+
+ // copy data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i)
+ {
+ m_pfData[i] = _pfData[i];
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData.
+void CFloat32Data3DMemory::setData(float32 _fScalar)
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+
+ // copy data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i)
+ {
+ m_pfData[i] = _fScalar;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Clear Data
+void CFloat32Data3DMemory::clearData()
+{
+ // basic checks
+ ASTRA_ASSERT(m_bInitialized);
+ ASTRA_ASSERT(m_pfData != NULL);
+ ASTRA_ASSERT(m_iSize > 0);
+
+ // set data
+ size_t i;
+ for (i = 0; i < m_iSize; ++i) {
+ m_pfData[i] = 0.0f;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+
+CFloat32Data3D& CFloat32Data3DMemory::clampMin(float32& _fMin)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ for (size_t i = 0; i < m_iSize; i++) {
+ if (m_pfData[i] < _fMin)
+ m_pfData[i] = _fMin;
+ }
+ return (*this);
+}
+
+CFloat32Data3D& CFloat32Data3DMemory::clampMax(float32& _fMax)
+{
+ ASTRA_ASSERT(m_bInitialized);
+ for (size_t i = 0; i < m_iSize; i++) {
+ if (m_pfData[i] > _fMax)
+ m_pfData[i] = _fMax;
+ }
+ return (*this);
+}
+
+
+
+
+} // end namespace astra
diff --git a/src/Float32ProjectionData2D.cpp b/src/Float32ProjectionData2D.cpp
new file mode 100644
index 0000000..a74fc14
--- /dev/null
+++ b/src/Float32ProjectionData2D.cpp
@@ -0,0 +1,139 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32ProjectionData2D.h"
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CFloat32ProjectionData2D::CFloat32ProjectionData2D() :
+ CFloat32Data2D()
+{
+ m_bInitialized = false;
+ m_pGeometry = NULL;
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32ProjectionData2D class, allocating (but not initializing) the data block.
+CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry)
+{
+ m_bInitialized = false;
+ initialize(_pGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32ProjectionData2D class with initialization of the data.
+CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32* _pfData)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry, _pfData);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32ProjectionData2D class with scalar initialization of the data.
+CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32 _fScalar)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry, _fScalar);
+}
+
+
+//----------------------------------------------------------------------------------------
+// Copy constructor
+CFloat32ProjectionData2D::CFloat32ProjectionData2D(const CFloat32ProjectionData2D& _other) : CFloat32Data2D(_other)
+{
+ // Data is copied by parent constructor
+ m_pGeometry = _other.m_pGeometry->clone();
+ m_bInitialized = true;
+}
+
+// Assignment operator
+
+CFloat32ProjectionData2D& CFloat32ProjectionData2D::operator=(const CFloat32ProjectionData2D& _other)
+{
+ ASTRA_ASSERT(_other.m_bInitialized);
+
+ if (m_bInitialized)
+ delete m_pGeometry;
+ *((CFloat32Data2D*)this) = _other;
+ m_pGeometry = _other.m_pGeometry->clone();
+ m_bInitialized = true;
+
+ return *this;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount());
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry, const float32* _pfData)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount(), _pfData);
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry, float32 _fScalar)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount(), _fScalar);
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CFloat32ProjectionData2D::~CFloat32ProjectionData2D()
+{
+ if (m_bInitialized)
+ delete m_pGeometry;
+ m_pGeometry = 0;
+}
+
+//----------------------------------------------------------------------------------------
+void CFloat32ProjectionData2D::changeGeometry(CProjectionGeometry2D* _pGeometry)
+{
+ if (!m_bInitialized) return;
+
+ delete m_pGeometry;
+ m_pGeometry = _pGeometry->clone();
+}
+
+} // end namespace astra
diff --git a/src/Float32ProjectionData3D.cpp b/src/Float32ProjectionData3D.cpp
new file mode 100644
index 0000000..66bb5e3
--- /dev/null
+++ b/src/Float32ProjectionData3D.cpp
@@ -0,0 +1,273 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32ProjectionData3D.h"
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Constructors
+//----------------------------------------------------------------------------------------
+
+
+// Default constructor
+CFloat32ProjectionData3D::CFloat32ProjectionData3D() :
+ CFloat32Data3D() {
+}
+
+// Destructor
+CFloat32ProjectionData3D::~CFloat32ProjectionData3D() {
+ delete m_pGeometry;
+ m_pGeometry = 0;
+}
+
+CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const CFloat32ProjectionData3D& _data)
+{
+ CProjectionGeometry3D * pThisGeometry = getGeometry();
+
+ int iProjectionCount = pThisGeometry->getProjectionCount();
+#ifdef _DEBUG
+ CProjectionGeometry3D * pDataGeometry = _data.getGeometry();
+ int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount();
+ int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount();
+
+ ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount());
+ ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount);
+#endif
+
+ for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
+ CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+ float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
+
+ fThisValue += fDataValue;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnProjection(iProjectionIndex, pThisProjection);
+
+ delete pThisProjection;
+ delete pDataProjection;
+ }
+
+ return *this;
+}
+
+CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const CFloat32ProjectionData3D& _data)
+{
+ CProjectionGeometry3D * pThisGeometry = getGeometry();
+
+ int iProjectionCount = pThisGeometry->getProjectionCount();
+#ifdef _DEBUG
+ CProjectionGeometry3D * pDataGeometry = _data.getGeometry();
+ int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount();
+ int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount();
+
+ ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount());
+ ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount);
+#endif
+
+ for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
+ CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+ float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
+
+ fThisValue -= fDataValue;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnProjection(iProjectionIndex, pThisProjection);
+
+ delete pThisProjection;
+ delete pDataProjection;
+ }
+
+ return *this;
+}
+
+CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const CFloat32ProjectionData3D& _data)
+{
+ CProjectionGeometry3D * pThisGeometry = getGeometry();
+
+ int iProjectionCount = pThisGeometry->getProjectionCount();
+#ifdef _DEBUG
+ CProjectionGeometry3D * pDataGeometry = _data.getGeometry();
+ int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount();
+ int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount();
+
+ ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount());
+ ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount);
+#endif
+
+ for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
+ CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+ float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
+
+ fThisValue *= fDataValue;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnProjection(iProjectionIndex, pThisProjection);
+
+ delete pThisProjection;
+ delete pDataProjection;
+ }
+
+ return *this;
+}
+
+CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const float32& _fScalar)
+{
+ CProjectionGeometry3D * pThisGeometry = getGeometry();
+
+ int iProjectionCount = pThisGeometry->getProjectionCount();
+
+ for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+
+ fThisValue *= _fScalar;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnProjection(iProjectionIndex, pThisProjection);
+
+ delete pThisProjection;
+ }
+
+ return *this;
+}
+
+CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator/=(const float32& _fScalar)
+{
+ CProjectionGeometry3D * pThisGeometry = getGeometry();
+
+ int iProjectionCount = pThisGeometry->getProjectionCount();
+
+ for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+
+ fThisValue /= _fScalar;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnProjection(iProjectionIndex, pThisProjection);
+
+ delete pThisProjection;
+ }
+
+ return *this;
+}
+
+CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const float32& _fScalar)
+{
+ CProjectionGeometry3D * pThisGeometry = getGeometry();
+
+ int iProjectionCount = pThisGeometry->getProjectionCount();
+
+ for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+
+ fThisValue += _fScalar;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnProjection(iProjectionIndex, pThisProjection);
+
+ delete pThisProjection;
+ }
+
+ return *this;
+}
+
+CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const float32& _fScalar)
+{
+ CProjectionGeometry3D * pThisGeometry = getGeometry();
+
+ int iProjectionCount = pThisGeometry->getProjectionCount();
+
+ for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+
+ fThisValue -= _fScalar;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnProjection(iProjectionIndex, pThisProjection);
+
+ delete pThisProjection;
+ }
+
+ return *this;
+}
+
+} // end namespace astra
diff --git a/src/Float32ProjectionData3DMemory.cpp b/src/Float32ProjectionData3DMemory.cpp
new file mode 100644
index 0000000..4d23688
--- /dev/null
+++ b/src/Float32ProjectionData3DMemory.cpp
@@ -0,0 +1,221 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32ProjectionData3DMemory.h"
+#include "astra/ParallelProjectionGeometry3D.h"
+
+#include <cstring>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory() :
+ CFloat32Data3DMemory()
+{
+ m_bInitialized = false;
+ m_pGeometry = NULL;
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32ProjectionData2D class, allocating (but not initializing) the data block.
+CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry)
+{
+ m_bInitialized = false;
+ initialize(_pGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32ProjectionData2D class with initialization of the data.
+CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32* _pfData)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry, _pfData);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32ProjectionData2D class with initialization of the data.
+CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32 _fScalar)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry, _fScalar);
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width
+ m_pGeometry->getProjectionCount(), // height
+ m_pGeometry->getDetectorRowCount()); // depth
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry, const float32* _pfData)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width
+ m_pGeometry->getProjectionCount(), // height
+ m_pGeometry->getDetectorRowCount(), // depth
+ _pfData);
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry, float32 _fScalar)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width
+ m_pGeometry->getProjectionCount(), // height
+ m_pGeometry->getDetectorRowCount(), // depth
+ _fScalar);
+ return m_bInitialized;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CFloat32ProjectionData3DMemory::~CFloat32ProjectionData3DMemory()
+{
+ //delete m_pGeometry; //delete geom inherited from CFloat32ProjectionData3D
+ //_unInit(); //delete stuff inherited from CFloat32Data3DMemory
+}
+
+//----------------------------------------------------------------------------------------
+// Fetch a projection
+CFloat32VolumeData2D* CFloat32ProjectionData3DMemory::fetchProjection(int _iProjectionNr) const
+{
+ // fetch slice of the geometry
+ CVolumeGeometry2D volGeom(m_pGeometry->getDetectorColCount(), m_pGeometry->getDetectorRowCount());
+ // create new volume data
+ CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom);
+ // copy data
+ int row, col;
+ for (row = 0; row < m_pGeometry->getDetectorRowCount(); ++row) {
+ for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) {
+ res->getData()[row*m_pGeometry->getDetectorColCount() + col] =
+ m_pfData[_iProjectionNr * m_pGeometry->getDetectorColCount() + m_pGeometry->getDetectorColCount()* m_pGeometry->getProjectionCount() * row + col];
+ }
+ }
+ // return
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// Return a projection
+void CFloat32ProjectionData3DMemory::returnProjection(int _iProjectionNr, CFloat32VolumeData2D* _pProjection)
+{
+ /// TODO: check geometry
+ // copy data
+ int row, col;
+ for (row = 0; row < m_pGeometry->getDetectorRowCount(); ++row) {
+ for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) {
+ m_pfData[_iProjectionNr * m_pGeometry->getDetectorColCount() + m_pGeometry->getDetectorColCount()* m_pGeometry->getProjectionCount() * row + col] =
+ _pProjection->getData()[row*m_pGeometry->getDetectorColCount() + col];
+ }
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Fetch a sinogram
+CFloat32ProjectionData2D* CFloat32ProjectionData3DMemory::fetchSinogram(int _iSliceNr) const
+{
+ CParallelProjectionGeometry3D * pParallelProjGeo = (CParallelProjectionGeometry3D *)m_pGeometry;
+ CParallelProjectionGeometry2D * pProjGeo2D = pParallelProjGeo->createProjectionGeometry2D();
+
+ // create new projection data
+ CFloat32ProjectionData2D* res = new CFloat32ProjectionData2D(pProjGeo2D);
+ // copy data
+ int row, col;
+
+ int iDetectorColumnCount = m_pGeometry->getDetectorColCount();
+ int iProjectionAngleCount = m_pGeometry->getProjectionCount();
+
+ for (row = 0; row < m_pGeometry->getProjectionCount(); ++row) {
+ for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col)
+ {
+ int iTargetIndex = row * iDetectorColumnCount + col;
+ int iSourceIndex = _iSliceNr * iDetectorColumnCount * iProjectionAngleCount + row * iDetectorColumnCount + col;
+
+ float32 fStoredValue = m_pfData[iSourceIndex];
+
+ res->getData()[iTargetIndex] = fStoredValue;
+ }
+ }
+
+ delete pProjGeo2D;
+
+ // return
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// Return a sinogram
+void CFloat32ProjectionData3DMemory::returnSinogram(int _iSliceNr, CFloat32ProjectionData2D* _pSinogram2D)
+{
+ /// TODO: check geometry
+ // copy data
+ int row, col;
+ for (row = 0; row < m_pGeometry->getProjectionCount(); ++row) {
+ for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) {
+ m_pfData[_iSliceNr*m_pGeometry->getDetectorColCount()*m_pGeometry->getProjectionCount() + row*m_pGeometry->getDetectorColCount() + col] =
+ _pSinogram2D->getData()[row*m_pGeometry->getDetectorColCount() + col];
+ }
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Returns a specific value
+float32 CFloat32ProjectionData3DMemory::getDetectorValue(int _iIndex)
+{
+ return m_pfData[_iIndex];
+}
+
+//----------------------------------------------------------------------------------------
+// Sets a specific value
+void CFloat32ProjectionData3DMemory::setDetectorValue(int _iIndex, float32 _fValue)
+{
+ m_pfData[_iIndex] = _fValue;
+}
+//----------------------------------------------------------------------------------------
+
+CFloat32ProjectionData3DMemory& CFloat32ProjectionData3DMemory::operator=(const CFloat32ProjectionData3DMemory& _dataIn)
+{
+ memcpy(m_pfData, _dataIn.m_pfData, sizeof(float32) * _dataIn.m_pGeometry->getDetectorTotCount());
+
+ return *this;
+}
+
+} // end namespace astra
diff --git a/src/Float32VolumeData2D.cpp b/src/Float32VolumeData2D.cpp
new file mode 100644
index 0000000..f07fd71
--- /dev/null
+++ b/src/Float32VolumeData2D.cpp
@@ -0,0 +1,135 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32VolumeData2D.h"
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CFloat32VolumeData2D::CFloat32VolumeData2D() :
+ CFloat32Data2D()
+{
+ m_pGeometry = NULL;
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32VolumeData2D class, allocating (but not initializing) the data block.
+CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32VolumeData2D class with initialization of the data.
+CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32* _pfData)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry, _pfData);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32VolumeData2D class with initialization of the data.
+CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32 _fScalar)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry, _fScalar);
+}
+
+//----------------------------------------------------------------------------------------
+// Copy constructor
+CFloat32VolumeData2D::CFloat32VolumeData2D(const CFloat32VolumeData2D& _other) : CFloat32Data2D(_other)
+{
+ m_pGeometry = _other.m_pGeometry->clone();
+ m_bInitialized = true;
+}
+
+// Assignment operator
+
+CFloat32VolumeData2D& CFloat32VolumeData2D::operator=(const CFloat32VolumeData2D& _other)
+{
+ ASTRA_ASSERT(_other.m_bInitialized);
+
+ if (m_bInitialized)
+ delete m_pGeometry;
+ *((CFloat32Data2D*)this) = _other;
+ m_pGeometry = _other.m_pGeometry->clone();
+ m_bInitialized = true;
+
+ return *this;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CFloat32VolumeData2D::~CFloat32VolumeData2D()
+{
+ if (m_bInitialized)
+ delete m_pGeometry;
+ m_pGeometry = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount());
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry, const float32* _pfData)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), _pfData);
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry, float32 _fScalar)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), _fScalar);
+ return m_bInitialized;
+}
+//----------------------------------------------------------------------------------------
+void CFloat32VolumeData2D::changeGeometry(CVolumeGeometry2D* _pGeometry)
+{
+ if (!m_bInitialized) return;
+
+ delete m_pGeometry;
+ m_pGeometry = _pGeometry->clone();
+}
+
+
+} // end namespace astra
diff --git a/src/Float32VolumeData3D.cpp b/src/Float32VolumeData3D.cpp
new file mode 100644
index 0000000..d269aa8
--- /dev/null
+++ b/src/Float32VolumeData3D.cpp
@@ -0,0 +1,269 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32VolumeData3D.h"
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CFloat32VolumeData3D::CFloat32VolumeData3D() :
+ CFloat32Data3D() {
+
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CFloat32VolumeData3D::~CFloat32VolumeData3D() {
+
+}
+
+CFloat32VolumeData3D& CFloat32VolumeData3D::operator+=(const CFloat32VolumeData3D& _data)
+{
+ CVolumeGeometry3D * pThisGeometry = getGeometry();
+
+ int iSliceCount = pThisGeometry->getGridSliceCount();
+#ifdef _DEBUG
+ CVolumeGeometry3D * pDataGeometry = _data.getGeometry();
+ int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount();
+ int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount();
+
+ ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount());
+ ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount);
+#endif
+
+ for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);
+ CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+ float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
+
+ fThisValue += fDataValue;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnSliceZ(iSliceIndex, pThisProjection);
+
+ delete pThisProjection;
+ delete pDataProjection;
+ }
+
+ return *this;
+}
+
+CFloat32VolumeData3D& CFloat32VolumeData3D::operator-=(const CFloat32VolumeData3D& _data)
+{
+ CVolumeGeometry3D * pThisGeometry = getGeometry();
+
+ int iSliceCount = pThisGeometry->getGridSliceCount();
+#ifdef _DEBUG
+ CVolumeGeometry3D * pDataGeometry = _data.getGeometry();
+ int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount();
+ int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount();
+
+ ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount());
+ ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount);
+#endif
+
+ for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);
+ CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+ float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
+
+ fThisValue -= fDataValue;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnSliceZ(iSliceIndex, pThisProjection);
+
+ delete pThisProjection;
+ delete pDataProjection;
+ }
+
+ return *this;
+}
+
+CFloat32VolumeData3D& CFloat32VolumeData3D::operator*=(const CFloat32VolumeData3D& _data)
+{
+ CVolumeGeometry3D * pThisGeometry = getGeometry();
+
+ int iSliceCount = pThisGeometry->getGridSliceCount();
+#ifdef _DEBUG
+ CVolumeGeometry3D * pDataGeometry = _data.getGeometry();
+ int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount();
+ int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount();
+
+ ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount());
+ ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount);
+#endif
+
+ for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);
+ CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+ float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex];
+
+ fThisValue *= fDataValue;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnSliceZ(iSliceIndex, pThisProjection);
+
+ delete pThisProjection;
+ delete pDataProjection;
+ }
+
+ return *this;
+}
+
+CFloat32VolumeData3D& CFloat32VolumeData3D::operator*=(const float32& _fScalar)
+{
+ CVolumeGeometry3D * pThisGeometry = getGeometry();
+
+ int iSliceCount = pThisGeometry->getGridSliceCount();
+
+ for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+
+ fThisValue *= _fScalar;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnSliceZ(iSliceIndex, pThisProjection);
+
+ delete pThisProjection;
+ }
+
+ return *this;
+}
+
+CFloat32VolumeData3D& CFloat32VolumeData3D::operator/=(const float32& _fScalar)
+{
+ CVolumeGeometry3D * pThisGeometry = getGeometry();
+
+ int iSliceCount = pThisGeometry->getGridSliceCount();
+
+ for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+
+ fThisValue /= _fScalar;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnSliceZ(iSliceIndex, pThisProjection);
+
+ delete pThisProjection;
+ }
+
+ return *this;
+}
+
+CFloat32VolumeData3D& CFloat32VolumeData3D::operator+=(const float32& _fScalar)
+{
+ CVolumeGeometry3D * pThisGeometry = getGeometry();
+
+ int iSliceCount = pThisGeometry->getGridSliceCount();
+
+ for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+
+ fThisValue += _fScalar;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnSliceZ(iSliceIndex, pThisProjection);
+
+ delete pThisProjection;
+ }
+
+ return *this;
+}
+
+CFloat32VolumeData3D& CFloat32VolumeData3D::operator-=(const float32& _fScalar)
+{
+ CVolumeGeometry3D * pThisGeometry = getGeometry();
+
+ int iSliceCount = pThisGeometry->getGridSliceCount();
+
+ for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++)
+ {
+ CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex);
+
+ for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++)
+ {
+ float32 fThisValue = pThisProjection->getData()[iDetectorIndex];
+
+ fThisValue -= _fScalar;
+
+ pThisProjection->getData()[iDetectorIndex] = fThisValue;
+ }
+
+ returnSliceZ(iSliceIndex, pThisProjection);
+
+ delete pThisProjection;
+ }
+
+ return *this;
+}
+
+} // end namespace astra
diff --git a/src/Float32VolumeData3DMemory.cpp b/src/Float32VolumeData3DMemory.cpp
new file mode 100644
index 0000000..aa3832b
--- /dev/null
+++ b/src/Float32VolumeData3DMemory.cpp
@@ -0,0 +1,208 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Float32VolumeData3DMemory.h"
+
+#include <cstring>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory() :
+ CFloat32Data3DMemory()
+{
+ m_pGeometry = NULL;
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32VolumeData2D class, allocating (but not initializing) the data block.
+CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32VolumeData2D class with initialization of the data.
+CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, const float32* _pfData)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry, _pfData);
+}
+
+//----------------------------------------------------------------------------------------
+// Create an instance of the CFloat32VolumeData2D class with initialization of the data.
+CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, float32 _fScalar)
+{
+ m_bInitialized = false;
+ m_bInitialized = initialize(_pGeometry, _fScalar);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CFloat32VolumeData3DMemory::~CFloat32VolumeData3DMemory()
+{
+ if(m_pGeometry){
+ delete m_pGeometry;
+ }
+ m_pGeometry = 0;
+
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount());
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, const float32* _pfData)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount(), _pfData);
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization
+bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, float32 _fScalar)
+{
+ m_pGeometry = _pGeometry->clone();
+ m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount(), _fScalar);
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Fetch a slice
+CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceZ(int _iSliceIndex) const
+{
+ // fetch slice of the geometry
+ int iRowCount = m_pGeometry->getGridRowCount();
+ int iColumnCount = m_pGeometry->getGridColCount();
+ CVolumeGeometry2D volGeom(iColumnCount, iRowCount);
+
+ // create new volume data
+ CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom);
+
+ // copy data
+ int iSliceCount = m_pGeometry->getGridSliceCount();
+ float * pfTargetData = res->getData();
+ for(int iRowIndex = 0; iRowIndex < iRowCount; iRowIndex++)
+ {
+ for(int iColumnIndex = 0; iColumnIndex < iColumnCount; iColumnIndex++)
+ {
+ int iSourceIndex = _iSliceIndex * iColumnCount * iRowCount + iRowIndex * iColumnCount + iColumnIndex;
+ int iTargetIndex = iRowIndex * iColumnCount + iColumnIndex;
+ float fStoredValue = m_pfData[iSourceIndex];
+ pfTargetData[iTargetIndex] = fStoredValue;
+ }
+ }
+ // return
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// Return a slice
+void CFloat32VolumeData3DMemory::returnSliceZ(int _iSliceIndex, CFloat32VolumeData2D * _pSlice)
+{
+ int iRowCount = _pSlice->getGeometry()->getGridRowCount();
+ int iColumnCount = _pSlice->getGeometry()->getGridColCount();
+
+ assert(iRowCount == m_pGeometry->getGridRowCount());
+ assert(iColumnCount == m_pGeometry->getGridColCount());
+
+ for(int iRowIndex = 0; iRowIndex < iRowCount; iRowIndex++)
+ {
+ for(int iColumnIndex = 0; iColumnIndex < iColumnCount; iColumnIndex++)
+ {
+ int iSourceIndex = iRowIndex * iColumnCount + iColumnIndex;
+ int iTargetIndex = _iSliceIndex * iColumnCount * iRowCount + iRowIndex * iColumnCount + iColumnIndex;
+ float fStoredValue = _pSlice->getDataConst()[iSourceIndex];
+ m_pfData[iTargetIndex] = fStoredValue;
+ }
+ }
+}
+
+CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceX(int _iColumnIndex) const
+{
+ // TODO:
+ assert(false);
+ return NULL;
+}
+
+CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceY(int _iRowIndex) const
+{
+ // TODO:
+ assert(false);
+ return NULL;
+}
+
+void CFloat32VolumeData3DMemory::returnSliceX(int _iColumnIndex, CFloat32VolumeData2D * _pSliceData)
+{
+ // TODO:
+ assert(false);
+}
+
+void CFloat32VolumeData3DMemory::returnSliceY(int _iRowIndex, CFloat32VolumeData2D * _pSliceData)
+{
+ // TODO:
+ assert(false);
+}
+
+//----------------------------------------------------------------------------------------
+// Returns a specific value
+float32 CFloat32VolumeData3DMemory::getVoxelValue(int _iIndex)
+{
+ return m_pfData[_iIndex];
+}
+
+//----------------------------------------------------------------------------------------
+// Sets a specific value
+void CFloat32VolumeData3DMemory::setVoxelValue(int _iIndex, float32 _fValue)
+{
+ m_pfData[_iIndex] = _fValue;
+}
+//----------------------------------------------------------------------------------------
+
+CFloat32VolumeData3DMemory& CFloat32VolumeData3DMemory::operator=(const CFloat32VolumeData3DMemory& _dataIn)
+{
+ memcpy(m_pfData, _dataIn.m_pfData, sizeof(float32) * _dataIn.m_pGeometry->getGridTotCount());
+
+ return *this;
+}
+
+} // end namespace astra
diff --git a/src/ForwardProjectionAlgorithm.cpp b/src/ForwardProjectionAlgorithm.cpp
new file mode 100644
index 0000000..970d5b0
--- /dev/null
+++ b/src/ForwardProjectionAlgorithm.cpp
@@ -0,0 +1,280 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ForwardProjectionAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+
+namespace astra {
+
+#include "astra/Projector2DImpl.inl"
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CForwardProjectionAlgorithm::type = "FP";
+
+//----------------------------------------------------------------------------------------
+// Constructor - Default
+CForwardProjectionAlgorithm::CForwardProjectionAlgorithm()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CForwardProjectionAlgorithm::CForwardProjectionAlgorithm(CProjector2D* _pProjector, CFloat32VolumeData2D* _pVolume, CFloat32ProjectionData2D* _pSinogram)
+{
+ _clear();
+ initialize(_pProjector, _pVolume, _pSinogram);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CForwardProjectionAlgorithm::~CForwardProjectionAlgorithm()
+{
+ delete m_pForwardProjector;
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CForwardProjectionAlgorithm::_clear()
+{
+ m_pProjector = NULL;
+ m_pSinogram = NULL;
+ m_pVolume = NULL;
+ m_pForwardProjector = NULL;
+ m_bUseSinogramMask = false;
+ m_bUseVolumeMask = false;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CForwardProjectionAlgorithm::clear()
+{
+ m_pProjector = NULL;
+ m_pSinogram = NULL;
+ m_pVolume = NULL;
+ m_bUseSinogramMask = false;
+ m_bUseVolumeMask = false;
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CForwardProjectionAlgorithm::_check()
+{
+ // check pointers
+ ASTRA_CONFIG_CHECK(m_pProjector, "ForwardProjection", "Invalid Projector Object.");
+ ASTRA_CONFIG_CHECK(m_pSinogram, "ForwardProjection", "Invalid Projection Data Object.");
+ ASTRA_CONFIG_CHECK(m_pVolume, "ForwardProjection", "Invalid Volume Data Object.");
+
+ // check initializations
+ ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ForwardProjection", "Projector Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "ForwardProjection", "Projection Data Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "ForwardProjection", "Volume Data Object Not Initialized.");
+
+ // check compatibility between projector and data classes
+ ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "ForwardProjection", "Projection Data not compatible with the specified Projector.");
+ ASTRA_CONFIG_CHECK(m_pVolume->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "ForwardProjection", "Volume Data not compatible with the specified Projector.");
+
+ ASTRA_CONFIG_CHECK(m_pForwardProjector, "ForwardProjection", "Invalid FP Policy");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CForwardProjectionAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // projector
+ XMLNode* node = _cfg.self->getSingleNode("ProjectorId");
+ ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No ProjectorId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pProjector = CProjector2DManager::getSingleton().get(id);
+ ASTRA_DELETE(node);
+
+ // sinogram data
+ node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No ProjectionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+
+ // volume data
+ node = _cfg.self->getSingleNode("VolumeDataId");
+ ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No VolumeDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pVolume = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+
+ // volume mask
+ if (_cfg.self->hasOption("VolumeMaskId")) {
+ m_bUseVolumeMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("VolumeMaskId"));
+ m_pVolumeMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ }
+
+ // sino mask
+ if (_cfg.self->hasOption("SinogramMaskId")) {
+ m_bUseSinogramMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId"));
+ m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ }
+
+ // ray or voxel-driven projector?
+ //m_bUseVoxelProjector = _cfg.self->getOptionBool("VoxelDriven", false);
+
+ // init data projector
+ _init();
+
+ // return success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Get Information - all
+map<string,boost::any> CForwardProjectionAlgorithm::getInformation()
+{
+ map<string, boost::any> result;
+ result["ProjectorId"] = getInformation("ProjectorId");
+ result["ProjectionDataId"] = getInformation("ProjectionDataId");
+ result["VolumeDataId"] = getInformation("VolumeDataId");
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), result);
+};
+
+//---------------------------------------------------------------------------------------
+// Get Information - specific
+boost::any CForwardProjectionAlgorithm::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "ProjectorId") {
+ int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ } else if (_sIdentifier == "ProjectionDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ } else if (_sIdentifier == "VolumeDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pVolume);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Initialize
+bool CForwardProjectionAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32VolumeData2D* _pVolume,
+ CFloat32ProjectionData2D* _pSinogram)
+{
+ // store classes
+ m_pProjector = _pProjector;
+ m_pVolume = _pVolume;
+ m_pSinogram = _pSinogram;
+
+ // init data projector
+ _init();
+
+ // return success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize Data Projectors - private
+void CForwardProjectionAlgorithm::_init()
+{
+ // forward projection data projector
+ m_pForwardProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pVolumeMask), // reconstruction mask
+ DefaultFPPolicy(m_pVolume, m_pSinogram), // forward projection
+ m_bUseSinogramMask, m_bUseVolumeMask, true // options on/off
+ );
+}
+
+//----------------------------------------------------------------------------------------
+// Set Fixed Reconstruction Mask
+void CForwardProjectionAlgorithm::setVolumeMask(CFloat32VolumeData2D* _pMask, bool _bEnable)
+{
+ // TODO: check geometry matches volume
+ m_bUseVolumeMask = _bEnable;
+ m_pVolumeMask = _pMask;
+ if (m_pVolumeMask == NULL) {
+ m_bUseVolumeMask = false;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Set Fixed Sinogram Mask
+void CForwardProjectionAlgorithm::setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable)
+{
+ // TODO: check geometry matches sinogram
+ m_bUseSinogramMask = _bEnable;
+ m_pSinogramMask = _pMask;
+ if (m_pSinogramMask == NULL) {
+ m_bUseSinogramMask = false;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CForwardProjectionAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ m_pSinogram->setData(0.0f);
+
+// if (m_bUseVoxelProjector) {
+// m_pForwardProjector->projectAllVoxels();
+// } else {
+ m_pForwardProjector->project();
+// }
+
+}
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/Fourier.cpp b/src/Fourier.cpp
new file mode 100644
index 0000000..0f7da28
--- /dev/null
+++ b/src/Fourier.cpp
@@ -0,0 +1,233 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Fourier.h"
+
+namespace astra {
+
+
+void discreteFourierTransform1D(unsigned int iLength,
+ const float32* pfRealIn,
+ const float32* pfImaginaryIn,
+ float32* pfRealOut,
+ float32* pfImaginaryOut,
+ unsigned int iStrideIn,
+ unsigned int iStrideOut,
+ bool inverse)
+{
+ for (unsigned int w = 0; w < iLength; w++)
+ {
+ pfRealOut[iStrideOut*w] = pfImaginaryOut[iStrideOut*w] = 0;
+ for (unsigned int y = 0; y < iLength; y++)
+ {
+ float32 a = 2 * PI * w * y / float32(iLength);
+ if (!inverse)
+ a = -a;
+ float32 ca = cos(a);
+ float32 sa = sin(a);
+ pfRealOut[iStrideOut*w] += pfRealIn[iStrideIn*y] * ca - pfImaginaryIn[iStrideIn*y] * sa;
+ pfImaginaryOut[iStrideOut*w] += pfRealIn[iStrideIn*y] * sa + pfImaginaryIn[iStrideIn*y] * ca;
+ }
+ }
+
+ if (inverse) {
+ for (unsigned int x = 0; x < iLength; ++x) {
+ pfRealOut[iStrideOut*x] /= iLength;
+ pfImaginaryOut[iStrideOut*x] /= iLength;
+ }
+ }
+}
+
+void discreteFourierTransform2D(unsigned int iHeight, unsigned int iWidth,
+ const float32* pfRealIn,
+ const float32* pfImaginaryIn,
+ float32* pfRealOut,
+ float32* pfImaginaryOut,
+ bool inverse)
+{
+ float32* reTemp = new float32[iWidth * iHeight];
+ float32* imTemp = new float32[iWidth * iHeight];
+
+ //calculate the fourier transform of the columns
+ for (unsigned int x = 0; x < iWidth; x++)
+ {
+ discreteFourierTransform1D(iHeight, pfRealIn+x, pfImaginaryIn+x,
+ reTemp+x, imTemp+x,
+ iWidth, iWidth, inverse);
+ }
+
+ //calculate the fourier transform of the rows
+ for(unsigned int y = 0; y < iHeight; y++)
+ {
+ discreteFourierTransform1D(iWidth,
+ reTemp+y*iWidth,
+ imTemp+y*iWidth,
+ pfRealOut+y*iWidth,
+ pfImaginaryOut+y*iWidth,
+ 1, 1, inverse);
+ }
+
+ delete[] reTemp;
+ delete[] imTemp;
+}
+
+/** permute the entries from pfDataIn into pfDataOut to prepare for an
+ * in-place FFT. pfDataIn may be equal to pfDataOut.
+ */
+static void bitReverse(unsigned int iLength,
+ const float32* pfDataIn, float32* pfDataOut,
+ unsigned int iStrideShiftIn,
+ unsigned int iStrideShiftOut)
+{
+ if (pfDataIn == pfDataOut) {
+ assert(iStrideShiftIn == iStrideShiftOut);
+ float32 t;
+ unsigned int j = 0;
+ for(unsigned int i = 0; i < iLength - 1; i++) {
+ if (i < j) {
+ t = pfDataOut[i<<iStrideShiftOut];
+ pfDataOut[i<<iStrideShiftOut] = pfDataOut[j<<iStrideShiftOut];
+ pfDataOut[j<<iStrideShiftOut] = t;
+ }
+ unsigned int k = iLength / 2;
+ while (k <= j) {
+ j -= k;
+ k /= 2;
+ }
+ j += k;
+ }
+ } else {
+ unsigned int j = 0;
+ for(unsigned int i = 0; i < iLength - 1; i++) {
+ pfDataOut[i<<iStrideShiftOut] = pfDataIn[j<<iStrideShiftIn];
+ unsigned int k = iLength / 2;
+ while (k <= j) {
+ j -= k;
+ k /= 2;
+ }
+ j += k;
+ }
+ pfDataOut[(iLength-1)<<iStrideShiftOut] = pfDataIn[(iLength-1)<<iStrideShiftOut];
+ }
+}
+
+static unsigned int log2(unsigned int n)
+{
+ unsigned int l = 0;
+ while (n > 1) {
+ n /= 2;
+ ++l;
+ }
+ return l;
+}
+
+/** perform 1D FFT. iLength, iStrideIn, iStrideOut must be powers of two. */
+void fastTwoPowerFourierTransform1D(unsigned int iLength,
+ const float32* pfRealIn,
+ const float32* pfImaginaryIn,
+ float32* pfRealOut,
+ float32* pfImaginaryOut,
+ unsigned int iStrideIn,
+ unsigned int iStrideOut,
+ bool inverse)
+{
+ unsigned int iStrideShiftIn = log2(iStrideIn);
+ unsigned int iStrideShiftOut = log2(iStrideOut);
+ unsigned int iLogLength = log2(iLength);
+
+ bitReverse(iLength, pfRealIn, pfRealOut, iStrideShiftIn, iStrideShiftOut);
+ bitReverse(iLength, pfImaginaryIn, pfImaginaryOut, iStrideShiftIn, iStrideShiftOut);
+
+ float32 ca = -1.0;
+ float32 sa = 0.0;
+ unsigned int l1 = 1, l2 = 1;
+ for(unsigned int l=0; l < iLogLength; ++l)
+ {
+ l1 = l2;
+ l2 *= 2;
+ float32 u1 = 1.0;
+ float32 u2 = 0.0;
+ for(unsigned int j = 0; j < l1; j++)
+ {
+ for(unsigned int i = j; i < iLength; i += l2)
+ {
+ unsigned int i1 = i + l1;
+ float32 t1 = u1 * pfRealOut[i1<<iStrideShiftOut] - u2 * pfImaginaryOut[i1<<iStrideShiftOut];
+ float32 t2 = u1 * pfImaginaryOut[i1<<iStrideShiftOut] + u2 * pfRealOut[i1<<iStrideShiftOut];
+ pfRealOut[i1<<iStrideShiftOut] = pfRealOut[i<<iStrideShiftOut] - t1;
+ pfImaginaryOut[i1<<iStrideShiftOut] = pfImaginaryOut[i<<iStrideShiftOut] - t2;
+ pfRealOut[i<<iStrideShiftOut] += t1;
+ pfImaginaryOut[i<<iStrideShiftOut] += t2;
+ }
+ float32 z = u1 * ca - u2 * sa;
+ u2 = u1 * sa + u2 * ca;
+ u1 = z;
+ }
+ sa = sqrt((1.0 - ca) / 2.0);
+ if (!inverse)
+ sa = -sa;
+ ca = sqrt((1.0 + ca) / 2.0);
+ }
+
+ if (inverse) {
+ for (unsigned int i = 0; i < iLength; ++i) {
+ pfRealOut[i<<iStrideShiftOut] /= iLength;
+ pfImaginaryOut[i<<iStrideShiftOut] /= iLength;
+ }
+ }
+}
+
+void fastTwoPowerFourierTransform2D(unsigned int iHeight,
+ unsigned int iWidth,
+ const float32* pfRealIn,
+ const float32* pfImaginaryIn,
+ float32* pfRealOut,
+ float32* pfImaginaryOut,
+ bool inverse)
+{
+ //calculate the fourier transform of the columns
+ for (unsigned int x = 0; x < iWidth; x++)
+ {
+ fastTwoPowerFourierTransform1D(iHeight, pfRealIn+x, pfImaginaryIn+x,
+ pfRealOut+x, pfImaginaryOut+x,
+ iWidth, iWidth, inverse);
+ }
+
+ //calculate the fourier transform of the rows
+ for (unsigned int y = 0; y < iHeight; y++)
+ {
+ fastTwoPowerFourierTransform1D(iWidth,
+ pfRealOut+y*iWidth,
+ pfImaginaryOut+y*iWidth,
+ pfRealOut+y*iWidth,
+ pfImaginaryOut+y*iWidth,
+ 1, 1, inverse);
+ }
+}
+
+}
diff --git a/src/Globals.cpp b/src/Globals.cpp
new file mode 100644
index 0000000..7f93fae
--- /dev/null
+++ b/src/Globals.cpp
@@ -0,0 +1,32 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Globals.h"
+
+// nothing to see here :)
+
diff --git a/src/Logger.cpp b/src/Logger.cpp
new file mode 100644
index 0000000..28368b2
--- /dev/null
+++ b/src/Logger.cpp
@@ -0,0 +1,77 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <astra/Logger.h>
+
+using namespace astra;
+
+const char * g_loggerFileName = "astra_logger.txt";
+
+void CLogger::_assureIsInitialized()
+{
+ if(!m_bInitialized)
+ {
+ m_pOutFile = fopen(g_loggerFileName, "r");
+ if(m_pOutFile != NULL)
+ {
+ // file exists, users wants to log
+ fclose(m_pOutFile);
+ m_pOutFile = fopen(g_loggerFileName, "w");
+ }
+
+ m_bInitialized = true;
+ }
+}
+
+void CLogger::writeLine(const char * _text)
+{
+ _assureIsInitialized();
+
+ if(m_pOutFile != NULL)
+ {
+ fprintf(m_pOutFile, "%s\n", _text);
+ fflush(m_pOutFile);
+ }
+}
+
+void CLogger::writeTerminalCUDAError(const char * _fileName, int _iLine, const char * _errString)
+{
+ char buffer[256];
+
+ sprintf(buffer, "Cuda error in file '%s' in line %i : %s.", _fileName, _iLine, _errString);
+
+ writeLine(buffer);
+}
+
+CLogger::CLogger()
+{
+ ;
+}
+
+FILE * CLogger::m_pOutFile = NULL;
+bool CLogger::m_bInitialized = false;
diff --git a/src/ParallelBeamBlobKernelProjector2D.cpp b/src/ParallelBeamBlobKernelProjector2D.cpp
new file mode 100644
index 0000000..e08f616
--- /dev/null
+++ b/src/ParallelBeamBlobKernelProjector2D.cpp
@@ -0,0 +1,271 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ParallelBeamBlobKernelProjector2D.h"
+
+#include <cmath>
+#include <boost/lexical_cast.hpp>
+
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+using namespace astra;
+
+#include "astra/ParallelBeamBlobKernelProjector2D.inl"
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CParallelBeamBlobKernelProjector2D::type = "blob";
+
+//----------------------------------------------------------------------------------------
+// default constructor
+CParallelBeamBlobKernelProjector2D::CParallelBeamBlobKernelProjector2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// constructor
+CParallelBeamBlobKernelProjector2D::CParallelBeamBlobKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry,
+ float32 _fBlobSize,
+ float32 _fBlobSampleRate,
+ int _iBlobSampleCount,
+ float32* _pfBlobValues)
+{
+ _clear();
+ initialize(_pProjectionGeometry, _pReconstructionGeometry, _fBlobSize, _fBlobSampleRate, _iBlobSampleCount, _pfBlobValues);
+}
+
+//----------------------------------------------------------------------------------------
+// destructor
+CParallelBeamBlobKernelProjector2D::~CParallelBeamBlobKernelProjector2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CParallelBeamBlobKernelProjector2D::_clear()
+{
+ CProjector2D::_clear();
+ m_pfBlobValues = NULL;
+ m_iBlobSampleCount = 0;
+ m_fBlobSize = 0;
+ m_fBlobSampleRate = 0;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CParallelBeamBlobKernelProjector2D::clear()
+{
+ CProjector2D::clear();
+ if (m_pfBlobValues) {
+ delete[] m_pfBlobValues;
+ m_pfBlobValues = NULL;
+ }
+ m_iBlobSampleCount = 0;
+ m_fBlobSize = 0;
+ m_fBlobSampleRate = 0;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CParallelBeamBlobKernelProjector2D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamBlobKernelProjector2D", "Error in Projector2D initialization");
+
+ ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamBlobKernelProjector2D", "Unsupported projection geometry");
+
+ ASTRA_CONFIG_CHECK(m_iBlobSampleCount > 0, "ParallelBeamBlobKernelProjector2D", "m_iBlobSampleCount should be strictly positive.");
+ ASTRA_CONFIG_CHECK(m_pfBlobValues, "ParallelBeamBlobKernelProjector2D", "Invalid Volume Geometry Object.");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CParallelBeamBlobKernelProjector2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // required: Kernel
+ XMLNode* node = _cfg.self->getSingleNode("Kernel");
+ ASTRA_CONFIG_CHECK(node, "BlobProjector", "No Kernel tag specified.");
+ {
+ // Required: KernelSize
+ XMLNode* node2 = node->getSingleNode("KernelSize");
+ ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelSize tag specified.");
+ m_fBlobSize = boost::lexical_cast<float32>(node2->getContent());
+
+ // Required: SampleRate
+ node2 = node->getSingleNode("SampleRate");
+ ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/SampleRate tag specified.");
+ m_fBlobSampleRate = boost::lexical_cast<float32>(node2->getContent());
+
+ // Required: SampleCount
+ node2 = node->getSingleNode("SampleCount");
+ ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/SampleCount tag specified.");
+ m_iBlobSampleCount = boost::lexical_cast<int>(node2->getContent());
+
+ // Required: KernelValues
+ node2 = node->getSingleNode("KernelValues");
+ ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelValues tag specified.");
+ vector<float32> values = node2->getContentNumericalArray();
+ ASTRA_CONFIG_CHECK(values.size() == (unsigned int)m_iBlobSampleCount, "BlobProjector", "Number of specified values doesn't match SampleCount.");
+ m_pfBlobValues = new float32[m_iBlobSampleCount];
+ for (int i = 0; i < m_iBlobSampleCount; i++) {
+ m_pfBlobValues[i] = values[i];
+ }
+
+ // Required: KernelValues
+ node2 = node->getSingleNode("KernelValuesNeg");
+ ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelValuesNeg tag specified.");
+ vector<float32> values2 = node2->getContentNumericalArray();
+ ASTRA_CONFIG_CHECK(values2.size() == (unsigned int)m_iBlobSampleCount, "BlobProjector", "Number of specified values doesn't match SampleCount.");
+ m_pfBlobValuesNeg = new float32[m_iBlobSampleCount];
+ for (int i = 0; i < m_iBlobSampleCount; i++) {
+ m_pfBlobValuesNeg[i] = values2[i];
+ }
+
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// initialize
+bool CParallelBeamBlobKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry,
+ float32 _fBlobSize,
+ float32 _fBlobSampleRate,
+ int _iBlobSampleCount,
+ float32* _pfBlobValues)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ ASTRA_CONFIG_CHECK(_pProjectionGeometry, "BlobProjector", "Invalid ProjectionGeometry Object");
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "BlobProjector", "Invalid ProjectionGeometry Object");
+ m_pProjectionGeometry = _pProjectionGeometry->clone();
+ m_pVolumeGeometry = _pVolumeGeometry->clone();
+ m_fBlobSize = _fBlobSize;
+ m_fBlobSampleRate = _fBlobSampleRate;
+ m_iBlobSampleCount = _iBlobSampleCount;
+ m_pfBlobValues = new float32[_iBlobSampleCount];
+ for (int i = 0; i <_iBlobSampleCount; i++) {
+ m_pfBlobValues[i] = _pfBlobValues[i];
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Get maximum amount of weights on a single ray
+int CParallelBeamBlobKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex)
+{
+ int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount());
+ return (int)(maxDim * 2 * (m_fBlobSize+2) + 1);
+}
+//----------------------------------------------------------------------------------------
+// Single Ray Weights
+void CParallelBeamBlobKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+ StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount);
+ projectSingleRay(_iProjectionIndex, _iDetectorIndex, p);
+ _iStoredPixelCount = p.getStoredPixelCount();
+}
+//----------------------------------------------------------------------------------------
+// Splat a single point
+std::vector<SDetector2D> CParallelBeamBlobKernelProjector2D::projectPoint(int _iRow, int _iCol)
+{
+ float32 x = m_pVolumeGeometry->pixelColToCenterX(_iCol);
+ float32 y = m_pVolumeGeometry->pixelRowToCenterY(_iRow);
+
+ std::vector<SDetector2D> res;
+ // loop projectors and detectors
+ for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) {
+
+ // get projection angle
+ float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection);
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ bool inverse = false;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ inverse = true;
+ }
+
+ // calculate distance from the center of the voxel to the ray though the origin
+ float32 t = x * cos(theta) + y * sin(theta);
+ if (inverse) t *= -1.0f;
+
+ // calculate the offset on the detectorarray (in indices)
+ float32 d = m_pProjectionGeometry->detectorOffsetToIndexFloat(t);
+ int dmin = (int)ceil(d - m_fBlobSize);
+ int dmax = (int)floor(d + m_fBlobSize);
+
+ // add affected detectors to the list
+ for (int i = dmin; i <= dmax; ++i) {
+ if (d >= 0 && d < m_pProjectionGeometry->getDetectorCount()) {
+ SDetector2D det;
+ det.m_iAngleIndex = iProjection;
+ det.m_iDetectorIndex = i;
+ det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i;
+ res.push_back(det);
+ }
+ }
+ }
+
+ // return result vector
+ return res;
+
+}
diff --git a/src/ParallelBeamLineKernelProjector2D.cpp b/src/ParallelBeamLineKernelProjector2D.cpp
new file mode 100644
index 0000000..16cc614
--- /dev/null
+++ b/src/ParallelBeamLineKernelProjector2D.cpp
@@ -0,0 +1,222 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ParallelBeamLineKernelProjector2D.h"
+
+#include <cmath>
+#include <boost/lexical_cast.hpp>
+
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+using namespace astra;
+
+#include "astra/ParallelBeamLineKernelProjector2D.inl"
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CParallelBeamLineKernelProjector2D::type = "line";
+
+//----------------------------------------------------------------------------------------
+// default constructor
+CParallelBeamLineKernelProjector2D::CParallelBeamLineKernelProjector2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// constructor
+CParallelBeamLineKernelProjector2D::CParallelBeamLineKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry)
+
+{
+ _clear();
+ initialize(_pProjectionGeometry, _pReconstructionGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// destructor
+CParallelBeamLineKernelProjector2D::~CParallelBeamLineKernelProjector2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CParallelBeamLineKernelProjector2D::_clear()
+{
+ CProjector2D::_clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CParallelBeamLineKernelProjector2D::clear()
+{
+ CProjector2D::clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CParallelBeamLineKernelProjector2D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamLineKernelProjector2D", "Error in Projector2D initialization");
+
+ ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamLineKernelProjector2D", "Unsupported projection geometry");
+
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamLineKernelProjector2D", "Pixel height must equal pixel width.");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CParallelBeamLineKernelProjector2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize
+bool CParallelBeamLineKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // hardcopy geometries
+ m_pProjectionGeometry = _pProjectionGeometry->clone();
+ m_pVolumeGeometry = _pVolumeGeometry->clone();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Get maximum amount of weights on a single ray
+int CParallelBeamLineKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex)
+{
+ int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount());
+ return maxDim * 2 + 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Single Ray Weights
+void CParallelBeamLineKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+ StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount);
+ projectSingleRay(_iProjectionIndex, _iDetectorIndex, p);
+ _iStoredPixelCount = p.getStoredPixelCount();
+}
+
+//----------------------------------------------------------------------------------------
+// Project Point
+std::vector<SDetector2D> CParallelBeamLineKernelProjector2D::projectPoint(int _iRow, int _iCol)
+{
+ float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+
+ std::vector<SDetector2D> res;
+ // loop projectors and detectors
+ for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) {
+
+ // get projection angle
+ float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection);
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ bool inverse = false;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ inverse = true;
+ }
+
+ // calculate distance from the center of the voxel to the ray though the origin
+ float32 tUL = xUL * cos(theta) + yUL * sin(theta);
+ float32 tUR = xUR * cos(theta) + yUR * sin(theta);
+ float32 tLL = xLL * cos(theta) + yLL * sin(theta);
+ float32 tLR = xLR * cos(theta) + yLR * sin(theta);
+ if (inverse) {
+ tUL *= -1.0f;
+ tUR *= -1.0f;
+ tLL *= -1.0f;
+ tLR *= -1.0f;
+ }
+ float32 tMin = min(tUL, min(tUR, min(tLL,tLR)));
+ float32 tMax = max(tUL, max(tUR, max(tLL,tLR)));
+
+ // calculate the offset on the detectorarray (in indices)
+ int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin));
+ int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax));
+
+ // add affected detectors to the list
+ for (int i = dmin; i <= dmax; ++i) {
+ if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) {
+ SDetector2D det;
+ det.m_iAngleIndex = iProjection;
+ det.m_iDetectorIndex = i;
+ det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i;
+ res.push_back(det);
+ }
+ }
+ }
+
+ // return result vector
+ return res;
+
+}
+
+//----------------------------------------------------------------------------------------
diff --git a/src/ParallelBeamLinearKernelProjector2D.cpp b/src/ParallelBeamLinearKernelProjector2D.cpp
new file mode 100644
index 0000000..5f1679d
--- /dev/null
+++ b/src/ParallelBeamLinearKernelProjector2D.cpp
@@ -0,0 +1,222 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ParallelBeamLinearKernelProjector2D.h"
+
+#include <cmath>
+#include <boost/lexical_cast.hpp>
+
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+using namespace astra;
+
+#include "astra/ParallelBeamLinearKernelProjector2D.inl"
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CParallelBeamLinearKernelProjector2D::type = "linear";
+
+//----------------------------------------------------------------------------------------
+// default constructor
+CParallelBeamLinearKernelProjector2D::CParallelBeamLinearKernelProjector2D()
+{
+ _clear();
+}
+
+
+//----------------------------------------------------------------------------------------
+// constructor
+CParallelBeamLinearKernelProjector2D::CParallelBeamLinearKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry)
+
+{
+ _clear();
+ initialize(_pProjectionGeometry, _pReconstructionGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// destructor
+CParallelBeamLinearKernelProjector2D::~CParallelBeamLinearKernelProjector2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - CParallelBeamLinearKernelProjector2D
+void CParallelBeamLinearKernelProjector2D::_clear()
+{
+ CProjector2D::_clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CParallelBeamLinearKernelProjector2D::clear()
+{
+ CProjector2D::clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CParallelBeamLinearKernelProjector2D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamLinearKernelProjector2D", "Error in Projector2D initialization");
+
+ ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamLinearKernelProjector2D", "Unsupported projection geometry");
+
+ /// TODO: ADD PIXEL H/W LIMITATIONS
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamLinearKernelProjector2D", "Pixel height must equal pixel width.");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CParallelBeamLinearKernelProjector2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize
+bool CParallelBeamLinearKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // hardcopy geometries
+ m_pProjectionGeometry = _pProjectionGeometry->clone();
+ m_pVolumeGeometry = _pVolumeGeometry->clone();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Get maximum amount of weights on a single ray
+int CParallelBeamLinearKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex)
+{
+ int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount());
+ return maxDim * 2 + 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Single Ray Weights
+void CParallelBeamLinearKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+ StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount);
+ projectSingleRay(_iProjectionIndex, _iDetectorIndex, p);
+ _iStoredPixelCount = p.getStoredPixelCount();
+}
+
+//----------------------------------------------------------------------------------------
+// Splat a single point
+std::vector<SDetector2D> CParallelBeamLinearKernelProjector2D::projectPoint(int _iRow, int _iCol)
+{
+ float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 1.5f;
+ float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 1.5f;
+ float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 1.5f;
+ float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 1.5f;
+ float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 1.5f;
+ float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 1.5f;
+ float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 1.5f;
+ float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 1.5f;
+
+ std::vector<SDetector2D> res;
+ // loop projectors and detectors
+ for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) {
+
+ // get projection angle
+ float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection);
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ bool inverse = false;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ inverse = true;
+ }
+
+ // calculate distance from the center of the voxel to the ray though the origin
+ float32 tUL = xUL * cos(theta) + yUL * sin(theta);
+ float32 tUR = xUR * cos(theta) + yUR * sin(theta);
+ float32 tLL = xLL * cos(theta) + yLL * sin(theta);
+ float32 tLR = xLR * cos(theta) + yLR * sin(theta);
+ if (inverse) {
+ tUL *= -1.0f;
+ tUR *= -1.0f;
+ tLL *= -1.0f;
+ tLR *= -1.0f;
+ }
+ float32 tMin = min(tUL, min(tUR, min(tLL,tLR)));
+ float32 tMax = max(tUL, max(tUR, max(tLL,tLR)));
+
+ // calculate the offset on the detectorarray (in indices)
+ int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin));
+ int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax));
+
+ // add affected detectors to the list
+ for (int i = dmin; i <= dmax; ++i) {
+ if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) {
+ SDetector2D det;
+ det.m_iAngleIndex = iProjection;
+ det.m_iDetectorIndex = i;
+ det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i;
+ res.push_back(det);
+ }
+ }
+ }
+
+ // return result vector
+ return res;
+
+}
diff --git a/src/ParallelBeamStripKernelProjector2D.cpp b/src/ParallelBeamStripKernelProjector2D.cpp
new file mode 100644
index 0000000..78997af
--- /dev/null
+++ b/src/ParallelBeamStripKernelProjector2D.cpp
@@ -0,0 +1,224 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ParallelBeamStripKernelProjector2D.h"
+
+#include <cmath>
+#include <boost/lexical_cast.hpp>
+
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+using namespace astra;
+
+#include "astra/ParallelBeamStripKernelProjector2D.inl"
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CParallelBeamStripKernelProjector2D::type = "strip";
+
+//----------------------------------------------------------------------------------------
+// default constructor
+CParallelBeamStripKernelProjector2D::CParallelBeamStripKernelProjector2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// constructor
+CParallelBeamStripKernelProjector2D::CParallelBeamStripKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry)
+
+{
+ _clear();
+ initialize(_pProjectionGeometry, _pReconstructionGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// destructor
+CParallelBeamStripKernelProjector2D::~CParallelBeamStripKernelProjector2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CParallelBeamStripKernelProjector2D::_clear()
+{
+ CProjector2D::_clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CParallelBeamStripKernelProjector2D::clear()
+{
+ CProjector2D::clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CParallelBeamStripKernelProjector2D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamStripKernelProjector2D", "Error in Projector2D initialization");
+
+ ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamStripKernelProjector2D", "Unsupported projection geometry");
+
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamStripKernelProjector2D", "Pixel height must equal pixel width.");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CParallelBeamStripKernelProjector2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize
+bool CParallelBeamStripKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // hardcopy geometries
+ m_pProjectionGeometry = _pProjectionGeometry->clone();
+ m_pVolumeGeometry = _pVolumeGeometry->clone();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Get maximum amount of weights on a single ray
+int CParallelBeamStripKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex)
+{
+ int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount());
+ int scale = m_pProjectionGeometry->getDetectorWidth() / min(m_pVolumeGeometry->getPixelLengthX(), m_pVolumeGeometry->getPixelLengthY());
+ return maxDim * scale * 10 + 1;
+}
+
+//----------------------------------------------------------------------------------------
+// Single Ray Weights
+void CParallelBeamStripKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount)
+{
+ ASTRA_ASSERT(m_bIsInitialized);
+ StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount);
+ projectSingleRay(_iProjectionIndex, _iDetectorIndex, p);
+ _iStoredPixelCount = p.getStoredPixelCount();
+}
+
+//----------------------------------------------------------------------------------------
+// Splat a single point
+std::vector<SDetector2D> CParallelBeamStripKernelProjector2D::projectPoint(int _iRow, int _iCol)
+{
+ float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+ float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f;
+ float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f;
+
+ std::vector<SDetector2D> res;
+ // loop projectors and detectors
+ for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) {
+
+ // get projection angle
+ float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection);
+ if (theta >= 7*PIdiv4) theta -= 2*PI;
+ bool inverse = false;
+ if (theta >= 3*PIdiv4) {
+ theta -= PI;
+ inverse = true;
+ }
+
+ // calculate distance from the center of the voxel to the ray though the origin
+ float32 tUL = xUL * cos(theta) + yUL * sin(theta);
+ float32 tUR = xUR * cos(theta) + yUR * sin(theta);
+ float32 tLL = xLL * cos(theta) + yLL * sin(theta);
+ float32 tLR = xLR * cos(theta) + yLR * sin(theta);
+ if (inverse) {
+ tUL *= -1.0f;
+ tUR *= -1.0f;
+ tLL *= -1.0f;
+ tLR *= -1.0f;
+ }
+ float32 tMin = min(tUL, min(tUR, min(tLL,tLR)));
+ float32 tMax = max(tUL, max(tUR, max(tLL,tLR)));
+
+ // calculate the offset on the detectorarray (in indices)
+ int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin));
+ int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax));
+
+ // add affected detectors to the list
+ for (int i = dmin; i <= dmax; ++i) {
+ if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) {
+ SDetector2D det;
+ det.m_iAngleIndex = iProjection;
+ det.m_iDetectorIndex = i;
+ det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i;
+ res.push_back(det);
+ }
+ }
+ }
+
+ // return result vector
+ return res;
+
+}
+
+//----------------------------------------------------------------------------------------
diff --git a/src/ParallelProjectionGeometry2D.cpp b/src/ParallelProjectionGeometry2D.cpp
new file mode 100644
index 0000000..79a325b
--- /dev/null
+++ b/src/ParallelProjectionGeometry2D.cpp
@@ -0,0 +1,186 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ParallelProjectionGeometry2D.h"
+
+#include <cstring>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CParallelProjectionGeometry2D::CParallelProjectionGeometry2D() :
+ CProjectionGeometry2D()
+{
+
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CParallelProjectionGeometry2D::CParallelProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsets)
+{
+ _clear();
+ initialize(_iProjectionAngleCount,
+ _iDetectorCount,
+ _fDetectorWidth,
+ _pfProjectionAngles,
+ _pfExtraDetectorOffsets);
+}
+
+//----------------------------------------------------------------------------------------
+CParallelProjectionGeometry2D::CParallelProjectionGeometry2D(const CParallelProjectionGeometry2D& _projGeom)
+{
+ _clear();
+ initialize(_projGeom.m_iProjectionAngleCount,
+ _projGeom.m_iDetectorCount,
+ _projGeom.m_fDetectorWidth,
+ _projGeom.m_pfProjectionAngles,
+ _projGeom.m_pfExtraDetectorOffset);
+}
+
+//----------------------------------------------------------------------------------------
+
+CParallelProjectionGeometry2D& CParallelProjectionGeometry2D::operator=(const CParallelProjectionGeometry2D& _other)
+{
+ if (m_bInitialized)
+ delete[] m_pfProjectionAngles;
+ m_bInitialized = _other.m_bInitialized;
+ if (_other.m_bInitialized) {
+ m_iProjectionAngleCount = _other.m_iProjectionAngleCount;
+ m_iDetectorCount = _other.m_iDetectorCount;
+ m_fDetectorWidth = _other.m_fDetectorWidth;
+ m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ memcpy(m_pfProjectionAngles, _other.m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount);
+ }
+ return *this;
+
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CParallelProjectionGeometry2D::~CParallelProjectionGeometry2D()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CParallelProjectionGeometry2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry2D> CC("ParallelProjectionGeometry2D", this, _cfg);
+
+
+ // initialization of parent class
+ CProjectionGeometry2D::initialize(_cfg);
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CParallelProjectionGeometry2D::initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsets)
+{
+ _initialize(_iProjectionAngleCount,
+ _iDetectorCount,
+ _fDetectorWidth,
+ _pfProjectionAngles,
+ _pfExtraDetectorOffsets);
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CProjectionGeometry2D* CParallelProjectionGeometry2D::clone()
+{
+ return new CParallelProjectionGeometry2D(*this);
+}
+
+//----------------------------------------------------------------------------------------
+// is equal
+bool CParallelProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // try to cast argument to CParallelProjectionGeometry2D
+ CParallelProjectionGeometry2D* pGeom2 = dynamic_cast<CParallelProjectionGeometry2D*>(_pGeom2);
+ if (pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false;
+ if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false;
+ if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false;
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ // if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// is of type
+bool CParallelProjectionGeometry2D::isOfType(const std::string& _sType)
+{
+ return (_sType == "parallel");
+}
+//----------------------------------------------------------------------------------------
+
+CVector3D CParallelProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */)
+{
+ CVector3D vOutput;
+
+ float32 fProjectionAngle = getProjectionAngle(_iProjectionIndex);
+
+ vOutput.setX(cosf(fProjectionAngle));
+ vOutput.setY(sinf(fProjectionAngle));
+ vOutput.setZ(0.0f);
+
+ return vOutput;
+}
+
+} // end namespace astra
diff --git a/src/ParallelProjectionGeometry3D.cpp b/src/ParallelProjectionGeometry3D.cpp
new file mode 100644
index 0000000..c0366bc
--- /dev/null
+++ b/src/ParallelProjectionGeometry3D.cpp
@@ -0,0 +1,211 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ParallelProjectionGeometry3D.h"
+
+#include <cstring>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CParallelProjectionGeometry3D::CParallelProjectionGeometry3D() :
+ CProjectionGeometry3D()
+{
+
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CParallelProjectionGeometry3D::CParallelProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorWidth,
+ float32 _fDetectorHeight,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsetsX,
+ const float32* _pfExtraDetectorOffsetsY) :
+ CProjectionGeometry3D()
+{
+ initialize(_iProjectionAngleCount,
+ _iDetectorRowCount,
+ _iDetectorColCount,
+ _fDetectorWidth,
+ _fDetectorHeight,
+ _pfProjectionAngles,
+ _pfExtraDetectorOffsetsX,
+ _pfExtraDetectorOffsetsY);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CParallelProjectionGeometry3D::~CParallelProjectionGeometry3D()
+{
+
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CParallelProjectionGeometry3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry3D> CC("ParallelProjectionGeometry3D", this, _cfg);
+
+
+ // initialization of parent class
+ CProjectionGeometry3D::initialize(_cfg);
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CParallelProjectionGeometry3D::initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorWidth,
+ float32 _fDetectorHeight,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsetsX,
+ const float32* _pfExtraDetectorOffsetsY)
+{
+ _initialize(_iProjectionAngleCount,
+ _iDetectorRowCount,
+ _iDetectorColCount,
+ _fDetectorWidth,
+ _fDetectorHeight,
+ _pfProjectionAngles,
+ _pfExtraDetectorOffsetsX,
+ _pfExtraDetectorOffsetsY);
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CProjectionGeometry3D* CParallelProjectionGeometry3D::clone() const
+{
+ CParallelProjectionGeometry3D* res = new CParallelProjectionGeometry3D();
+ res->m_bInitialized = m_bInitialized;
+ res->m_iProjectionAngleCount = m_iProjectionAngleCount;
+ res->m_iDetectorRowCount = m_iDetectorRowCount;
+ res->m_iDetectorColCount = m_iDetectorColCount;
+ res->m_iDetectorTotCount = m_iDetectorTotCount;
+ res->m_fDetectorSpacingX = m_fDetectorSpacingX;
+ res->m_fDetectorSpacingY = m_fDetectorSpacingY;
+ res->m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ memcpy(res->m_pfProjectionAngles, m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount);
+ res->m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount];
+ memcpy(res->m_pfExtraDetectorOffsetsX, m_pfExtraDetectorOffsetsX, sizeof(float32)*m_iProjectionAngleCount);
+ res->m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount];
+ memcpy(res->m_pfExtraDetectorOffsetsY, m_pfExtraDetectorOffsetsY, sizeof(float32)*m_iProjectionAngleCount);
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// is equal
+bool CParallelProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // try to cast argument to CParallelProjectionGeometry3D
+ const CParallelProjectionGeometry3D* pGeom2 = dynamic_cast<const CParallelProjectionGeometry3D*>(_pGeom2);
+ if (pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false;
+ if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false;
+ if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false;
+ if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false;
+ if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false;
+ if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false;
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// is of type
+bool CParallelProjectionGeometry3D::isOfType(const std::string& _sType) const
+{
+ return (_sType == "parallel");
+}
+
+//----------------------------------------------------------------------------------------
+void CParallelProjectionGeometry3D::toXML(XMLNode* _sNode) const
+{
+ _sNode->addAttribute("type","parallel3d");
+ _sNode->addChildNode("DetectorSpacingX", m_fDetectorSpacingX);
+ _sNode->addChildNode("DetectorSpacingY", m_fDetectorSpacingY);
+ _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount);
+ _sNode->addChildNode("DetectorColCount", m_iDetectorColCount);
+ _sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount);
+ _sNode->addChildNode("ExtraDetectorOffsetsX", m_pfExtraDetectorOffsetsX, m_iProjectionAngleCount);
+ _sNode->addChildNode("ExtraDetectorOffsetsY", m_pfExtraDetectorOffsetsY, m_iProjectionAngleCount);
+}
+
+CVector3D CParallelProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const
+{
+ float fTheta = m_pfProjectionAngles[_iProjectionIndex];
+
+ float fDirX = cosf(fTheta);
+ float fDirY = sinf(fTheta);
+ float fDirZ = 0.0f;
+
+ return CVector3D(fDirX, fDirY, fDirZ);
+}
+
+CParallelProjectionGeometry2D * CParallelProjectionGeometry3D::createProjectionGeometry2D() const
+{
+ const float32 * pfProjectionAngles = getProjectionAngles(); //new float32[getProjectionCount()];
+ //getProjectionAngles(pfProjectionAngles);
+
+ CParallelProjectionGeometry2D * pOutput = new CParallelProjectionGeometry2D(getProjectionCount(),
+ getDetectorColCount(), getDetectorSpacingX(), pfProjectionAngles,getExtraDetectorOffsetsX());
+
+ //delete [] pfProjectionAngles;
+
+ return pOutput;
+}
+
+//----------------------------------------------------------------------------------------
+
+} // end namespace astra
diff --git a/src/ParallelVecProjectionGeometry3D.cpp b/src/ParallelVecProjectionGeometry3D.cpp
new file mode 100644
index 0000000..c1265dd
--- /dev/null
+++ b/src/ParallelVecProjectionGeometry3D.cpp
@@ -0,0 +1,230 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ParallelVecProjectionGeometry3D.h"
+
+#include <cstring>
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CParallelVecProjectionGeometry3D::CParallelVecProjectionGeometry3D() :
+ CProjectionGeometry3D()
+{
+ m_pProjectionAngles = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CParallelVecProjectionGeometry3D::CParallelVecProjectionGeometry3D(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ const SPar3DProjection* _pProjectionAngles
+ ) :
+ CProjectionGeometry3D()
+{
+ initialize(_iProjectionAngleCount,
+ _iDetectorRowCount,
+ _iDetectorColCount,
+ _pProjectionAngles);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CParallelVecProjectionGeometry3D::~CParallelVecProjectionGeometry3D()
+{
+ delete[] m_pProjectionAngles;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CParallelVecProjectionGeometry3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry3D> CC("ParallelVecProjectionGeometry3D", this, _cfg);
+
+ XMLNode* node;
+
+ // TODO: Fix up class hierarchy... this class doesn't fit very well.
+ // initialization of parent class
+ //CProjectionGeometry3D::initialize(_cfg);
+
+ // Required: DetectorRowCount
+ node = _cfg.self->getSingleNode("DetectorRowCount");
+ ASTRA_CONFIG_CHECK(node, "ParallelVecProjectionGeometry3D", "No DetectorRowCount tag specified.");
+ m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorRowCount");
+
+ // Required: DetectorCount
+ node = _cfg.self->getSingleNode("DetectorColCount");
+ ASTRA_CONFIG_CHECK(node, "", "No DetectorColCount tag specified.");
+ m_iDetectorColCount = boost::lexical_cast<int>(node->getContent());
+ m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount;
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorColCount");
+
+ // Required: Vectors
+ node = _cfg.self->getSingleNode("Vectors");
+ ASTRA_CONFIG_CHECK(node, "ParallelVecProjectionGeometry3D", "No Vectors tag specified.");
+ vector<double> data = node->getContentNumericalArrayDouble();
+ CC.markNodeParsed("Vectors");
+ ASTRA_DELETE(node);
+ ASTRA_CONFIG_CHECK(data.size() % 12 == 0, "ParallelVecProjectionGeometry3D", "Vectors doesn't consist of 12-tuples.");
+ m_iProjectionAngleCount = data.size() / 12;
+ m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount];
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ SPar3DProjection& p = m_pProjectionAngles[i];
+ p.fRayX = data[12*i + 0];
+ p.fRayY = data[12*i + 1];
+ p.fRayZ = data[12*i + 2];
+ p.fDetUX = data[12*i + 6];
+ p.fDetUY = data[12*i + 7];
+ p.fDetUZ = data[12*i + 8];
+ p.fDetVX = data[12*i + 9];
+ p.fDetVY = data[12*i + 10];
+ p.fDetVZ = data[12*i + 11];
+
+ // The backend code currently expects the corner of the detector, while
+ // the matlab interface supplies the center
+ p.fDetSX = data[12*i + 3] - 0.5f * m_iDetectorRowCount * p.fDetVX - 0.5f * m_iDetectorColCount * p.fDetUX;
+ p.fDetSY = data[12*i + 4] - 0.5f * m_iDetectorRowCount * p.fDetVY - 0.5f * m_iDetectorColCount * p.fDetUY;
+ p.fDetSZ = data[12*i + 5] - 0.5f * m_iDetectorRowCount * p.fDetVZ - 0.5f * m_iDetectorColCount * p.fDetUZ;
+ }
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CParallelVecProjectionGeometry3D::initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ const SPar3DProjection* _pProjectionAngles)
+{
+ m_iProjectionAngleCount = _iProjectionAngleCount;
+ m_iDetectorRowCount = _iDetectorRowCount;
+ m_iDetectorColCount = _iDetectorColCount;
+ m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount];
+ for (int i = 0; i < m_iProjectionAngleCount; ++i)
+ m_pProjectionAngles[i] = _pProjectionAngles[i];
+
+ // TODO: check?
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CProjectionGeometry3D* CParallelVecProjectionGeometry3D::clone() const
+{
+ CParallelVecProjectionGeometry3D* res = new CParallelVecProjectionGeometry3D();
+ res->m_bInitialized = m_bInitialized;
+ res->m_iProjectionAngleCount = m_iProjectionAngleCount;
+ res->m_iDetectorRowCount = m_iDetectorRowCount;
+ res->m_iDetectorColCount = m_iDetectorColCount;
+ res->m_iDetectorTotCount = m_iDetectorTotCount;
+ res->m_fDetectorSpacingX = m_fDetectorSpacingX;
+ res->m_fDetectorSpacingY = m_fDetectorSpacingY;
+ res->m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount];
+ memcpy(res->m_pProjectionAngles, m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount);
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// is equal
+bool CParallelVecProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // try to cast argument to CParallelProjectionGeometry3D
+ const CParallelVecProjectionGeometry3D* pGeom2 = dynamic_cast<const CParallelVecProjectionGeometry3D*>(_pGeom2);
+ if (pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false;
+ if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false;
+ if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false;
+ if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false;
+ //if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false;
+ //if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false;
+
+ for (int i = 0; i < m_iProjectionAngleCount; ++i) {
+ if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// is of type
+bool CParallelVecProjectionGeometry3D::isOfType(const std::string& _sType) const
+{
+ return (_sType == "parallel3d_vec");
+}
+
+//----------------------------------------------------------------------------------------
+void CParallelVecProjectionGeometry3D::toXML(XMLNode* _sNode) const
+{
+ _sNode->addAttribute("type","parallel3d_vec");
+ _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount);
+ _sNode->addChildNode("DetectorColCount", m_iDetectorColCount);
+ // TODO:
+ //_sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount);
+}
+
+CVector3D CParallelVecProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const
+{
+ const SPar3DProjection& p = m_pProjectionAngles[_iProjectionIndex];
+
+ return CVector3D(p.fRayX, p.fRayY, p.fRayZ);
+}
+
+
+//----------------------------------------------------------------------------------------
+
+bool CParallelVecProjectionGeometry3D::_check()
+{
+ // TODO
+ return true;
+}
+
+} // end namespace astra
diff --git a/src/PlatformDepSystemCode.cpp b/src/PlatformDepSystemCode.cpp
new file mode 100644
index 0000000..a628aeb
--- /dev/null
+++ b/src/PlatformDepSystemCode.cpp
@@ -0,0 +1,76 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/PlatformDepSystemCode.h"
+
+using namespace astra;
+
+#ifdef _WIN32
+#include "windows.h"
+// windows API available
+
+unsigned long CPlatformDepSystemCode::getMSCount()
+{
+ return ::GetTickCount();
+}
+
+int CPlatformDepSystemCode::fseek64(FILE * _pStream, astra::int64 _iOffset, int _iOrigin)
+{
+ return _fseeki64(_pStream, _iOffset, _iOrigin);
+}
+
+astra::int64 CPlatformDepSystemCode::ftell64(FILE * _pStream)
+{
+ return _ftelli64(_pStream);
+}
+
+#else
+// linux, ...
+
+#include <sys/time.h>
+
+unsigned long CPlatformDepSystemCode::getMSCount()
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return (tv.tv_sec * 1000) + (tv.tv_usec/1000);
+}
+
+int CPlatformDepSystemCode::fseek64(FILE * _pStream, astra::int64 _iOffset, int _iOrigin)
+{
+ return fseeko(_pStream, _iOffset, _iOrigin);
+}
+
+astra::int64 CPlatformDepSystemCode::ftell64(FILE * _pStream)
+{
+ return ftello(_pStream);
+}
+
+
+
+#endif
diff --git a/src/ProjectionGeometry2D.cpp b/src/ProjectionGeometry2D.cpp
new file mode 100644
index 0000000..982a1e4
--- /dev/null
+++ b/src/ProjectionGeometry2D.cpp
@@ -0,0 +1,203 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ProjectionGeometry2D.h"
+
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CProjectionGeometry2D::CProjectionGeometry2D() : configCheckData(0)
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CProjectionGeometry2D::CProjectionGeometry2D(int _iAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsets) : configCheckData(0)
+{
+ _clear();
+ _initialize(_iAngleCount, _iDetectorCount, _fDetectorWidth, _pfProjectionAngles,_pfExtraDetectorOffsets);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CProjectionGeometry2D::~CProjectionGeometry2D()
+{
+ if (m_bInitialized) {
+ clear();
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+// Should only be used by constructors. Otherwise use the clear() function.
+void CProjectionGeometry2D::_clear()
+{
+ m_iProjectionAngleCount = 0;
+ m_iDetectorCount = 0;
+ m_fDetectorWidth = 0.0f;
+ m_pfProjectionAngles = NULL;
+ m_pfExtraDetectorOffset = NULL;
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+void CProjectionGeometry2D::clear()
+{
+ m_iProjectionAngleCount = 0;
+ m_iDetectorCount = 0;
+ m_fDetectorWidth = 0.0f;
+ if (m_bInitialized){
+ delete[] m_pfProjectionAngles;
+ delete[] m_pfExtraDetectorOffset;
+ }
+ m_pfProjectionAngles = NULL;
+ m_pfExtraDetectorOffset = NULL;
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Check all variable values.
+bool CProjectionGeometry2D::_check()
+{
+ ASTRA_CONFIG_CHECK(m_iDetectorCount > 0, "ProjectionGeometry2D", "Detector Count should be positive.");
+ ASTRA_CONFIG_CHECK(m_fDetectorWidth > 0.0f, "ProjectionGeometry2D", "Detector Width should be positive.");
+ ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry2D", "ProjectionAngleCount should be positive.");
+ ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry2D", "ProjectionAngles not initialized");
+
+ // autofix: angles in [0,2pi[
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ while (2*PI <= m_pfProjectionAngles[i]) m_pfProjectionAngles[i] -= 2*PI;
+ while (m_pfProjectionAngles[i] < 0) m_pfProjectionAngles[i] += 2*PI;
+ }
+
+ // success
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization with a Config object
+bool CProjectionGeometry2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry2D> CC("ProjectionGeometry2D", this, _cfg);
+
+ // uninitialize if the object was initialized before
+ if (m_bInitialized) {
+ clear();
+ }
+
+ // Required: DetectorWidth
+ XMLNode* node = _cfg.self->getSingleNode("DetectorWidth");
+ ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No DetectorWidth tag specified.");
+ m_fDetectorWidth = boost::lexical_cast<float32>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorWidth");
+
+ // Required: DetectorCount
+ node = _cfg.self->getSingleNode("DetectorCount");
+ ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No DetectorCount tag specified.");
+ m_iDetectorCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorCount");
+
+ // Required: ProjectionAngles
+ node = _cfg.self->getSingleNode("ProjectionAngles");
+ ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No ProjectionAngles tag specified.");
+ vector<float32> angles = node->getContentNumericalArray();
+ delete node;
+ m_iProjectionAngleCount = angles.size();
+ ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry2D", "Not enough ProjectionAngles specified.");
+ m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfProjectionAngles[i] = angles[i];
+ }
+ CC.markNodeParsed("ProjectionAngles");
+
+ vector<float32> offset = _cfg.self->getOptionNumericalArray("ExtraDetectorOffset");
+ m_pfExtraDetectorOffset = new float32[m_iProjectionAngleCount];
+ if (offset.size() == (size_t)m_iProjectionAngleCount) {
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfExtraDetectorOffset[i] = offset[i];
+ }
+ } else {
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfExtraDetectorOffset[i] = 0.0f;
+ }
+ }
+ CC.markOptionParsed("ExtraDetectorOffset");
+
+ // some checks
+ ASTRA_CONFIG_CHECK(m_iDetectorCount > 0, "ProjectionGeometry2D", "DetectorCount should be positive.");
+ ASTRA_CONFIG_CHECK(m_fDetectorWidth > 0.0f, "ProjectionGeometry2D", "DetectorWidth should be positive.");
+ ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry2D", "ProjectionAngles not initialized");
+
+ // Interface class, so don't return true
+ return false;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CProjectionGeometry2D::_initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ float32 _fDetectorWidth,
+ const float32* _pfProjectionAngles,
+ const float32* _pfExtraDetectorOffsets)
+{
+ if (m_bInitialized) {
+ clear();
+ }
+
+ // copy parameters
+ m_iProjectionAngleCount = _iProjectionAngleCount;
+ m_iDetectorCount = _iDetectorCount;
+ m_fDetectorWidth = _fDetectorWidth;
+ m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ m_pfExtraDetectorOffset = new float32[m_iProjectionAngleCount];
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfProjectionAngles[i] = _pfProjectionAngles[i];
+ m_pfExtraDetectorOffset[i] = _pfExtraDetectorOffsets ? _pfExtraDetectorOffsets[i]:0;
+ }
+
+ // Interface class, so don't set m_bInitialized to true
+ return true;
+}
+//---------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/ProjectionGeometry3D.cpp b/src/ProjectionGeometry3D.cpp
new file mode 100644
index 0000000..b78b7b8
--- /dev/null
+++ b/src/ProjectionGeometry3D.cpp
@@ -0,0 +1,329 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ProjectionGeometry3D.h"
+
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Check all variable values.
+bool CProjectionGeometry3D::_check()
+{
+ ASTRA_CONFIG_CHECK(m_iDetectorRowCount > 0, "ProjectionGeometry3D", "DetectorRowCount should be positive.");
+ ASTRA_CONFIG_CHECK(m_iDetectorColCount > 0, "ProjectionGeometry3D", "DetectorColCount should be positive.");
+ ASTRA_CONFIG_CHECK(m_fDetectorSpacingX > 0.0f, "ProjectionGeometry3D", "m_fDetectorSpacingX should be positive.");
+ ASTRA_CONFIG_CHECK(m_fDetectorSpacingY > 0.0f, "ProjectionGeometry3D", "m_fDetectorSpacingY should be positive.");
+ ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry3D", "ProjectionAngleCount should be positive.");
+ ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry3D", "ProjectionAngles not initialized");
+
+/*
+ // autofix: angles in [0,2pi[
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ while (2*PI <= m_pfProjectionAngles[i]) m_pfProjectionAngles[i] -= 2*PI;
+ while (m_pfProjectionAngles[i] < 0) m_pfProjectionAngles[i] += 2*PI;
+ }
+*/
+
+ // succes
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CProjectionGeometry3D::CProjectionGeometry3D() : configCheckData(0)
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CProjectionGeometry3D::CProjectionGeometry3D(int _iAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorSpacingX,
+ float32 _fDetectorSpacingY,
+ const float32 *_pfProjectionAngles,
+ const float32 *_pfExtraDetectorOffsetsX,
+ const float32 *_pfExtraDetectorOffsetsY) : configCheckData(0)
+{
+ _clear();
+ _initialize(_iAngleCount,
+ _iDetectorRowCount,
+ _iDetectorColCount,
+ _fDetectorSpacingX,
+ _fDetectorSpacingY,
+ _pfProjectionAngles,
+ _pfExtraDetectorOffsetsX,
+ _pfExtraDetectorOffsetsY);
+}
+
+//----------------------------------------------------------------------------------------
+// Copy constructor.
+CProjectionGeometry3D::CProjectionGeometry3D(const CProjectionGeometry3D& _projGeom)
+{
+ _clear();
+ _initialize(_projGeom.m_iProjectionAngleCount,
+ _projGeom.m_iDetectorRowCount,
+ _projGeom.m_iDetectorColCount,
+ _projGeom.m_fDetectorSpacingX,
+ _projGeom.m_fDetectorSpacingY,
+ _projGeom.m_pfProjectionAngles,
+ _projGeom.m_pfExtraDetectorOffsetsX,
+ _projGeom.m_pfExtraDetectorOffsetsY);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CProjectionGeometry3D::~CProjectionGeometry3D()
+{
+ if (m_bInitialized) {
+ clear();
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+// Should only be used by constructors. Otherwise use the clear() function.
+void CProjectionGeometry3D::_clear()
+{
+ m_iProjectionAngleCount = 0;
+ m_iDetectorRowCount = 0;
+ m_iDetectorColCount = 0;
+ m_fDetectorSpacingX = 0.0f;
+ m_fDetectorSpacingY = 0.0f;
+ m_pfProjectionAngles = NULL;
+ m_pfExtraDetectorOffsetsX = NULL;
+ m_pfExtraDetectorOffsetsY = NULL;
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+void CProjectionGeometry3D::clear()
+{
+ m_iProjectionAngleCount = 0;
+ m_iDetectorRowCount = 0;
+ m_iDetectorColCount = 0;
+ m_fDetectorSpacingX = 0.0f;
+ m_fDetectorSpacingY = 0.0f;
+ if (m_pfProjectionAngles != NULL) {
+ delete [] m_pfProjectionAngles;
+ }
+ if (m_pfExtraDetectorOffsetsX != NULL) {
+ delete [] m_pfExtraDetectorOffsetsX;
+ }
+ if (m_pfExtraDetectorOffsetsY != NULL) {
+ delete [] m_pfExtraDetectorOffsetsY;
+ }
+ m_pfProjectionAngles = NULL;
+ m_pfExtraDetectorOffsetsX = NULL;
+ m_pfExtraDetectorOffsetsY = NULL;
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization witha Config object
+bool CProjectionGeometry3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry3D> CC("ProjectionGeometry3D", this, _cfg);
+
+ if (m_bInitialized) {
+ clear();
+ }
+
+ ASTRA_ASSERT(_cfg.self);
+
+ // Required: DetectorWidth
+ XMLNode* node = _cfg.self->getSingleNode("DetectorSpacingX");
+ ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorSpacingX tag specified.");
+ m_fDetectorSpacingX = boost::lexical_cast<float32>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorSpacingX");
+
+ // Required: DetectorHeight
+ node = _cfg.self->getSingleNode("DetectorSpacingY");
+ ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorSpacingY tag specified.");
+ m_fDetectorSpacingY = boost::lexical_cast<float32>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorSpacingY");
+
+ // Required: DetectorRowCount
+ node = _cfg.self->getSingleNode("DetectorRowCount");
+ ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorRowCount tag specified.");
+ m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorRowCount");
+
+ // Required: DetectorCount
+ node = _cfg.self->getSingleNode("DetectorColCount");
+ ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorColCount tag specified.");
+ m_iDetectorColCount = boost::lexical_cast<int>(node->getContent());
+ m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount;
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("DetectorColCount");
+
+ // Required: ProjectionAngles
+ node = _cfg.self->getSingleNode("ProjectionAngles");
+ ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No ProjectionAngles tag specified.");
+ vector<float32> angles = node->getContentNumericalArray();
+ m_iProjectionAngleCount = angles.size();
+ ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry3D", "Not enough ProjectionAngles specified.");
+ m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfProjectionAngles[i] = angles[i];
+ }
+ CC.markNodeParsed("ProjectionAngles");
+ ASTRA_DELETE(node);
+
+ // Optional: ExtraDetectorOffsetX
+ node = _cfg.self->getSingleNode("ExtraDetectorOffsetsX");
+ m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount];
+ if (node) {
+ vector<float32> translationsX = node->getContentNumericalArray();
+ if (translationsX.size() < m_iProjectionAngleCount){
+ cout << "Not enough ExtraDetectorOffsetsX components specified. " << endl;
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfExtraDetectorOffsetsX[i] = 0;
+ }
+ }
+ else {
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfExtraDetectorOffsetsX[i] = translationsX[i];
+ }
+ }
+ }
+ else {
+ //cout << "No ExtraDetectorOffsetsX tag specified." << endl;
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfExtraDetectorOffsetsX[i] = 0;
+ }
+ }
+ CC.markOptionParsed("ExtraDetectorOffsetsX");
+ ASTRA_DELETE(node);
+
+ // Optional: ExtraDetectorOffsetsY
+ node = _cfg.self->getSingleNode("ExtraDetectorOffsetsY");
+ m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount];
+ if (node) {
+ vector<float32> translationsX = node->getContentNumericalArray();
+ if (translationsX.size() < m_iProjectionAngleCount){
+ cout << "Not enough ExtraDetectorOffsetsY components specified. " << endl;
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfExtraDetectorOffsetsY[i] = 0;
+ }
+ }
+ else {
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfExtraDetectorOffsetsY[i] = translationsX[i];
+ }
+ }
+ }
+ else {
+ //cout << "No ExtraDetectorOffsetsY tag specified." << endl;
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfExtraDetectorOffsetsY[i] = 0;
+ }
+ }
+ CC.markOptionParsed("ExtraDetectorOffsetsY");
+ ASTRA_DELETE(node);
+
+ // Interface class, so don't return true
+ return false;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CProjectionGeometry3D::_initialize(int _iProjectionAngleCount,
+ int _iDetectorRowCount,
+ int _iDetectorColCount,
+ float32 _fDetectorSpacingX,
+ float32 _fDetectorSpacingY,
+ const float32 *_pfProjectionAngles,
+ const float32 *_pfExtraDetectorOffsetsX,
+ const float32 *_pfExtraDetectorOffsetsY)
+{
+ if (m_bInitialized) {
+ clear();
+ }
+
+ // copy parameters
+ m_iProjectionAngleCount = _iProjectionAngleCount;
+ m_iDetectorRowCount = _iDetectorRowCount;
+ m_iDetectorColCount = _iDetectorColCount;
+ m_iDetectorTotCount = _iDetectorRowCount * _iDetectorColCount;
+ m_fDetectorSpacingX = _fDetectorSpacingX;
+ m_fDetectorSpacingY = _fDetectorSpacingY;
+ m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount];
+ m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount];
+ for (int i = 0; i < m_iProjectionAngleCount; i++) {
+ m_pfProjectionAngles[i] = _pfProjectionAngles[i];
+ m_pfExtraDetectorOffsetsX[i] = _pfExtraDetectorOffsetsX ? _pfExtraDetectorOffsetsX[i]:0;
+ m_pfExtraDetectorOffsetsY[i] = _pfExtraDetectorOffsetsY ? _pfExtraDetectorOffsetsY[i]:0;
+ //m_pfExtraDetectorOffsetsX[i] = 0;
+ //m_pfExtraDetectorOffsetsY[i] = 0;
+ }
+
+ m_iDetectorTotCount = m_iProjectionAngleCount * m_iDetectorRowCount * m_iDetectorColCount;
+
+ // Interface class, so don't return true
+ return false;
+}
+
+//---------------------------------------------------------------------------------------
+//
+AstraError CProjectionGeometry3D::setExtraDetectorOffsetsX(float32* _pfExtraDetectorOffsetsX)
+{
+ if (!m_bInitialized)
+ return ASTRA_ERROR_NOT_INITIALIZED;
+
+ for (int iAngle = 0; iAngle<m_iProjectionAngleCount; iAngle++)
+ m_pfExtraDetectorOffsetsX[iAngle] = _pfExtraDetectorOffsetsX[iAngle];
+
+ return ASTRA_SUCCESS;
+}
+
+//---------------------------------------------------------------------------------------
+//
+AstraError CProjectionGeometry3D::setExtraDetectorOffsetsY(float32* _pfExtraDetectorOffsetsY)
+{
+ if (!m_bInitialized)
+ return ASTRA_ERROR_NOT_INITIALIZED;
+
+ for (int iAngle = 0; iAngle<m_iProjectionAngleCount; iAngle++)
+ m_pfExtraDetectorOffsetsY[iAngle] = _pfExtraDetectorOffsetsY[iAngle];
+
+ return ASTRA_SUCCESS;
+}
+} // namespace astra
diff --git a/src/Projector2D.cpp b/src/Projector2D.cpp
new file mode 100644
index 0000000..e67cd0c
--- /dev/null
+++ b/src/Projector2D.cpp
@@ -0,0 +1,217 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Projector2D.h"
+
+#include "astra/FanFlatProjectionGeometry2D.h"
+#include "astra/FanFlatVecProjectionGeometry2D.h"
+#include "astra/SparseMatrixProjectionGeometry2D.h"
+#include "astra/SparseMatrix.h"
+
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// constructor
+CProjector2D::CProjector2D() : configCheckData(0)
+{
+
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// constructor
+CProjector2D::CProjector2D(CProjectionGeometry2D* _pProjectionGeometry, CVolumeGeometry2D* _pVolumeGeometry) : configCheckData(0)
+{
+ m_pProjectionGeometry = _pProjectionGeometry->clone();
+ m_pVolumeGeometry = _pVolumeGeometry->clone();
+ m_bIsInitialized = true;
+}
+
+//----------------------------------------------------------------------------------------
+// destructor
+CProjector2D::~CProjector2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CProjector2D::_clear()
+{
+ m_pProjectionGeometry = NULL;
+ m_pVolumeGeometry = NULL;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CProjector2D::clear()
+{
+ if (m_pProjectionGeometry) {
+ delete m_pProjectionGeometry;
+ m_pProjectionGeometry = NULL;
+ }
+ if (m_pVolumeGeometry) {
+ delete m_pVolumeGeometry;
+ m_pVolumeGeometry = NULL;
+ }
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CProjector2D::_check()
+{
+ // check pointers
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "Projector2D", "Invalid Projection Geometry Object.");
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "Projector2D", "Invalid Volume Geometry Object.");
+
+ // check initializations
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector2D", "Projection Geometry Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector2D", "Volume Geometry Object Not Initialized.");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CProjector2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjector2D> CC("Projector2D", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required: ProjectionGeometry
+ XMLNode* node = _cfg.self->getSingleNode("ProjectionGeometry");
+ ASTRA_CONFIG_CHECK(node, "Projector2D", "No ProjectionGeometry tag specified.");
+
+ // FIXME: Change how the base class is created. (This is duplicated
+ // in astra_mex_data2d.cpp.)
+ std::string type = node->getAttribute("type");
+ if (type == "sparse_matrix") {
+ m_pProjectionGeometry = new CSparseMatrixProjectionGeometry2D();
+ m_pProjectionGeometry->initialize(Config(node));
+ } else if (type == "fanflat") {
+ CFanFlatProjectionGeometry2D* pFanFlatProjectionGeometry = new CFanFlatProjectionGeometry2D();
+ pFanFlatProjectionGeometry->initialize(Config(node));
+ m_pProjectionGeometry = pFanFlatProjectionGeometry;
+ } else if (type == "fanflat_vec") {
+ CFanFlatVecProjectionGeometry2D* pFanFlatVecProjectionGeometry = new CFanFlatVecProjectionGeometry2D();
+ pFanFlatVecProjectionGeometry->initialize(Config(node));
+ m_pProjectionGeometry = pFanFlatVecProjectionGeometry;
+ } else {
+ m_pProjectionGeometry = new CParallelProjectionGeometry2D();
+ m_pProjectionGeometry->initialize(Config(node));
+ }
+ // "node" is deleted by the temp Config(node) objects
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector2D", "ProjectionGeometry not initialized.");
+ CC.markNodeParsed("ProjectionGeometry");
+
+
+ // required: VolumeGeometry
+ node = _cfg.self->getSingleNode("VolumeGeometry");
+ ASTRA_CONFIG_CHECK(node, "Projector2D", "No VolumeGeometry tag specified.");
+ m_pVolumeGeometry = new CVolumeGeometry2D();
+ m_pVolumeGeometry->initialize(Config(node));
+ // "node" is deleted by the temp Config(node) object
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector2D", "VolumeGeometry not initialized.");
+ CC.markNodeParsed("VolumeGeometry");
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// weights of each detector in a projection angle
+void CProjector2D::computeProjectionRayWeights(int _iProjection, SPixelWeight* _pfWeightedPixels, int* _piRayStoredPixelCount)
+{
+ int iPixelBufferSize = getProjectionWeightsCount(_iProjection);
+
+ int iDetector;
+ for(iDetector = m_pProjectionGeometry->getDetectorCount()-1; iDetector >= 0; --iDetector) {
+ computeSingleRayWeights(_iProjection, // projector index
+ iDetector, // detector index
+ &_pfWeightedPixels[iDetector*iPixelBufferSize], // pixel buffer
+ iPixelBufferSize, // pixel buffer size
+ _piRayStoredPixelCount[iDetector]); // stored pixel count
+ }
+
+}
+
+//----------------------------------------------------------------------------------------
+// explicit projection matrix
+CSparseMatrix* CProjector2D::getMatrix()
+{
+ unsigned int iProjectionCount = m_pProjectionGeometry->getProjectionAngleCount();
+ unsigned int iDetectorCount = m_pProjectionGeometry->getDetectorCount();
+ unsigned int iRayCount = iProjectionCount * iDetectorCount;
+ unsigned int iVolumeSize = m_pVolumeGeometry->getGridTotCount();
+ unsigned long lSize = 0;
+ unsigned int iMaxRayLength = 0;
+ for (unsigned int i = 0; i < iProjectionCount; ++i) {
+ unsigned int iRayLength = getProjectionWeightsCount(i);
+ lSize += iDetectorCount * iRayLength;
+ if (iRayLength > iMaxRayLength)
+ iMaxRayLength = iRayLength;
+ }
+ CSparseMatrix* pMatrix = new CSparseMatrix(iRayCount, iVolumeSize, lSize);
+
+ if (!pMatrix || !pMatrix->isInitialized()) {
+ delete pMatrix;
+ return 0;
+ }
+
+ SPixelWeight* pEntries = new SPixelWeight[iMaxRayLength];
+ unsigned long lMatrixIndex = 0;
+ for (unsigned int iRay = 0; iRay < iRayCount; ++iRay) {
+ pMatrix->m_plRowStarts[iRay] = lMatrixIndex;
+ int iPixelCount;
+ int iProjIndex, iDetIndex;
+ m_pProjectionGeometry->indexToAngleDetectorIndex(iRay, iProjIndex, iDetIndex);
+ computeSingleRayWeights(iProjIndex, iDetIndex, pEntries, iMaxRayLength, iPixelCount);
+
+ for (int i = 0; i < iPixelCount; ++i) {
+ pMatrix->m_piColIndices[lMatrixIndex] = pEntries[i].m_iIndex;
+ pMatrix->m_pfValues[lMatrixIndex] = pEntries[i].m_fWeight;
+ ++lMatrixIndex;
+ }
+
+ }
+ pMatrix->m_plRowStarts[iRayCount] = lMatrixIndex;
+
+ delete[] pEntries;
+ return pMatrix;
+}
+
+} // end namespace
diff --git a/src/Projector3D.cpp b/src/Projector3D.cpp
new file mode 100644
index 0000000..f8fddf4
--- /dev/null
+++ b/src/Projector3D.cpp
@@ -0,0 +1,121 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Projector3D.h"
+
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CProjector3D::CProjector3D() : configCheckData(0)
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CProjector3D::~CProjector3D()
+{
+ if (m_bIsInitialized) clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Clear for constructors
+void CProjector3D::_clear()
+{
+ m_pProjectionGeometry = NULL;
+ m_pVolumeGeometry = NULL;
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Clear
+void CProjector3D::clear()
+{
+ ASTRA_DELETE(m_pProjectionGeometry);
+ ASTRA_DELETE(m_pVolumeGeometry);
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CProjector3D::_check()
+{
+ // projection geometry
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "Projector3D", "ProjectionGeometry3D not initialized.");
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector3D", "ProjectionGeometry3D not initialized.");
+
+ // volume geometry
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "Projector3D", "VolumeGeometry3D not initialized.");
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector3D", "VolumeGeometry3D not initialized.");
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CProjector3D::initialize(const Config& _cfg)
+{
+ assert(_cfg.self);
+
+ return true;
+}
+
+/*
+bool CProjector3D::initialize(astra::CProjectionGeometry3D *, astra::CVolumeGeometry3D *)
+{
+ ASTRA_ASSERT(false);
+
+ return false;
+}
+*/
+
+//----------------------------------------------------------------------------------------
+// Weights of each detector in a projection angle
+void CProjector3D::computeProjectionRayWeights(int _iProjection, SPixelWeight* _pfWeightedPixels, int* _piRayStoredPixelCount)
+{
+ int iPixelBufferSize = getProjectionWeightsCount(_iProjection);
+
+ int iDetector = 0;
+ for(iDetector = m_pProjectionGeometry->getDetectorTotCount()-1; iDetector >= 0; --iDetector) {
+ int iSliceIndex = iDetector / m_pProjectionGeometry->getDetectorColCount();
+ int iDetectorColIndex = iDetector % m_pProjectionGeometry->getDetectorColCount();
+
+ computeSingleRayWeights(_iProjection, // projector index
+ iSliceIndex, // slice index
+ iDetectorColIndex, // detector index
+ &_pfWeightedPixels[iDetector*iPixelBufferSize], // pixel buffer
+ iPixelBufferSize, // pixel buffer size
+ _piRayStoredPixelCount[iDetector]); // stored pixel count
+ }
+}
+//----------------------------------------------------------------------------------------
+
+} // end namespace
diff --git a/src/ReconstructionAlgorithm2D.cpp b/src/ReconstructionAlgorithm2D.cpp
new file mode 100644
index 0000000..ea693e3
--- /dev/null
+++ b/src/ReconstructionAlgorithm2D.cpp
@@ -0,0 +1,275 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ReconstructionAlgorithm2D.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CReconstructionAlgorithm2D::CReconstructionAlgorithm2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CReconstructionAlgorithm2D::~CReconstructionAlgorithm2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CReconstructionAlgorithm2D::_clear()
+{
+ m_pProjector = NULL;
+ m_pSinogram = NULL;
+ m_pReconstruction = NULL;
+ m_bUseMinConstraint = false;
+ m_fMinValue = 0.0f;
+ m_bUseMaxConstraint = false;
+ m_fMaxValue = 0.0f;
+ m_bUseReconstructionMask = false;
+ m_pReconstructionMask = NULL;
+ m_bUseSinogramMask = false;
+ m_pSinogramMask = NULL;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CReconstructionAlgorithm2D::clear()
+{
+ // Nothing to delete, so just _clear()
+ _clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CReconstructionAlgorithm2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithm2D", this, _cfg);
+
+ // projector
+ XMLNode* node = _cfg.self->getSingleNode("ProjectorId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pProjector = CProjector2DManager::getSingleton().get(id);
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectorId");
+
+ // sinogram data
+ node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("ReconstructionDataId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ReconstructionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ReconstructionDataId");
+
+ // fixed mask
+ if (_cfg.self->hasOption("ReconstructionMaskId")) {
+ m_bUseReconstructionMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId"));
+ m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("ReconstructionMaskId");
+
+ // fixed mask
+ if (_cfg.self->hasOption("SinogramMaskId")) {
+ m_bUseSinogramMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId"));
+ m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("SinogramMaskId");
+
+ // Constraints - NEW
+ if (_cfg.self->hasOption("MinConstraint")) {
+ m_bUseMinConstraint = true;
+ m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f);
+ CC.markOptionParsed("MinConstraint");
+ } else {
+ // Constraint - OLD
+ m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false);
+ CC.markOptionParsed("UseMinConstraint");
+ if (m_bUseMinConstraint) {
+ m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f);
+ CC.markOptionParsed("MinConstraintValue");
+ }
+ }
+ if (_cfg.self->hasOption("MaxConstraint")) {
+ m_bUseMaxConstraint = true;
+ m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f);
+ CC.markOptionParsed("MaxConstraint");
+ } else {
+ // Constraint - OLD
+ m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false);
+ CC.markOptionParsed("UseMaxConstraint");
+ if (m_bUseMaxConstraint) {
+ m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f);
+ CC.markOptionParsed("MaxConstraintValue");
+ }
+ }
+
+ // return success
+ return _check();
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // return success
+ return _check();
+}
+
+//---------------------------------------------------------------------------------------
+// Set Constraints
+void CReconstructionAlgorithm2D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue)
+{
+ m_bUseMinConstraint = _bUseMin;
+ m_fMinValue = _fMinValue;
+ m_bUseMaxConstraint = _bUseMax;
+ m_fMaxValue = _fMaxValue;
+}
+
+//----------------------------------------------------------------------------------------
+// Set Fixed Reconstruction Mask
+void CReconstructionAlgorithm2D::setReconstructionMask(CFloat32VolumeData2D* _pMask, bool _bEnable)
+{
+ // TODO: check geometry matches volume
+ m_bUseReconstructionMask = _bEnable;
+ m_pReconstructionMask = _pMask;
+ if (m_pReconstructionMask == NULL) {
+ m_bUseReconstructionMask = false;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Set Fixed Sinogram Mask
+void CReconstructionAlgorithm2D::setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable)
+{
+ // TODO: check geometry matches sinogram
+ m_bUseSinogramMask = _bEnable;
+ m_pSinogramMask = _pMask;
+ if (m_pSinogramMask == NULL) {
+ m_bUseSinogramMask = false;
+ }
+}//----------------------------------------------------------------------------------------
+// Check
+bool CReconstructionAlgorithm2D::_check()
+{
+ // check pointers
+ ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object.");
+ ASTRA_CONFIG_CHECK(m_pSinogram, "Reconstruction2D", "Invalid Projection Data Object.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction, "Reconstruction2D", "Invalid Reconstruction Data Object.");
+
+ // check initializations
+ ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "Reconstruction2D", "Projection Data Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "Reconstruction2D", "Reconstruction Data Object Not Initialized.");
+
+ // check compatibility between projector and data classes
+ ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction2D", "Projection Data not compatible with the specified Projector.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction2D", "Reconstruction Data not compatible with the specified Projector.");
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CReconstructionAlgorithm2D::getInformation()
+{
+ map<string, boost::any> res;
+ res["ProjectorId"] = getInformation("ProjectorId");
+ res["ProjectionDataId"] = getInformation("ProjectionDataId");
+ res["ReconstructionDataId"] = getInformation("ReconstructionDataId");
+ res["UseMinConstraint"] = getInformation("UseMinConstraint");
+ res["MinConstraintValue"] = getInformation("MinConstraintValue");
+ res["UseMaxConstraint"] = getInformation("UseMaxConstraint");
+ res["MaxConstraintValue"] = getInformation("MaxConstraintValue");
+ res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId");
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CReconstructionAlgorithm2D::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); }
+ if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; }
+ if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); }
+ if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; }
+ if (_sIdentifier == "ProjectorId") {
+ int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "ProjectionDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "ReconstructionDataId") {
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "ReconstructionMaskId") {
+ if (!m_bUseReconstructionMask) return string("not used");
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/ReconstructionAlgorithm3D.cpp b/src/ReconstructionAlgorithm3D.cpp
new file mode 100644
index 0000000..4d9bbc6
--- /dev/null
+++ b/src/ReconstructionAlgorithm3D.cpp
@@ -0,0 +1,306 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ReconstructionAlgorithm3D.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CReconstructionAlgorithm3D::CReconstructionAlgorithm3D()
+{
+ m_pProjector = NULL;
+ m_pSinogram = NULL;
+ m_pReconstruction = NULL;
+ m_bUseMinConstraint = false;
+ m_fMinValue = 0.0f;
+ m_bUseMaxConstraint = false;
+ m_fMaxValue = 0.0f;
+ m_bUseReconstructionMask = false;
+ m_pReconstructionMask = NULL;
+ m_bUseSinogramMask = false;
+ m_pSinogramMask = NULL;
+ m_bIsInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CReconstructionAlgorithm3D::~CReconstructionAlgorithm3D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CReconstructionAlgorithm3D::_clear()
+{
+ m_pProjector = NULL;
+ m_pSinogram = NULL;
+ m_pReconstruction = NULL;
+ m_bUseMinConstraint = false;
+ m_fMinValue = 0.0f;
+ m_bUseMaxConstraint = false;
+ m_fMaxValue = 0.0f;
+ m_bUseReconstructionMask = false;
+ m_pReconstructionMask = NULL;
+ m_bUseSinogramMask = false;
+ m_pSinogramMask = NULL;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CReconstructionAlgorithm3D::clear()
+{
+ m_pProjector = NULL;
+ m_pSinogram = NULL;
+ m_pReconstruction = NULL;
+ m_bUseMinConstraint = false;
+ m_fMinValue = 0.0f;
+ m_bUseMaxConstraint = false;
+ m_fMaxValue = 0.0f;
+ m_bUseReconstructionMask = false;
+ m_pReconstructionMask = NULL;
+ m_bUseSinogramMask = false;
+ m_pSinogramMask = NULL;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CReconstructionAlgorithm3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithm3D", this, _cfg);
+
+ XMLNode* node;
+ int id;
+#if 0
+ // projector
+ node = _cfg.self->getSingleNode("ProjectorId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ProjectorId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pProjector = CProjector3DManager::getSingleton().get(id);
+ ASTRA_DELETE(node);
+#endif
+
+ // sinogram data
+ node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ProjectionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pSinogram = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("ReconstructionDataId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ReconstructionDataId tag specified.");
+ id = boost::lexical_cast<int>(node->getContent());
+ m_pReconstruction = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id));
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ReconstructionDataId");
+
+ // fixed mask
+ if (_cfg.self->hasOption("ReconstructionMaskId")) {
+ m_bUseReconstructionMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId"));
+ m_pReconstructionMask = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("ReconstructionMaskId");
+
+ // fixed mask
+ if (_cfg.self->hasOption("SinogramMaskId")) {
+ m_bUseSinogramMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId"));
+ m_pSinogramMask = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id));
+ }
+
+ // Constraints - NEW
+ if (_cfg.self->hasOption("MinConstraint")) {
+ m_bUseMinConstraint = true;
+ m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f);
+ CC.markOptionParsed("MinConstraint");
+ } else {
+ // Constraint - OLD
+ m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false);
+ CC.markOptionParsed("UseMinConstraint");
+ if (m_bUseMinConstraint) {
+ m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f);
+ CC.markOptionParsed("MinConstraintValue");
+ }
+ }
+ if (_cfg.self->hasOption("MaxConstraint")) {
+ m_bUseMaxConstraint = true;
+ m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f);
+ CC.markOptionParsed("MaxConstraint");
+ } else {
+ // Constraint - OLD
+ m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false);
+ CC.markOptionParsed("UseMaxConstraint");
+ if (m_bUseMaxConstraint) {
+ m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f);
+ CC.markOptionParsed("MaxConstraintValue");
+ }
+ }
+
+ // return success
+ return _check();
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CReconstructionAlgorithm3D::initialize(CProjector3D* _pProjector,
+ CFloat32ProjectionData3D* _pSinogram,
+ CFloat32VolumeData3D* _pReconstruction)
+{
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // return success
+ return _check();
+}
+
+//---------------------------------------------------------------------------------------
+// Set Constraints
+void CReconstructionAlgorithm3D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue)
+{
+ m_bUseMinConstraint = _bUseMin;
+ m_fMinValue = _fMinValue;
+ m_bUseMaxConstraint = _bUseMax;
+ m_fMaxValue = _fMaxValue;
+}
+
+//----------------------------------------------------------------------------------------
+// Set Fixed Reconstruction Mask
+void CReconstructionAlgorithm3D::setReconstructionMask(CFloat32VolumeData3D* _pMask, bool _bEnable)
+{
+ // TODO: check geometry matches volume
+ m_bUseReconstructionMask = _bEnable;
+ m_pReconstructionMask = _pMask;
+ if (m_pReconstructionMask == NULL) {
+ m_bUseReconstructionMask = false;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Set Fixed Sinogram Mask
+void CReconstructionAlgorithm3D::setSinogramMask(CFloat32ProjectionData3D* _pMask, bool _bEnable)
+{
+ // TODO: check geometry matches sinogram
+ m_bUseSinogramMask = _bEnable;
+ m_pSinogramMask = _pMask;
+ if (m_pSinogramMask == NULL) {
+ m_bUseSinogramMask = false;
+ }
+}//----------------------------------------------------------------------------------------
+// Check
+bool CReconstructionAlgorithm3D::_check()
+{
+ // check pointers
+#if 0
+ ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction3D", "Invalid Projector Object.");
+#endif
+ ASTRA_CONFIG_CHECK(m_pSinogram, "Reconstruction3D", "Invalid Projection Data Object.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction, "Reconstruction3D", "Invalid Reconstruction Data Object.");
+
+ // check initializations
+#if 0
+ ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction3D", "Projector Object Not Initialized.");
+#endif
+ ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "Reconstruction3D", "Projection Data Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "Reconstruction3D", "Reconstruction Data Object Not Initialized.");
+
+#if 0
+ // check compatibility between projector and data classes
+ ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction3D", "Projection Data not compatible with the specified Projector.");
+ ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction3D", "Reconstruction Data not compatible with the specified Projector.");
+#endif
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CReconstructionAlgorithm3D::getInformation()
+{
+ map<string, boost::any> res;
+ res["ProjectorId"] = getInformation("ProjectorId");
+ res["ProjectionDataId"] = getInformation("ProjectionDataId");
+ res["ReconstructionDataId"] = getInformation("ReconstructionDataId");
+ res["UseMinConstraint"] = getInformation("UseMinConstraint");
+ res["MinConstraintValue"] = getInformation("MinConstraintValue");
+ res["UseMaxConstraint"] = getInformation("UseMaxConstraint");
+ res["MaxConstraintValue"] = getInformation("MaxConstraintValue");
+ res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId");
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CReconstructionAlgorithm3D::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); }
+ if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; }
+ if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); }
+ if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; }
+#if 0
+ if (_sIdentifier == "ProjectorId") {
+ int iIndex = CProjector3DManager::getSingleton().getIndex(m_pProjector);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+#endif
+ if (_sIdentifier == "ProjectionDataId") {
+ int iIndex = CData3DManager::getSingleton().getIndex(m_pSinogram);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "ReconstructionDataId") {
+ int iIndex = CData3DManager::getSingleton().getIndex(m_pReconstruction);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ if (_sIdentifier == "ReconstructionMaskId") {
+ if (!m_bUseReconstructionMask) return string("not used");
+ int iIndex = CData3DManager::getSingleton().getIndex(m_pReconstructionMask);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/ReconstructionAlgorithmMultiSlice2D.cpp b/src/ReconstructionAlgorithmMultiSlice2D.cpp
new file mode 100644
index 0000000..648db61
--- /dev/null
+++ b/src/ReconstructionAlgorithmMultiSlice2D.cpp
@@ -0,0 +1,288 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/ReconstructionAlgorithmMultiSlice2D.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+using namespace std;
+
+namespace astra {
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CReconstructionAlgorithmMultiSlice2D::CReconstructionAlgorithmMultiSlice2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CReconstructionAlgorithmMultiSlice2D::~CReconstructionAlgorithmMultiSlice2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CReconstructionAlgorithmMultiSlice2D::_clear()
+{
+ m_pProjector = NULL;
+ m_iSliceCount = 0;
+ m_bUseMinConstraint = false;
+ m_fMinValue = 0.0f;
+ m_bUseMaxConstraint = false;
+ m_fMaxValue = 0.0f;
+ m_bUseReconstructionMask = false;
+ m_pReconstructionMask = NULL;
+ m_bUseSinogramMask = false;
+ m_pSinogramMask = NULL;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CReconstructionAlgorithmMultiSlice2D::clear()
+{
+ m_pProjector = NULL;
+ m_vpSinogram.clear();
+ m_vpReconstruction.clear();
+ m_iSliceCount = 0;
+ m_bUseMinConstraint = false;
+ m_fMinValue = 0.0f;
+ m_bUseMaxConstraint = false;
+ m_fMaxValue = 0.0f;
+ m_bUseReconstructionMask = false;
+ m_pReconstructionMask = NULL;
+ m_bUseSinogramMask = false;
+ m_pSinogramMask = NULL;
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CReconstructionAlgorithmMultiSlice2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithmMultiSlice2D", this, _cfg);
+
+ // projector
+ XMLNode* node = _cfg.self->getSingleNode("ProjectorId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pProjector = CProjector2DManager::getSingleton().get(id);
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectorId");
+
+ // sinogram data
+ node = _cfg.self->getSingleNode("ProjectionDataId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectionDataId tag specified.");
+ vector<float32> tmpvector = node->getContentNumericalArray();
+ for (unsigned int i = 0; i < tmpvector.size(); ++i) {
+ m_vpSinogram.push_back(dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(int(tmpvector[i]))));
+ }
+ m_iSliceCount = tmpvector.size();
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ProjectionDataId");
+
+ // reconstruction data
+ node = _cfg.self->getSingleNode("ReconstructionDataId");
+ ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ReconstructionDataId tag specified.");
+ tmpvector = node->getContentNumericalArray();
+ for (unsigned int i = 0; i < tmpvector.size(); ++i) {
+ m_vpReconstruction.push_back(dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(int(tmpvector[i]))));
+ }
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("ReconstructionDataId");
+
+ // reconstruction masks
+ if (_cfg.self->hasOption("ReconstructionMaskId")) {
+ m_bUseReconstructionMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId"));
+ m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("ReconstructionMaskId");
+
+ // sinogram masks
+ if (_cfg.self->hasOption("SinogramMaskId")) {
+ m_bUseSinogramMask = true;
+ id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId"));
+ m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id));
+ }
+ CC.markOptionParsed("SinogramMaskId");
+
+ // Constraints - NEW
+ if (_cfg.self->hasOption("MinConstraint")) {
+ m_bUseMinConstraint = true;
+ m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f);
+ CC.markOptionParsed("MinConstraint");
+ } else {
+ // Constraint - OLD
+ m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false);
+ CC.markOptionParsed("UseMinConstraint");
+ if (m_bUseMinConstraint) {
+ m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f);
+ CC.markOptionParsed("MinConstraintValue");
+ }
+ }
+ if (_cfg.self->hasOption("MaxConstraint")) {
+ m_bUseMaxConstraint = true;
+ m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f);
+ CC.markOptionParsed("MaxConstraint");
+ } else {
+ // Constraint - OLD
+ m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false);
+ CC.markOptionParsed("UseMaxConstraint");
+ if (m_bUseMaxConstraint) {
+ m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f);
+ CC.markOptionParsed("MaxConstraintValue");
+ }
+ }
+
+ // return success
+ return _check();
+}
+
+//----------------------------------------------------------------------------------------
+// Initialize - C++
+bool CReconstructionAlgorithmMultiSlice2D::initialize(CProjector2D* _pProjector,
+ vector<CFloat32ProjectionData2D*> _vpSinogram,
+ vector<CFloat32VolumeData2D*> _vpReconstruction)
+{
+ m_pProjector = _pProjector;
+ m_vpSinogram = _vpSinogram;
+ m_vpReconstruction = _vpReconstruction;
+ m_iSliceCount = _vpSinogram.size();
+
+ // return success
+ return _check();
+}
+
+//---------------------------------------------------------------------------------------
+// Set Constraints
+void CReconstructionAlgorithmMultiSlice2D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue)
+{
+ m_bUseMinConstraint = _bUseMin;
+ m_fMinValue = _fMinValue;
+ m_bUseMaxConstraint = _bUseMax;
+ m_fMaxValue = _fMaxValue;
+}
+
+//----------------------------------------------------------------------------------------
+// Set Fixed Reconstruction Mask
+void CReconstructionAlgorithmMultiSlice2D::setReconstructionMask(CFloat32VolumeData2D* _pMask, bool _bEnable)
+{
+ m_bUseReconstructionMask = _bEnable;
+ m_pReconstructionMask = _pMask;
+ if (m_pReconstructionMask == NULL) {
+ m_bUseReconstructionMask = false;
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CReconstructionAlgorithmMultiSlice2D::_check()
+{
+ // check projector
+ ASTRA_CONFIG_CHECK(m_pProjector, "ReconstructionMultiSlice2D", "Invalid Projector Object.");
+ ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ReconstructionMultiSlice2D", "Projector Object Not Initialized.");
+
+ // check list
+ ASTRA_CONFIG_CHECK(m_vpSinogram.size() == (unsigned int)m_iSliceCount, "ReconstructionMultiSlice2D", "Sinogram slicecount mismatch.");
+ ASTRA_CONFIG_CHECK(m_vpReconstruction.size() == (unsigned int)m_iSliceCount, "ReconstructionMultiSlice2D", "Volume slicecount mismatch.");
+
+ for (int i = 0; i < m_iSliceCount; ++i) {
+ // pointers
+ ASTRA_CONFIG_CHECK(m_vpSinogram[i], "ReconstructionMultiSlice2D", "Invalid Projection Data Object.");
+ ASTRA_CONFIG_CHECK(m_vpReconstruction[i], "ReconstructionMultiSlice2D", "Invalid Volume Data Object.");
+
+ // initialized
+ ASTRA_CONFIG_CHECK(m_vpSinogram[i]->isInitialized(), "ReconstructionMultiSlice2D", "Projection Data Object Not Initialized.");
+ ASTRA_CONFIG_CHECK(m_vpReconstruction[i]->isInitialized(), "ReconstructionMultiSlice2D", "Volume Data Object Not Initialized.");
+
+ // geometry compatibility
+ ASTRA_CONFIG_CHECK(m_vpSinogram[i]->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction2D", "Projection Data not compatible with the specified Projector.");
+ ASTRA_CONFIG_CHECK(m_vpReconstruction[i]->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction2D", "Reconstruction Data not compatible with the specified Projector.");
+ }
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CReconstructionAlgorithmMultiSlice2D::getInformation()
+{
+ map<string, boost::any> res;
+ res["ProjectorId"] = getInformation("ProjectorId");
+// res["ProjectionDataId"] = getInformation("ProjectionDataId");
+// res["ReconstructionDataId"] = getInformation("ReconstructionDataId");
+ res["UseMinConstraint"] = getInformation("UseMinConstraint");
+ res["MinConstraintValue"] = getInformation("MinConstraintValue");
+ res["UseMaxConstraint"] = getInformation("UseMaxConstraint");
+ res["MaxConstraintValue"] = getInformation("MaxConstraintValue");
+ res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId");
+ return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CReconstructionAlgorithmMultiSlice2D::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); }
+ if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; }
+ if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); }
+ if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; }
+ if (_sIdentifier == "ProjectorId") {
+ int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+// if (_sIdentifier == "ProjectionDataId") {
+// int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram);
+// if (iIndex != 0) return iIndex;
+// return std::string("not in manager");
+// }
+// if (_sIdentifier == "ReconstructionDataId") {
+// int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction);
+// if (iIndex != 0) return iIndex;
+// return std::string("not in manager");
+// }
+ if (_sIdentifier == "ReconstructionMaskId") {
+ if (!m_bUseReconstructionMask) return string("not used");
+ int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask);
+ if (iIndex != 0) return iIndex;
+ return std::string("not in manager");
+ }
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/SartAlgorithm.cpp b/src/SartAlgorithm.cpp
new file mode 100644
index 0000000..d898297
--- /dev/null
+++ b/src/SartAlgorithm.cpp
@@ -0,0 +1,452 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/SartAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+
+namespace astra {
+
+#include "astra/Projector2DImpl.inl"
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CSartAlgorithm::type = "SART";
+
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CSartAlgorithm::_clear()
+{
+ CReconstructionAlgorithm2D::_clear();
+ m_piProjectionOrder = NULL;
+ m_iProjectionCount = 0;
+ m_iCurrentProjection = 0;
+ m_bIsInitialized = false;
+ m_iIterationCount = 0;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CSartAlgorithm::clear()
+{
+ CReconstructionAlgorithm2D::clear();
+ if (m_piProjectionOrder) {
+ delete[] m_piProjectionOrder;
+ m_piProjectionOrder = NULL;
+ }
+ m_iProjectionCount = 0;
+ m_iCurrentProjection = 0;
+ m_bIsInitialized = false;
+ m_iIterationCount = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CSartAlgorithm::CSartAlgorithm()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CSartAlgorithm::CSartAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ _clear();
+ initialize(_pProjector, _pSinogram, _pReconstruction);
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CSartAlgorithm::CSartAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int* _piProjectionOrder,
+ int _iProjectionCount)
+{
+ _clear();
+ initialize(_pProjector, _pSinogram, _pReconstruction, _piProjectionOrder, _iProjectionCount);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CSartAlgorithm::~CSartAlgorithm()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CSartAlgorithm::initialize(const Config& _cfg)
+{
+ assert(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("SartAlgorithm", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // projection order
+ m_iCurrentProjection = 0;
+ m_iProjectionCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount();
+ string projOrder = _cfg.self->getOption("ProjectionOrder", "sequential");
+ CC.markOptionParsed("ProjectionOrder");
+ if (projOrder == "sequential") {
+ m_piProjectionOrder = new int[m_iProjectionCount];
+ for (int i = 0; i < m_iProjectionCount; i++) {
+ m_piProjectionOrder[i] = i;
+ }
+ } else if (projOrder == "random") {
+ m_piProjectionOrder = new int[m_iProjectionCount];
+ for (int i = 0; i < m_iProjectionCount; i++) {
+ m_piProjectionOrder[i] = i;
+ }
+ for (int i = 0; i < m_iProjectionCount-1; i++) {
+ int k = (rand() % (m_iProjectionCount - i));
+ int t = m_piProjectionOrder[i];
+ m_piProjectionOrder[i] = m_piProjectionOrder[i + k];
+ m_piProjectionOrder[i + k] = t;
+ }
+ } else if (projOrder == "custom") {
+ vector<float32> projOrderList = _cfg.self->getOptionNumericalArray("ProjectionOrderList");
+ m_piProjectionOrder = new int[projOrderList.size()];
+ for (int i = 0; i < m_iProjectionCount; i++) {
+ m_piProjectionOrder[i] = static_cast<int>(projOrderList[i]);
+ }
+ CC.markOptionParsed("ProjectionOrderList");
+ }
+
+ // create data objects
+ m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
+ m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry());
+ m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CSartAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // ray order
+ m_iCurrentProjection = 0;
+ m_iProjectionCount = _pProjector->getProjectionGeometry()->getProjectionAngleCount();
+ m_piProjectionOrder = new int[m_iProjectionCount];
+ for (int i = 0; i < m_iProjectionCount; i++) {
+ m_piProjectionOrder[i] = i;
+ }
+
+ // create data objects
+ m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
+ m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry());
+ m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CSartAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction,
+ int* _piProjectionOrder,
+ int _iProjectionCount)
+{
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // ray order
+ m_iCurrentProjection = 0;
+ m_iProjectionCount = _iProjectionCount;
+ m_piProjectionOrder = new int[m_iProjectionCount];
+ for (int i = 0; i < m_iProjectionCount; i++) {
+ m_piProjectionOrder[i] = _piProjectionOrder[i];
+ }
+
+ // create data objects
+ m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
+ m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry());
+ m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+bool CSartAlgorithm::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "SART", "Error in ReconstructionAlgorithm2D initialization");
+
+ // check projection order all within range
+ for (int i = 0; i < m_iProjectionCount; ++i) {
+ ASTRA_CONFIG_CHECK(0 <= m_piProjectionOrder[i] && m_piProjectionOrder[i] < m_pProjector->getProjectionGeometry()->getProjectionAngleCount(), "SART", "Projection Order out of range.");
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CSartAlgorithm::getInformation()
+{
+ map<string, boost::any> res;
+ res["ProjectionOrder"] = getInformation("ProjectionOrder");
+ return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CSartAlgorithm::getInformation(std::string _sIdentifier)
+{
+ if (_sIdentifier == "ProjectionOrder") {
+ vector<float32> res;
+ for (int i = 0; i < m_iProjectionCount; i++) {
+ res.push_back(m_piProjectionOrder[i]);
+ }
+ return res;
+ }
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CSartAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ m_bShouldAbort = false;
+
+ int iIteration = 0;
+
+ // data projectors
+ CDataProjectorInterface* pForwardProjector;
+ CDataProjectorInterface* pBackProjector;
+
+ m_pTotalRayLength->setData(0.0f);
+ m_pTotalPixelWeight->setData(0.0f);
+
+ // backprojection data projector
+ pBackProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ SIRTBPPolicy(m_pReconstruction, m_pDiffSinogram, m_pTotalPixelWeight, m_pTotalRayLength), // SIRT backprojection
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
+ // first time forward projection data projector,
+ // also computes total pixel weight and total ray length
+ pForwardProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ Combine3Policy<DiffFPPolicy, TotalPixelWeightPolicy, TotalRayLengthPolicy>( // 3 basic operations
+ DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation
+ TotalPixelWeightPolicy(m_pTotalPixelWeight), // calculate the total pixel weights
+ TotalRayLengthPolicy(m_pTotalRayLength)), // calculate the total ray lengths
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
+
+
+ // iteration loop
+ for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) {
+
+ int iProjection = m_piProjectionOrder[m_iIterationCount % m_iProjectionCount];
+
+ // forward projection and difference calculation
+ m_pTotalPixelWeight->setData(0.0f);
+ pForwardProjector->projectSingleProjection(iProjection);
+ // backprojection
+ pBackProjector->projectSingleProjection(iProjection);
+ // update iteration count
+ m_iIterationCount++;
+
+ if (m_bUseMinConstraint)
+ m_pReconstruction->clampMin(m_fMinValue);
+ if (m_bUseMaxConstraint)
+ m_pReconstruction->clampMax(m_fMaxValue);
+ }
+
+
+ ASTRA_DELETE(pForwardProjector);
+ ASTRA_DELETE(pBackProjector);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ //// check initialized
+ // ASTRA_ASSERT(m_bIsInitialized);
+
+ //// variables
+ //int iIteration, iDetector;
+ //int baseIndex, iPixel;
+ //float32* pfGamma = new float32[m_pReconstruction->getSize()];
+ //float32* pfBeta = new float32[m_pProjector->getProjectionGeometry()->getDetectorCount()];
+ //float32* pfProjectionDiff = new float32[m_pProjector->getProjectionGeometry()->getDetectorCount()];
+
+ //// ITERATE
+ //for (iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) {
+ //
+ // // reset gamma
+ // memset(pfGamma, 0, sizeof(float32) * m_pReconstruction->getSize());
+ // memset(pfBeta, 0, sizeof(float32) * m_pProjector->getProjectionGeometry()->getDetectorCount());
+ //
+ // // get current projection angle
+ // int iProjection = m_piProjectionOrder[m_iCurrentProjection];
+ // m_iCurrentProjection = (m_iCurrentProjection + 1) % m_iProjectionCount;
+ // int iProjectionWeightCount = m_pProjector->getProjectionWeightsCount(iProjection);
+ //
+ // // allocate memory for the pixel buffer
+ // SPixelWeight* pPixels = new SPixelWeight[m_pProjector->getProjectionWeightsCount(iProjection) * m_pProjector->getProjectionGeometry()->getDetectorCount()];
+ // int* piRayStoredPixelCount = new int[m_pProjector->getProjectionGeometry()->getDetectorCount()];
+
+ // // compute weights for this projection
+ // m_pProjector->computeProjectionRayWeights(iProjection, pPixels, piRayStoredPixelCount);
+ //
+ // // calculate projection difference in each detector
+ // for (iDetector = m_pProjector->getProjectionGeometry()->getDetectorCount()-1; iDetector >= 0; --iDetector) {
+
+ // if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue;
+
+ // // index base of the pixel in question
+ // baseIndex = iDetector * iProjectionWeightCount;
+ //
+ // // set the initial projection difference to the sinogram value
+ // pfProjectionDiff[iDetector] = m_pSinogram->getData2DConst()[iProjection][iDetector];
+ //
+ // // update projection difference, beta and gamma
+ // for (iPixel = piRayStoredPixelCount[iDetector]-1; iPixel >= 0; --iPixel) {
+
+ // // pixel must be loose
+ // if (m_bUseReconstructionMask && m_pReconstructionMask->getData()[pPixels[baseIndex+iPixel].m_iIndex] == 0) continue;
+
+ // // subtract projection value from projection difference
+ // pfProjectionDiff[iDetector] -=
+ // pPixels[baseIndex+iPixel].m_fWeight * m_pReconstruction->getDataConst()[pPixels[baseIndex+iPixel].m_iIndex];
+ //
+ // // update beta and gamma if this pixel lies inside a loose part
+ // pfBeta[iDetector] += pPixels[baseIndex+iPixel].m_fWeight;
+ // pfGamma[pPixels[baseIndex+iPixel].m_iIndex] += pPixels[baseIndex+iPixel].m_fWeight;
+ // }
+ //
+ // }
+ //
+ // // back projection
+ // for (iDetector = m_pProjector->getProjectionGeometry()->getDetectorCount()-1; iDetector >= 0; --iDetector) {
+ //
+ // if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue;
+
+ // // index base of the pixel in question
+ // baseIndex = iDetector * iProjectionWeightCount;
+
+ // // update pixel values
+ // for (iPixel = piRayStoredPixelCount[iDetector]-1; iPixel >= 0; --iPixel) {
+
+ //
+ // // pixel must be loose
+ // if (m_bUseReconstructionMask && m_pReconstructionMask->getData()[pPixels[baseIndex+iPixel].m_iIndex] == 0) continue;
+
+ //
+
+ // // update reconstruction volume
+ // float32 fGammaBeta = pfGamma[pPixels[baseIndex+iPixel].m_iIndex] * pfBeta[iDetector];
+ // if ((fGammaBeta > 0.01f) || (fGammaBeta < -0.01f)) {
+ // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] +=
+ // pPixels[baseIndex+iPixel].m_fWeight * pfProjectionDiff[iDetector] / fGammaBeta;
+ // }
+
+ // // constraints
+ // if (m_bUseMinConstraint && m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] < m_fMinValue) {
+ // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] = m_fMinValue;
+ // }
+ // if (m_bUseMaxConstraint && m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] > m_fMaxValue) {
+ // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] = m_fMaxValue;
+ // }
+ // }
+ // }
+ //
+ // // garbage disposal
+ // delete[] pPixels;
+ // delete[] piRayStoredPixelCount;
+ //}
+
+ //// garbage disposal
+ //delete[] pfGamma;
+ //delete[] pfBeta;
+ //delete[] pfProjectionDiff;
+
+ //// update statistics
+ //m_pReconstruction->updateStatistics();
+}
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/SirtAlgorithm.cpp b/src/SirtAlgorithm.cpp
new file mode 100644
index 0000000..60cee8a
--- /dev/null
+++ b/src/SirtAlgorithm.cpp
@@ -0,0 +1,321 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/SirtAlgorithm.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include "astra/AstraObjectManager.h"
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+
+namespace astra {
+
+#include "astra/Projector2DImpl.inl"
+
+// type of the algorithm, needed to register with CAlgorithmFactory
+std::string CSirtAlgorithm::type = "SIRT";
+
+//----------------------------------------------------------------------------------------
+// Constructor
+CSirtAlgorithm::CSirtAlgorithm()
+{
+ _clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+CSirtAlgorithm::CSirtAlgorithm(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ _clear();
+ initialize(_pProjector, _pSinogram, _pReconstruction);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor
+CSirtAlgorithm::~CSirtAlgorithm()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CSirtAlgorithm::_clear()
+{
+ CReconstructionAlgorithm2D::_clear();
+ m_bIsInitialized = false;
+
+ m_pTotalRayLength = NULL;
+ m_pTotalPixelWeight = NULL;
+ m_pDiffSinogram = NULL;
+ m_pTmpVolume = NULL;
+
+ m_iIterationCount = 0;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CSirtAlgorithm::clear()
+{
+ CReconstructionAlgorithm2D::_clear();
+ m_bIsInitialized = false;
+
+ ASTRA_DELETE(m_pTotalRayLength);
+ ASTRA_DELETE(m_pTotalPixelWeight);
+ ASTRA_DELETE(m_pDiffSinogram);
+ ASTRA_DELETE(m_pTmpVolume);
+
+ m_iIterationCount = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Check
+bool CSirtAlgorithm::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "SIRT", "Error in ReconstructionAlgorithm2D initialization");
+
+ ASTRA_CONFIG_CHECK(m_pTotalRayLength, "SIRT", "Invalid TotalRayLength Object");
+ ASTRA_CONFIG_CHECK(m_pTotalRayLength->isInitialized(), "SIRT", "Invalid TotalRayLength Object");
+ ASTRA_CONFIG_CHECK(m_pTotalPixelWeight, "SIRT", "Invalid TotalPixelWeight Object");
+ ASTRA_CONFIG_CHECK(m_pTotalPixelWeight->isInitialized(), "SIRT", "Invalid TotalPixelWeight Object");
+ ASTRA_CONFIG_CHECK(m_pDiffSinogram, "SIRT", "Invalid DiffSinogram Object");
+ ASTRA_CONFIG_CHECK(m_pDiffSinogram->isInitialized(), "SIRT", "Invalid DiffSinogram Object");
+
+ return true;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CSirtAlgorithm::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CAlgorithm> CC("SirtAlgorithm", this, _cfg);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CReconstructionAlgorithm2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // init data objects and data projectors
+ _init();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - C++
+bool CSirtAlgorithm::initialize(CProjector2D* _pProjector,
+ CFloat32ProjectionData2D* _pSinogram,
+ CFloat32VolumeData2D* _pReconstruction)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // required classes
+ m_pProjector = _pProjector;
+ m_pSinogram = _pSinogram;
+ m_pReconstruction = _pReconstruction;
+
+ // init data objects and data projectors
+ _init();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize Data Projectors - private
+void CSirtAlgorithm::_init()
+{
+ // create data objects
+ m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
+ m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry());
+ m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry());
+ m_pTmpVolume = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry());
+}
+
+//---------------------------------------------------------------------------------------
+// Information - All
+map<string,boost::any> CSirtAlgorithm::getInformation()
+{
+ map<string, boost::any> res;
+ return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res);
+};
+
+//---------------------------------------------------------------------------------------
+// Information - Specific
+boost::any CSirtAlgorithm::getInformation(std::string _sIdentifier)
+{
+ return CAlgorithm::getInformation(_sIdentifier);
+};
+
+//----------------------------------------------------------------------------------------
+// Iterate
+void CSirtAlgorithm::run(int _iNrIterations)
+{
+ // check initialized
+ ASTRA_ASSERT(m_bIsInitialized);
+
+ m_bShouldAbort = false;
+
+ int iIteration = 0;
+
+ // data projectors
+ CDataProjectorInterface* pForwardProjector;
+ CDataProjectorInterface* pBackProjector;
+ CDataProjectorInterface* pFirstForwardProjector;
+
+ m_pTotalRayLength->setData(0.0f);
+ m_pTotalPixelWeight->setData(0.0f);
+
+ // forward projection data projector
+ pForwardProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
+ // backprojection data projector
+ pBackProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ DefaultBPPolicy(m_pTmpVolume, m_pDiffSinogram), // backprojection
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
+ // first time forward projection data projector,
+ // also computes total pixel weight and total ray length
+ pFirstForwardProjector = dispatchDataProjector(
+ m_pProjector,
+ SinogramMaskPolicy(m_pSinogramMask), // sinogram mask
+ ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask
+ Combine3Policy<DiffFPPolicy, TotalPixelWeightPolicy, TotalRayLengthPolicy>( // 3 basic operations
+ DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation
+ TotalPixelWeightPolicy(m_pTotalPixelWeight), // calculate the total pixel weights
+ TotalRayLengthPolicy(m_pTotalRayLength)), // calculate the total ray lengths
+ m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off
+ );
+
+
+
+ // forward projection, difference calculation and raylength/pixelweight computation
+ pFirstForwardProjector->project();
+
+ float32* pfT = m_pTotalPixelWeight->getData();
+ for (int i = 0; i < m_pTotalPixelWeight->getSize(); ++i) {
+ float32 x = pfT[i];
+ if (x < -eps || x > eps)
+ x = 1.0f / x;
+ else
+ x = 0.0f;
+ pfT[i] = x;
+ }
+ pfT = m_pTotalRayLength->getData();
+ for (int i = 0; i < m_pTotalRayLength->getSize(); ++i) {
+ float32 x = pfT[i];
+ if (x < -eps || x > eps)
+ x = 1.0f / x;
+ else
+ x = 0.0f;
+ pfT[i] = x;
+ }
+
+ // divide by line weights
+ (*m_pDiffSinogram) *= (*m_pTotalRayLength);
+
+ // backprojection
+ m_pTmpVolume->setData(0.0f);
+ pBackProjector->project();
+
+ // divide by pixel weights
+ (*m_pTmpVolume) *= (*m_pTotalPixelWeight);
+ (*m_pReconstruction) += (*m_pTmpVolume);
+
+ if (m_bUseMinConstraint)
+ m_pReconstruction->clampMin(m_fMinValue);
+ if (m_bUseMaxConstraint)
+ m_pReconstruction->clampMax(m_fMaxValue);
+
+ // update iteration count
+ m_iIterationCount++;
+ iIteration++;
+
+
+
+
+ // iteration loop
+ for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) {
+ // forward projection and difference calculation
+ pForwardProjector->project();
+
+ // divide by line weights
+ (*m_pDiffSinogram) *= (*m_pTotalRayLength);
+
+
+ // backprojection
+ m_pTmpVolume->setData(0.0f);
+ pBackProjector->project();
+
+ // divide by pixel weights
+ (*m_pTmpVolume) *= (*m_pTotalPixelWeight);
+ (*m_pReconstruction) += (*m_pTmpVolume);
+
+ if (m_bUseMinConstraint)
+ m_pReconstruction->clampMin(m_fMinValue);
+ if (m_bUseMaxConstraint)
+ m_pReconstruction->clampMax(m_fMaxValue);
+
+ // update iteration count
+ m_iIterationCount++;
+ }
+
+
+ ASTRA_DELETE(pForwardProjector);
+ ASTRA_DELETE(pBackProjector);
+ ASTRA_DELETE(pFirstForwardProjector);
+}
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/SparseMatrix.cpp b/src/SparseMatrix.cpp
new file mode 100644
index 0000000..e6d115f
--- /dev/null
+++ b/src/SparseMatrix.cpp
@@ -0,0 +1,91 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include <sstream>
+
+#include "astra/Globals.h"
+#include "astra/SparseMatrix.h"
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// constructor
+
+CSparseMatrix::CSparseMatrix()
+{
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// constructor
+CSparseMatrix::CSparseMatrix(unsigned int _iHeight, unsigned int _iWidth,
+ unsigned long _lSize)
+{
+ initialize(_iHeight, _iWidth, _lSize);
+}
+
+
+//----------------------------------------------------------------------------------------
+// destructor
+CSparseMatrix::~CSparseMatrix()
+{
+ delete[] m_pfValues;
+ delete[] m_piColIndices;
+ delete[] m_plRowStarts;
+}
+
+//----------------------------------------------------------------------------------------
+// initialize
+bool CSparseMatrix::initialize(unsigned int _iHeight, unsigned int _iWidth,
+ unsigned long _lSize)
+{
+ m_iHeight = _iHeight;
+ m_iWidth = _iWidth;
+ m_lSize = _lSize;
+
+ m_pfValues = new float32[_lSize];
+ m_piColIndices = new unsigned int[_lSize];
+ m_plRowStarts = new unsigned long[_iHeight+1];
+ m_bInitialized = true;
+
+ return m_bInitialized;
+}
+
+
+std::string CSparseMatrix::description() const
+{
+ std::stringstream res;
+ res << m_iHeight << "x" << m_iWidth << " sparse matrix";
+ return res.str();
+}
+
+
+
+
+} // end namespace
diff --git a/src/SparseMatrixProjectionGeometry2D.cpp b/src/SparseMatrixProjectionGeometry2D.cpp
new file mode 100644
index 0000000..b95bbf4
--- /dev/null
+++ b/src/SparseMatrixProjectionGeometry2D.cpp
@@ -0,0 +1,203 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/SparseMatrixProjectionGeometry2D.h"
+
+#include <boost/lexical_cast.hpp>
+#include "astra/AstraObjectManager.h"
+
+
+using namespace std;
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D() :
+ CProjectionGeometry2D()
+{
+ m_pMatrix = 0;
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ const CSparseMatrix* _pMatrix)
+{
+ _clear();
+ initialize(_iProjectionAngleCount,
+ _iDetectorCount,
+ _pMatrix);
+}
+
+//----------------------------------------------------------------------------------------
+CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D(const CSparseMatrixProjectionGeometry2D& _projGeom)
+{
+ _clear();
+ initialize(_projGeom.m_iProjectionAngleCount,
+ _projGeom.m_iDetectorCount,
+ _projGeom.m_pMatrix);
+}
+
+//----------------------------------------------------------------------------------------
+
+CSparseMatrixProjectionGeometry2D& CSparseMatrixProjectionGeometry2D::operator=(const CSparseMatrixProjectionGeometry2D& _other)
+{
+ m_bInitialized = _other.m_bInitialized;
+ if (_other.m_bInitialized) {
+ m_pMatrix = _other.m_pMatrix;
+ m_iDetectorCount = _other.m_iDetectorCount;
+ m_fDetectorWidth = _other.m_fDetectorWidth;
+ }
+ return *this;
+
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CSparseMatrixProjectionGeometry2D::~CSparseMatrixProjectionGeometry2D()
+{
+ m_pMatrix = 0;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize - Config
+bool CSparseMatrixProjectionGeometry2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CProjectionGeometry2D> CC("SparseMatrixProjectionGeometry2D", this, _cfg);
+
+ // initialization of parent class
+ CProjectionGeometry2D::initialize(_cfg);
+
+ // get matrix
+ XMLNode* node = _cfg.self->getSingleNode("MatrixID");
+ ASTRA_CONFIG_CHECK(node, "SparseMatrixProjectionGeometry2D", "No MatrixID tag specified.");
+ int id = boost::lexical_cast<int>(node->getContent());
+ m_pMatrix = CMatrixManager::getSingleton().get(id);
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("MatrixID");
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CSparseMatrixProjectionGeometry2D::initialize(int _iProjectionAngleCount,
+ int _iDetectorCount,
+ const CSparseMatrix* _pMatrix)
+{
+ if (m_bInitialized) {
+ clear();
+ }
+
+ m_iProjectionAngleCount = _iProjectionAngleCount;
+ m_iDetectorCount = _iDetectorCount;
+
+ // FIXME: We should probably require these for consistency?
+ m_fDetectorWidth = 1.0f;
+ m_pfProjectionAngles = new float32[m_iProjectionAngleCount];
+ for (int i = 0; i < m_iProjectionAngleCount; ++i)
+ m_pfProjectionAngles[i] = 0.0f;
+
+ m_pMatrix = _pMatrix;
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Check.
+bool CSparseMatrixProjectionGeometry2D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CProjectionGeometry2D::_check(), "SparseMatrixProjectionGeometry2D", "Error in ProjectionGeometry2D initialization");
+
+ ASTRA_CONFIG_CHECK(m_pMatrix, "SparseMatrixProjectionGeometry2D", "No matrix specified");
+
+ ASTRA_CONFIG_CHECK(m_pMatrix->m_iHeight == (unsigned int)(m_iProjectionAngleCount * m_iDetectorCount), "SparseMatrixProjectionGeometry2D", "Matrix height doesn't match projection geometry");
+
+ return true;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Clone
+CProjectionGeometry2D* CSparseMatrixProjectionGeometry2D::clone()
+{
+ return new CSparseMatrixProjectionGeometry2D(*this);
+}
+
+//----------------------------------------------------------------------------------------
+// is equal
+bool CSparseMatrixProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // try to cast argument to CSparseMatrixProjectionGeometry2D
+ CSparseMatrixProjectionGeometry2D* pGeom2 = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(_pGeom2);
+ if (pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false;
+ if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false;
+ if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false;
+
+ // Maybe check equality of matrices by element?
+ if (m_pMatrix != pGeom2->m_pMatrix) return false;
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// is of type
+bool CSparseMatrixProjectionGeometry2D::isOfType(const std::string& _sType)
+{
+ return (_sType == "sparse_matrix");
+}
+//----------------------------------------------------------------------------------------
+
+CVector3D CSparseMatrixProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex)
+{
+ CVector3D vOutput(0.0f, 0.0f, 0.0f);
+
+ // not implemented, yet
+ ASTRA_ASSERT(false);
+
+ return vOutput;
+}
+
+} // end namespace astra
diff --git a/src/SparseMatrixProjector2D.cpp b/src/SparseMatrixProjector2D.cpp
new file mode 100644
index 0000000..ba3a46b
--- /dev/null
+++ b/src/SparseMatrixProjector2D.cpp
@@ -0,0 +1,219 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/SparseMatrixProjector2D.h"
+
+#include <cmath>
+#include <boost/lexical_cast.hpp>
+
+#include "astra/DataProjectorPolicies.h"
+
+using namespace std;
+using namespace astra;
+
+#include "astra/SparseMatrixProjector2D.inl"
+
+// type of the projector, needed to register with CProjectorFactory
+std::string CSparseMatrixProjector2D::type = "sparse_matrix";
+
+//----------------------------------------------------------------------------------------
+// default constructor
+CSparseMatrixProjector2D::CSparseMatrixProjector2D()
+{
+ _clear();
+}
+
+//----------------------------------------------------------------------------------------
+// constructor
+CSparseMatrixProjector2D::CSparseMatrixProjector2D(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pReconstructionGeometry)
+
+{
+ _clear();
+ initialize(_pProjectionGeometry, _pReconstructionGeometry);
+}
+
+//----------------------------------------------------------------------------------------
+// destructor
+CSparseMatrixProjector2D::~CSparseMatrixProjector2D()
+{
+ clear();
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Constructors
+void CSparseMatrixProjector2D::_clear()
+{
+ CProjector2D::_clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Clear - Public
+void CSparseMatrixProjector2D::clear()
+{
+ CProjector2D::clear();
+ m_bIsInitialized = false;
+}
+
+//---------------------------------------------------------------------------------------
+// Check
+bool CSparseMatrixProjector2D::_check()
+{
+ // check base class
+ ASTRA_CONFIG_CHECK(CProjector2D::_check(), "SparseMatrixProjector2D", "Error in Projector2D initialization");
+
+ ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "SparseMatrixProjector2D", "Volume geometry not initialized");
+ ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SparseMatrixProjector2D", "Projection geometry not initialized");
+
+
+ ASTRA_CONFIG_CHECK(dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry), "SparseMatrixProjector2D", "Unsupported projection geometry");
+
+ const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix();
+ ASTRA_CONFIG_CHECK(pMatrix, "SparseMatrixProjector2D", "No matrix specified in projection geometry");
+
+ ASTRA_CONFIG_CHECK(pMatrix->m_iWidth == (unsigned int)m_pVolumeGeometry->getGridTotCount(), "SparseMatrixProjector2D", "Matrix width doesn't match volume geometry");
+
+ return true;
+}
+
+
+//---------------------------------------------------------------------------------------
+// Initialize, use a Config object
+bool CSparseMatrixProjector2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // initialization of parent class
+ if (!CProjector2D::initialize(_cfg)) {
+ return false;
+ }
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+//---------------------------------------------------------------------------------------
+// Initialize
+bool CSparseMatrixProjector2D::initialize(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry,
+ CVolumeGeometry2D* _pVolumeGeometry)
+{
+ // if already initialized, clear first
+ if (m_bIsInitialized) {
+ clear();
+ }
+
+ // hardcopy geometries
+ m_pProjectionGeometry = _pProjectionGeometry->clone();
+ m_pVolumeGeometry = _pVolumeGeometry->clone();
+
+ // success
+ m_bIsInitialized = _check();
+ return m_bIsInitialized;
+}
+
+
+//----------------------------------------------------------------------------------------
+// Get maximum amount of weights on a single ray
+int CSparseMatrixProjector2D::getProjectionWeightsCount(int _iProjectionIndex)
+{
+ const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix();
+
+ unsigned int iMax = 0;
+ unsigned long lSize = m_pProjectionGeometry->getDetectorCount();
+ lSize *= m_pProjectionGeometry->getProjectionAngleCount();
+ for (unsigned long i = 0; i < lSize; ++i) {
+ unsigned int iRowSize = pMatrix->getRowSize(i);
+ if (iRowSize > iMax)
+ iMax = pMatrix->getRowSize(i);
+ }
+ return iMax;
+}
+
+//----------------------------------------------------------------------------------------
+// Single Ray Weights
+void CSparseMatrixProjector2D::computeSingleRayWeights(int _iProjectionIndex,
+ int _iDetectorIndex,
+ SPixelWeight* _pWeightedPixels,
+ int _iMaxPixelCount,
+ int& _iStoredPixelCount)
+{
+ // TODO: Move this default implementation to Projector2D?
+ ASTRA_ASSERT(m_bIsInitialized);
+ StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount);
+ projectSingleRay(_iProjectionIndex, _iDetectorIndex, p);
+ _iStoredPixelCount = p.getStoredPixelCount();
+}
+
+//----------------------------------------------------------------------------------------
+// Splat a single point
+std::vector<SDetector2D> CSparseMatrixProjector2D::projectPoint(int _iRow, int _iCol)
+{
+ unsigned int iVolumeIndex = _iCol * m_pVolumeGeometry->getGridRowCount() + _iRow;
+
+ // NOTE: This is very slow currently because we don't have the
+ // sparse matrix stored in an appropriate form for this function.
+ std::vector<SDetector2D> ret;
+
+ const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix();
+
+ for (int iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle)
+ {
+ for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector)
+ {
+ int iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
+ const unsigned int* piColIndices;
+ const float32* pfValues;
+ unsigned int iSize;
+
+ pMatrix->getRowData(iRayIndex, iSize, pfValues, piColIndices);
+
+ for (unsigned int i = 0; i < iSize; ++i) {
+ if (piColIndices[i] == iVolumeIndex) {
+ SDetector2D s;
+ s.m_iIndex = iRayIndex;
+ s.m_iAngleIndex = iAngle;
+ s.m_iDetectorIndex = iDetector;
+ ret.push_back(s);
+ break;
+ } else if (piColIndices[i] > iVolumeIndex) {
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+//----------------------------------------------------------------------------------------
diff --git a/src/Utilities.cpp b/src/Utilities.cpp
new file mode 100644
index 0000000..94992a9
--- /dev/null
+++ b/src/Utilities.cpp
@@ -0,0 +1,128 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/Utilities.h"
+
+using namespace std;
+using namespace astra;
+
+//-----------------------------------------------------------------------------
+// Trim Whitespace Characters
+void StringUtil::trim(std::string& _sString, bool _bLeft, bool _bRight)
+{
+ // trim right
+ if (_bRight)
+ _sString.erase(_sString.find_last_not_of(" \t\r") + 1);
+
+ // trim left
+ if (_bLeft)
+ _sString.erase(0, _sString.find_first_not_of(" \t\r"));
+}
+//-----------------------------------------------------------------------------
+// Split String
+vector<string> StringUtil::split(const string& _sString, const string& _sDelims)
+{
+ std::vector<string> ret;
+
+ size_t start, pos;
+ start = 0;
+ do {
+ pos = _sString.find_first_of(_sDelims, start);
+ if (pos == start) {
+ // Do nothing
+ start = pos + 1;
+ } else if (pos == string::npos) {
+ // Copy the rest of the string
+ ret.push_back(_sString.substr(start));
+ break;
+ } else {
+ // Copy up to newt delimiter
+ ret.push_back(_sString.substr(start, pos - start));
+ start = pos + 1;
+ }
+
+ // Parse up to next real data (in case there are two delims after each other)
+ start = _sString.find_first_not_of(_sDelims, start);
+ } while (pos != string::npos);
+
+ return ret;
+}
+//-----------------------------------------------------------------------------
+// Cast string to int
+bool StringUtil::toInt(const string& _sString, int& _iValue)
+{
+ std::istringstream ss(_sString);
+ ss >> _iValue;
+ return !ss.fail();
+}
+//-----------------------------------------------------------------------------
+// Cast string to float
+bool StringUtil::toFloat32(const string& _sString, float32& _fValue)
+{
+ std::istringstream ss(_sString);
+ ss >> _fValue;
+ return !ss.fail();
+}
+//-----------------------------------------------------------------------------
+// Convert string to Lower Case
+void StringUtil::toLowerCase(std::string& _sString)
+{
+ std::transform(_sString.begin(),
+ _sString.end(),
+ _sString.begin(),
+ ::tolower);
+}
+//-----------------------------------------------------------------------------
+// Convert string to Upper Case
+void StringUtil::toUpperCase(std::string& _sString)
+{
+ std::transform(_sString.begin(),
+ _sString.end(),
+ _sString.begin(),
+ ::toupper);
+}
+//-----------------------------------------------------------------------------
+
+
+
+
+//-----------------------------------------------------------------------------
+// Get Extension
+string FileSystemUtil::getExtension(string& _sFilename)
+{
+ string sExtension = "";
+ for (int i = _sFilename.length() - 1; 0 < i; i--) {
+ if (_sFilename[i] == '.') {
+ std::transform(sExtension.begin(),sExtension.end(),sExtension.begin(),::tolower);
+ return sExtension;
+ }
+ sExtension = _sFilename[i] + sExtension;
+ }
+ return "";
+}
+//-----------------------------------------------------------------------------
diff --git a/src/Vector3D.cpp b/src/Vector3D.cpp
new file mode 100644
index 0000000..1e571b1
--- /dev/null
+++ b/src/Vector3D.cpp
@@ -0,0 +1,29 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "../include/astra/Vector3D.h"
diff --git a/src/VolumeGeometry2D.cpp b/src/VolumeGeometry2D.cpp
new file mode 100644
index 0000000..01d9b9a
--- /dev/null
+++ b/src/VolumeGeometry2D.cpp
@@ -0,0 +1,282 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/VolumeGeometry2D.h"
+
+#include <boost/lexical_cast.hpp>
+#include <cmath>
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Check all variable values
+bool CVolumeGeometry2D::_check()
+{
+ ASTRA_CONFIG_CHECK(m_iGridColCount > 0, "VolumeGeometry2D", "GridColCount must be strictly positive.");
+ ASTRA_CONFIG_CHECK(m_iGridRowCount > 0, "VolumeGeometry2D", "GridRowCount must be strictly positive.");
+ ASTRA_CONFIG_CHECK(m_fWindowMinX < m_fWindowMaxX, "VolumeGeometry2D", "WindowMinX should be lower than WindowMaxX.");
+ ASTRA_CONFIG_CHECK(m_fWindowMinY < m_fWindowMaxY, "VolumeGeometry2D", "WindowMinY should be lower than WindowMaxY.");
+
+ ASTRA_CONFIG_CHECK(m_iGridTotCount == (m_iGridColCount * m_iGridRowCount), "VolumeGeometry2D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fWindowLengthX == (m_fWindowMaxX - m_fWindowMinX), "VolumeGeometry2D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fWindowLengthY == (m_fWindowMaxY - m_fWindowMinY), "VolumeGeometry2D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fWindowArea == (m_fWindowLengthX * m_fWindowLengthY), "VolumeGeometry2D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fPixelLengthX == (m_fWindowLengthX / (float32)m_iGridColCount), "VolumeGeometry2D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fPixelLengthY == (m_fWindowLengthY / (float32)m_iGridRowCount), "VolumeGeometry2D", "Internal configuration error.");
+
+ ASTRA_CONFIG_CHECK(m_fPixelArea == (m_fPixelLengthX * m_fPixelLengthY), "VolumeGeometry2D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(fabsf(m_fDivPixelLengthX * m_fPixelLengthX - 1.0f) < eps, "VolumeGeometry2D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(fabsf(m_fDivPixelLengthY * m_fPixelLengthY - 1.0f) < eps, "VolumeGeometry2D", "Internal configuration error.");
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+void CVolumeGeometry2D::clear()
+{
+ m_iGridColCount = 0;
+ m_iGridRowCount = 0;
+ m_iGridTotCount = 0;
+
+ m_fWindowLengthX = 0.0f;
+ m_fWindowLengthY = 0.0f;
+ m_fWindowArea = 0.0f;
+
+ m_fPixelLengthX = 0.0f;
+ m_fPixelLengthY = 0.0f;
+ m_fPixelArea = 0.0f;
+
+ m_fDivPixelLengthX = 0.0f;
+ m_fDivPixelLengthY = 0.0f;
+
+ m_fWindowMinX = 0.0f;
+ m_fWindowMinY = 0.0f;
+ m_fWindowMaxX = 0.0f;
+ m_fWindowMaxY = 0.0f;
+
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CVolumeGeometry2D::CVolumeGeometry2D() : configCheckData(0)
+{
+ clear();
+}
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CVolumeGeometry2D::CVolumeGeometry2D(int _iGridColCount, int _iGridRowCount)
+ : configCheckData(0)
+{
+ clear();
+ initialize(_iGridColCount, _iGridRowCount);
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CVolumeGeometry2D::CVolumeGeometry2D(int _iGridColCount,
+ int _iGridRowCount,
+ float32 _fWindowMinX,
+ float32 _fWindowMinY,
+ float32 _fWindowMaxX,
+ float32 _fWindowMaxY)
+{
+ clear();
+ initialize(_iGridColCount,
+ _iGridRowCount,
+ _fWindowMinX,
+ _fWindowMinY,
+ _fWindowMaxX,
+ _fWindowMaxY);
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CVolumeGeometry2D::~CVolumeGeometry2D()
+{
+ if (m_bInitialized) {
+ clear();
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CVolumeGeometry2D* CVolumeGeometry2D::clone()
+{
+ CVolumeGeometry2D* res = new CVolumeGeometry2D();
+ res->m_bInitialized = m_bInitialized;
+ res->m_iGridColCount = m_iGridColCount;
+ res->m_iGridRowCount = m_iGridRowCount;
+ res->m_iGridTotCount = m_iGridTotCount;
+ res->m_fWindowLengthX = m_fWindowLengthX;
+ res->m_fWindowLengthY = m_fWindowLengthY;
+ res->m_fWindowArea = m_fWindowArea;
+ res->m_fPixelLengthX = m_fPixelLengthX;
+ res->m_fPixelLengthY = m_fPixelLengthY;
+ res->m_fPixelArea = m_fPixelArea;
+ res->m_fDivPixelLengthX = m_fDivPixelLengthX;
+ res->m_fDivPixelLengthY = m_fDivPixelLengthY;
+ res->m_fWindowMinX = m_fWindowMinX;
+ res->m_fWindowMinY = m_fWindowMinY;
+ res->m_fWindowMaxX = m_fWindowMaxX;
+ res->m_fWindowMaxY = m_fWindowMaxY;
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization witha COnfig object
+bool CVolumeGeometry2D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CVolumeGeometry2D> CC("VolumeGeometry2D", this, _cfg);
+
+ // uninitialize if the object was initialized before
+ if (m_bInitialized) {
+ clear();
+ }
+
+ // Required: GridColCount
+ XMLNode* node = _cfg.self->getSingleNode("GridColCount");
+ ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridColCount tag specified.");
+ m_iGridColCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("GridColCount");
+
+ // Required: GridRowCount
+ node = _cfg.self->getSingleNode("GridRowCount");
+ ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridRowCount tag specified.");
+ m_iGridRowCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("GridRowCount");
+
+ // Optional: Window minima and maxima
+ m_fWindowMinX = _cfg.self->getOptionNumerical("WindowMinX", -m_iGridColCount/2.0f);
+ m_fWindowMaxX = _cfg.self->getOptionNumerical("WindowMaxX", m_iGridColCount/2.0f);
+ m_fWindowMinY = _cfg.self->getOptionNumerical("WindowMinY", -m_iGridRowCount/2.0f);
+ m_fWindowMaxY = _cfg.self->getOptionNumerical("WindowMaxY", m_iGridRowCount/2.0f);
+ CC.markOptionParsed("WindowMinX");
+ CC.markOptionParsed("WindowMaxX");
+ CC.markOptionParsed("WindowMinY");
+ CC.markOptionParsed("WindowMaxY");
+
+ _calculateDependents();
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CVolumeGeometry2D::initialize(int _iGridColCount, int _iGridRowCount)
+{
+ return initialize(_iGridColCount,
+ _iGridRowCount,
+ -_iGridColCount/2.0f,
+ -_iGridRowCount/2.0f,
+ _iGridColCount/2.0f,
+ _iGridRowCount/2.0f);
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CVolumeGeometry2D::initialize(int _iGridColCount,
+ int _iGridRowCount,
+ float32 _fWindowMinX,
+ float32 _fWindowMinY,
+ float32 _fWindowMaxX,
+ float32 _fWindowMaxY)
+{
+ if (m_bInitialized) {
+ clear();
+ }
+
+ m_iGridColCount = _iGridColCount;
+ m_iGridRowCount = _iGridRowCount;
+
+ m_fWindowMinX = _fWindowMinX;
+ m_fWindowMinY = _fWindowMinY;
+ m_fWindowMaxX = _fWindowMaxX;
+ m_fWindowMaxY = _fWindowMaxY;
+
+ _calculateDependents();
+
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+void CVolumeGeometry2D::_calculateDependents()
+{
+ m_iGridTotCount = (m_iGridColCount * m_iGridRowCount);
+
+ m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX);
+ m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY);
+ m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY);
+
+ m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount);
+ m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount);
+ m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY);
+
+ m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX);
+ m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY);
+}
+
+//----------------------------------------------------------------------------------------
+// is of type
+bool CVolumeGeometry2D::isEqual(CVolumeGeometry2D* _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !_pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iGridColCount != _pGeom2->m_iGridColCount) return false;
+ if (m_iGridRowCount != _pGeom2->m_iGridRowCount) return false;
+ if (m_iGridTotCount != _pGeom2->m_iGridTotCount) return false;
+ if (m_fWindowLengthX != _pGeom2->m_fWindowLengthX) return false;
+ if (m_fWindowLengthY != _pGeom2->m_fWindowLengthY) return false;
+ if (m_fWindowArea != _pGeom2->m_fWindowArea) return false;
+ if (m_fPixelLengthX != _pGeom2->m_fPixelLengthX) return false;
+ if (m_fPixelLengthY != _pGeom2->m_fPixelLengthY) return false;
+ if (m_fPixelArea != _pGeom2->m_fPixelArea) return false;
+ if (m_fDivPixelLengthX != _pGeom2->m_fDivPixelLengthX) return false;
+ if (m_fDivPixelLengthY != _pGeom2->m_fDivPixelLengthY) return false;
+ if (m_fWindowMinX != _pGeom2->m_fWindowMinX) return false;
+ if (m_fWindowMinY != _pGeom2->m_fWindowMinY) return false;
+ if (m_fWindowMaxX != _pGeom2->m_fWindowMaxX) return false;
+ if (m_fWindowMaxY != _pGeom2->m_fWindowMaxY) return false;
+
+ return true;
+}
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/VolumeGeometry3D.cpp b/src/VolumeGeometry3D.cpp
new file mode 100644
index 0000000..86b8642
--- /dev/null
+++ b/src/VolumeGeometry3D.cpp
@@ -0,0 +1,384 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/VolumeGeometry3D.h"
+
+#include <boost/lexical_cast.hpp>
+
+namespace astra
+{
+
+//----------------------------------------------------------------------------------------
+// Check all variable values
+bool CVolumeGeometry3D::_check()
+{
+ ASTRA_CONFIG_CHECK(m_iGridColCount > 0, "VolumeGeometry3D", "GridColCount must be strictly positive.");
+ ASTRA_CONFIG_CHECK(m_iGridRowCount > 0, "VolumeGeometry3D", "GridRowCount must be strictly positive.");
+ ASTRA_CONFIG_CHECK(m_iGridSliceCount > 0, "VolumeGeometry3D", "GridSliceCount must be strictly positive.");
+ ASTRA_CONFIG_CHECK(m_fWindowMinX < m_fWindowMaxX, "VolumeGeometry3D", "WindowMinX should be lower than WindowMaxX.");
+ ASTRA_CONFIG_CHECK(m_fWindowMinY < m_fWindowMaxY, "VolumeGeometry3D", "WindowMinY should be lower than WindowMaxY.");
+ ASTRA_CONFIG_CHECK(m_fWindowMinZ < m_fWindowMaxZ, "VolumeGeometry3D", "WindowMinZ should be lower than WindowMaxZ.");
+
+ ASTRA_CONFIG_CHECK(m_iGridTotCount == (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fWindowLengthX == (m_fWindowMaxX - m_fWindowMinX), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fWindowLengthY == (m_fWindowMaxY - m_fWindowMinY), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fWindowLengthZ == (m_fWindowMaxZ - m_fWindowMinZ), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fWindowArea == (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fPixelLengthX == (m_fWindowLengthX / (float32)m_iGridColCount), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fPixelLengthY == (m_fWindowLengthY / (float32)m_iGridRowCount), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fPixelLengthZ == (m_fWindowLengthZ / (float32)m_iGridSliceCount), "VolumeGeometry3D", "Internal configuration error.");
+
+ ASTRA_CONFIG_CHECK(m_fPixelArea == (m_fPixelLengthX * m_fPixelLengthY * m_fPixelLengthZ), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fDivPixelLengthX == (1.0f / m_fPixelLengthX), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fDivPixelLengthY == (1.0f / m_fPixelLengthY), "VolumeGeometry3D", "Internal configuration error.");
+ ASTRA_CONFIG_CHECK(m_fDivPixelLengthZ == (1.0f / m_fPixelLengthZ), "VolumeGeometry3D", "Internal configuration error.");
+
+ return true;
+}
+
+//----------------------------------------------------------------------------------------
+// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL.
+void CVolumeGeometry3D::clear()
+{
+ m_iGridColCount = 0;
+ m_iGridRowCount = 0;
+ m_iGridSliceCount = 0;
+ m_iGridTotCount = 0;
+
+ m_fWindowLengthX = 0.0f;
+ m_fWindowLengthY = 0.0f;
+ m_fWindowLengthZ = 0.0f;
+ m_fWindowArea = 0.0f;
+
+ m_fPixelLengthX = 0.0f;
+ m_fPixelLengthY = 0.0f;
+ m_fPixelLengthZ = 0.0f;
+ m_fPixelArea = 0.0f;
+
+ m_fDivPixelLengthX = 0.0f;
+ m_fDivPixelLengthY = 0.0f;
+ m_fDivPixelLengthZ = 0.0f;
+
+ m_fWindowMinX = 0.0f;
+ m_fWindowMinY = 0.0f;
+ m_fWindowMinZ = 0.0f;
+ m_fWindowMaxX = 0.0f;
+ m_fWindowMaxY = 0.0f;
+ m_fWindowMaxZ = 0.0f;
+
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Default constructor.
+CVolumeGeometry3D::CVolumeGeometry3D() : configCheckData(0)
+{
+ clear();
+ m_bInitialized = false;
+}
+
+//----------------------------------------------------------------------------------------
+// Default constructor
+CVolumeGeometry3D::CVolumeGeometry3D(int _iGridColCount, int _iGridRowCount, int _iGridSliceCount)
+ : configCheckData(0)
+{
+ clear();
+ initialize(_iGridColCount, _iGridRowCount, _iGridSliceCount);
+}
+
+//----------------------------------------------------------------------------------------
+// Constructor.
+CVolumeGeometry3D::CVolumeGeometry3D(int _iGridColCount,
+ int _iGridRowCount,
+ int _iGridSliceCount,
+ float32 _fWindowMinX,
+ float32 _fWindowMinY,
+ float32 _fWindowMinZ,
+ float32 _fWindowMaxX,
+ float32 _fWindowMaxY,
+ float32 _fWindowMaxZ)
+{
+ clear();
+ initialize(_iGridColCount,
+ _iGridRowCount,
+ _iGridSliceCount,
+ _fWindowMinX,
+ _fWindowMinY,
+ _fWindowMinZ,
+ _fWindowMaxX,
+ _fWindowMaxY,
+ _fWindowMaxZ);
+}
+
+CVolumeGeometry3D::CVolumeGeometry3D(const CVolumeGeometry3D& _other)
+{
+ *this = _other;
+}
+
+CVolumeGeometry3D& CVolumeGeometry3D::operator=(const CVolumeGeometry3D& _other)
+{
+ m_bInitialized = _other.m_bInitialized;
+ m_iGridColCount = _other.m_iGridColCount;
+ m_iGridRowCount = _other.m_iGridRowCount;
+ m_iGridSliceCount = _other.m_iGridSliceCount;
+ m_fWindowLengthX = _other.m_fWindowLengthX;
+ m_fWindowLengthY = _other.m_fWindowLengthY;
+ m_fWindowLengthZ = _other.m_fWindowLengthZ;
+ m_fWindowArea = _other.m_fWindowArea;
+ m_fPixelLengthX = _other.m_fPixelLengthX;
+ m_fPixelLengthY = _other.m_fPixelLengthY;
+ m_fPixelLengthZ = _other.m_fPixelLengthZ;
+ m_fDivPixelLengthX = _other.m_fDivPixelLengthX;
+ m_fDivPixelLengthY = _other.m_fDivPixelLengthY;
+ m_fDivPixelLengthZ = _other.m_fDivPixelLengthZ;
+ m_fWindowMinX = _other.m_fWindowMinX;
+ m_fWindowMinY = _other.m_fWindowMinY;
+ m_fWindowMinZ = _other.m_fWindowMinZ;
+ m_fWindowMaxX = _other.m_fWindowMaxX;
+ m_fWindowMaxY = _other.m_fWindowMaxY;
+ m_fWindowMaxZ = _other.m_fWindowMaxZ;
+
+ m_iGridTotCount = _other.m_iGridTotCount;
+ m_fPixelArea = _other.m_fPixelArea;
+
+ return *this;
+}
+
+//----------------------------------------------------------------------------------------
+// Destructor.
+CVolumeGeometry3D::~CVolumeGeometry3D()
+{
+ if (m_bInitialized) {
+ clear();
+ }
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization with a Config object
+bool CVolumeGeometry3D::initialize(const Config& _cfg)
+{
+ ASTRA_ASSERT(_cfg.self);
+ ConfigStackCheck<CVolumeGeometry3D> CC("VolumeGeometry3D", this, _cfg);
+
+
+ // uninitialize if the object was initialized before
+ if (m_bInitialized) {
+ clear();
+ }
+
+ // Required: GridColCount
+ XMLNode* node = _cfg.self->getSingleNode("GridColCount");
+ ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridColCount tag specified.");
+ m_iGridColCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("GridColCount");
+
+ // Required: GridRowCount
+ node = _cfg.self->getSingleNode("GridRowCount");
+ ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridRowCount tag specified.");
+ m_iGridRowCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("GridRowCount");
+
+ // Required: GridRowCount
+ node = _cfg.self->getSingleNode("GridSliceCount");
+ ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridSliceCount tag specified.");
+ m_iGridSliceCount = boost::lexical_cast<int>(node->getContent());
+ ASTRA_DELETE(node);
+ CC.markNodeParsed("GridSliceCount");
+
+ // Optional: Window minima and maxima
+ m_fWindowMinX = _cfg.self->getOptionNumerical("WindowMinX", -m_iGridColCount/2.0f);
+ m_fWindowMaxX = _cfg.self->getOptionNumerical("WindowMaxX", m_iGridColCount/2.0f);
+ m_fWindowMinY = _cfg.self->getOptionNumerical("WindowMinY", -m_iGridRowCount/2.0f);
+ m_fWindowMaxY = _cfg.self->getOptionNumerical("WindowMaxY", m_iGridRowCount/2.0f);
+ m_fWindowMinZ = _cfg.self->getOptionNumerical("WindowMinZ", -m_iGridSliceCount/2.0f);
+ m_fWindowMaxZ = _cfg.self->getOptionNumerical("WindowMaxZ", m_iGridSliceCount/2.0f);
+ CC.markOptionParsed("WindowMinX");
+ CC.markOptionParsed("WindowMaxX");
+ CC.markOptionParsed("WindowMinY");
+ CC.markOptionParsed("WindowMaxY");
+ CC.markOptionParsed("WindowMinZ");
+ CC.markOptionParsed("WindowMaxZ");
+
+ // calculate some other things
+ m_iGridTotCount = (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount);
+ m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX);
+ m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY);
+ m_fWindowLengthZ = (m_fWindowMaxZ - m_fWindowMinZ);
+ m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ);
+ m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount);
+ m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount);
+ m_fPixelLengthZ = (m_fWindowLengthZ / (float32)m_iGridSliceCount);
+
+ m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY * m_fPixelLengthZ);
+ m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX);
+ m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY);
+ m_fDivPixelLengthZ = ((float32)m_iGridSliceCount / m_fWindowLengthZ); // == (1.0f / m_fPixelLengthZ);
+
+ // success
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CVolumeGeometry3D::initialize(int _iGridColCount, int _iGridRowCount, int _iGridSliceCount)
+{
+ return initialize(_iGridColCount,
+ _iGridRowCount,
+ _iGridSliceCount,
+ -_iGridColCount/2.0f,
+ -_iGridRowCount/2.0f,
+ -_iGridSliceCount/2.0f,
+ _iGridColCount/2.0f,
+ _iGridRowCount/2.0f,
+ _iGridSliceCount/2.0f);
+}
+
+//----------------------------------------------------------------------------------------
+// Initialization.
+bool CVolumeGeometry3D::initialize(int _iGridColCount,
+ int _iGridRowCount,
+ int _iGridSliceCount,
+ float32 _fWindowMinX,
+ float32 _fWindowMinY,
+ float32 _fWindowMinZ,
+ float32 _fWindowMaxX,
+ float32 _fWindowMaxY,
+ float32 _fWindowMaxZ)
+{
+ if (m_bInitialized) {
+ clear();
+ }
+
+ m_iGridColCount = _iGridColCount;
+ m_iGridRowCount = _iGridRowCount;
+ m_iGridSliceCount = _iGridSliceCount;
+ m_iGridTotCount = (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount);
+
+ m_fWindowMinX = _fWindowMinX;
+ m_fWindowMinY = _fWindowMinY;
+ m_fWindowMinZ = _fWindowMinZ;
+ m_fWindowMaxX = _fWindowMaxX;
+ m_fWindowMaxY = _fWindowMaxY;
+ m_fWindowMaxZ = _fWindowMaxZ;
+
+ m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX);
+ m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY);
+ m_fWindowLengthZ = (m_fWindowMaxZ - m_fWindowMinZ);
+ m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ);
+
+ m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount);
+ m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount);
+ m_fPixelLengthZ = (m_fWindowLengthZ / (float32)m_iGridSliceCount);
+ m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY);
+
+ m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX);
+ m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY);
+ m_fDivPixelLengthZ = ((float32)m_iGridSliceCount / m_fWindowLengthZ); // == (1.0f / m_fPixelLengthZ);
+
+ m_bInitialized = _check();
+ return m_bInitialized;
+}
+
+//----------------------------------------------------------------------------------------
+// Clone
+CVolumeGeometry3D* CVolumeGeometry3D::clone() const
+{
+ CVolumeGeometry3D* res = new CVolumeGeometry3D();
+ res->m_bInitialized = m_bInitialized;
+ res->m_iGridColCount = m_iGridColCount;
+ res->m_iGridRowCount = m_iGridRowCount;
+ res->m_iGridSliceCount = m_iGridSliceCount;
+ res->m_iGridTotCount = m_iGridTotCount;
+ res->m_fWindowLengthX = m_fWindowLengthX;
+ res->m_fWindowLengthY = m_fWindowLengthY;
+ res->m_fWindowLengthZ = m_fWindowLengthZ;
+ res->m_fWindowArea = m_fWindowArea;
+ res->m_fPixelLengthX = m_fPixelLengthX;
+ res->m_fPixelLengthY = m_fPixelLengthY;
+ res->m_fPixelLengthZ = m_fPixelLengthZ;
+ res->m_fPixelArea = m_fPixelArea;
+ res->m_fDivPixelLengthX = m_fDivPixelLengthX;
+ res->m_fDivPixelLengthY = m_fDivPixelLengthY;
+ res->m_fDivPixelLengthZ = m_fDivPixelLengthZ;
+ res->m_fWindowMinX = m_fWindowMinX;
+ res->m_fWindowMinY = m_fWindowMinY;
+ res->m_fWindowMinZ = m_fWindowMinZ;
+ res->m_fWindowMaxX = m_fWindowMaxX;
+ res->m_fWindowMaxY = m_fWindowMaxY;
+ res->m_fWindowMaxZ = m_fWindowMaxZ;
+ return res;
+}
+
+//----------------------------------------------------------------------------------------
+// is of type
+bool CVolumeGeometry3D::isEqual(const CVolumeGeometry3D* _pGeom2) const
+{
+ if (_pGeom2 == NULL) return false;
+
+ // both objects must be initialized
+ if (!m_bInitialized || !_pGeom2->m_bInitialized) return false;
+
+ // check all values
+ if (m_iGridColCount != _pGeom2->m_iGridColCount) return false;
+ if (m_iGridRowCount != _pGeom2->m_iGridRowCount) return false;
+ if (m_iGridSliceCount != _pGeom2->m_iGridSliceCount) return false;
+ if (m_iGridTotCount != _pGeom2->m_iGridTotCount) return false;
+ if (m_fWindowLengthX != _pGeom2->m_fWindowLengthX) return false;
+ if (m_fWindowLengthY != _pGeom2->m_fWindowLengthY) return false;
+ if (m_fWindowLengthZ != _pGeom2->m_fWindowLengthZ) return false;
+ if (m_fWindowArea != _pGeom2->m_fWindowArea) return false;
+ if (m_fPixelLengthX != _pGeom2->m_fPixelLengthX) return false;
+ if (m_fPixelLengthY != _pGeom2->m_fPixelLengthY) return false;
+ if (m_fPixelLengthZ != _pGeom2->m_fPixelLengthZ) return false;
+ if (m_fPixelArea != _pGeom2->m_fPixelArea) return false;
+ if (m_fDivPixelLengthX != _pGeom2->m_fDivPixelLengthX) return false;
+ if (m_fDivPixelLengthY != _pGeom2->m_fDivPixelLengthY) return false;
+ if (m_fDivPixelLengthZ != _pGeom2->m_fDivPixelLengthZ) return false;
+ if (m_fWindowMinX != _pGeom2->m_fWindowMinX) return false;
+ if (m_fWindowMinY != _pGeom2->m_fWindowMinY) return false;
+ if (m_fWindowMinZ != _pGeom2->m_fWindowMinZ) return false;
+ if (m_fWindowMaxX != _pGeom2->m_fWindowMaxX) return false;
+ if (m_fWindowMaxY != _pGeom2->m_fWindowMaxY) return false;
+ if (m_fWindowMaxZ != _pGeom2->m_fWindowMaxZ) return false;
+
+ return true;
+}
+
+CVolumeGeometry2D * CVolumeGeometry3D::createVolumeGeometry2D() const
+{
+ CVolumeGeometry2D * pOutput = new CVolumeGeometry2D();
+ pOutput->initialize(getGridColCount(), getGridRowCount());
+ return pOutput;
+}
+
+//----------------------------------------------------------------------------------------
+
+} // namespace astra
diff --git a/src/XMLDocument.cpp b/src/XMLDocument.cpp
new file mode 100644
index 0000000..96d0f80
--- /dev/null
+++ b/src/XMLDocument.cpp
@@ -0,0 +1,112 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/XMLDocument.h"
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+#ifdef _MSC_VER
+#include "rapidxml/rapidxml.hpp"
+#include "rapidxml/rapidxml_print.hpp"
+#else
+#include "rapidxml.hpp"
+#include "rapidxml_print.hpp"
+#endif
+
+using namespace rapidxml;
+using namespace astra;
+using namespace std;
+
+
+
+//-----------------------------------------------------------------------------
+XMLDocument::XMLDocument()
+{
+ fDOMDocument = 0;
+}
+
+//-----------------------------------------------------------------------------
+XMLDocument::~XMLDocument()
+{
+ delete fDOMDocument;
+ //parser->release();
+}
+
+//-----------------------------------------------------------------------------
+XMLDocument* XMLDocument::readFromFile(string filename)
+{
+ // create the document
+ XMLDocument* res = new XMLDocument();
+ res->fDOMDocument = new xml_document<>();
+
+ std::ifstream file(filename.c_str());
+ std::stringstream reader;
+ reader << file.rdbuf();
+ res->fBuf = reader.str();
+
+ res->fDOMDocument->parse<0>((char*)res->fBuf.c_str());
+
+ // return the document
+ return res;
+
+}
+
+//-----------------------------------------------------------------------------
+// create an XML document with an empty root node
+XMLDocument* XMLDocument::createDocument(string sRootName)
+{
+ XMLDocument* res = new XMLDocument();
+ res->fDOMDocument = new xml_document<>();
+
+ char *node_name = res->fDOMDocument->allocate_string(sRootName.c_str());
+ xml_node<> *node = res->fDOMDocument->allocate_node(node_element, node_name);
+
+ res->fDOMDocument->append_node(node);
+
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+XMLNode* XMLDocument::getRootNode()
+{
+ // TODO: clean up: this 'new' requires callers to do memory management
+ return new XMLNode(fDOMDocument->first_node());
+}
+
+//-----------------------------------------------------------------------------
+void XMLDocument::saveToFile(string sFilename)
+{
+ std::ofstream file(sFilename.c_str());
+
+ file << *fDOMDocument;
+}
+
+//-----------------------------------------------------------------------------
+
diff --git a/src/XMLNode.cpp b/src/XMLNode.cpp
new file mode 100644
index 0000000..e47c3e7
--- /dev/null
+++ b/src/XMLNode.cpp
@@ -0,0 +1,499 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#include "astra/XMLNode.h"
+
+#ifdef _MSC_VER
+#include "rapidxml/rapidxml.hpp"
+#include "rapidxml/rapidxml_print.hpp"
+#else
+#include "rapidxml.hpp"
+#include "rapidxml_print.hpp"
+#endif
+
+#include <boost/lexical_cast.hpp>
+
+using namespace rapidxml;
+using namespace astra;
+using namespace std;
+
+
+//-----------------------------------------------------------------------------
+// Utility function to delete a list of nodes
+static void deleteNodes(list<XMLNode*>& nodes)
+{
+ for (list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i)
+ delete (*i);
+
+ nodes.clear();
+}
+
+
+//-----------------------------------------------------------------------------
+// default constructor
+XMLNode::XMLNode()
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// private constructor
+XMLNode::XMLNode(xml_node<>* node)
+{
+ fDOMElement = node;
+}
+
+//-----------------------------------------------------------------------------
+// destructor
+XMLNode::~XMLNode()
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// set DOM node (private)
+void XMLNode::setDOMNode(xml_node<>* n)
+{
+ fDOMElement = n;
+}
+
+//-----------------------------------------------------------------------------
+// print XML Node
+void XMLNode::print()
+{
+ std::cout << fDOMElement;
+}
+
+//-----------------------------------------------------------------------------
+// print XML Node
+std::string XMLNode::toString()
+{
+ std::string s;
+ ::print(std::back_inserter(s), *fDOMElement, 0);
+ return s;
+}
+
+//-----------------------------------------------------------------------------
+// Get single node
+XMLNode* XMLNode::getSingleNode(string name)
+{
+ xml_node<> *node = fDOMElement->first_node(name.c_str());
+
+ if (node)
+ return new XMLNode(node);
+ else
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Get list of nodes
+list<XMLNode*> XMLNode::getNodes(string name)
+{
+ list<XMLNode*> result;
+ xml_node<> *iter;
+ for (iter = fDOMElement->first_node(name.c_str()); iter; iter = iter->next_sibling(name.c_str())) {
+ result.push_back(new XMLNode(iter));
+ }
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// Get list of nodes
+list<XMLNode*> XMLNode::getNodes()
+{
+ list<XMLNode*> result;
+ xml_node<> *iter;
+ for (iter = fDOMElement->first_node(); iter; iter = iter->next_sibling()) {
+ result.push_back(new XMLNode(iter));
+ }
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// Get name of this node
+std::string XMLNode::getName()
+{
+ return fDOMElement->name();
+}
+
+//-----------------------------------------------------------------------------
+// Get node content - STRING
+string XMLNode::getContent()
+{
+ return fDOMElement->value();
+}
+
+//-----------------------------------------------------------------------------
+// Get node content - NUMERICAL
+float32 XMLNode::getContentNumerical()
+{
+ return boost::lexical_cast<float32>(getContent());
+}
+
+//-----------------------------------------------------------------------------
+// Get node content - BOOLEAN
+bool XMLNode::getContentBool()
+{
+ string res = getContent();
+ return ((res == "1") || (res == "yes") || (res == "true") || (res == "on"));
+}
+
+//-----------------------------------------------------------------------------
+// Get node content - STRING LIST
+vector<string> XMLNode::getContentArray()
+{
+ // get listsize
+ int iSize = boost::lexical_cast<int>(getAttribute("listsize"));
+ // create result array
+ vector<string> res(iSize);
+ // loop all list item nodes
+ list<XMLNode*> nodes = getNodes("ListItem");
+ for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+ int iIndex = (*it)->getAttributeNumerical("index");
+ string sValue = (*it)->getAttribute("value");
+ ASTRA_ASSERT(iIndex < iSize);
+ res[iIndex] = sValue;
+ }
+ deleteNodes(nodes);
+
+ // return
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+// Get node content - NUMERICAL LIST
+vector<float32> XMLNode::getContentNumericalArray()
+{
+ // is scalar
+ if (!hasAttribute("listsize")) {
+ vector<float32> res(1);
+ res[0] = getContentNumerical();
+ return res;
+ }
+
+ int iSize = boost::lexical_cast<int>(getAttribute("listsize"));
+ // create result array
+ vector<float32> res(iSize);
+ // loop all list item nodes
+ list<XMLNode*> nodes = getNodes("ListItem");
+ for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+ int iIndex = (*it)->getAttributeNumerical("index");
+ float32 fValue = (*it)->getAttributeNumerical("value");
+ ASTRA_ASSERT(iIndex < iSize);
+ res[iIndex] = fValue;
+ }
+ deleteNodes(nodes);
+ // return
+ return res;
+}
+
+vector<double> XMLNode::getContentNumericalArrayDouble()
+{
+ // is scalar
+ if (!hasAttribute("listsize")) {
+ vector<double> res(1);
+ res[0] = getContentNumerical();
+ return res;
+ }
+
+ int iSize = boost::lexical_cast<int>(getAttribute("listsize"));
+ // create result array
+ vector<double> res(iSize);
+ // loop all list item nodes
+ list<XMLNode*> nodes = getNodes("ListItem");
+ for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+ int iIndex = (*it)->getAttributeNumerical("index");
+ double fValue = (*it)->getAttributeNumericalDouble("value");
+ ASTRA_ASSERT(iIndex < iSize);
+ res[iIndex] = fValue;
+ }
+ deleteNodes(nodes);
+ // return
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+// Get node content - NUMERICAL LIST 2
+void XMLNode::getContentNumericalArray(float32*& _pfData, int& _iSize)
+{
+ // is scalar
+ if (!hasAttribute("listsize")) {
+ _iSize = 1;
+ _pfData = new float32[_iSize];
+ _pfData[0] = getContentNumerical();
+ return;
+ }
+ // get listsize
+ _iSize = boost::lexical_cast<int>(getAttribute("listsize"));
+ // create result array
+ _pfData = new float32[_iSize];
+ // loop all list item nodes
+ list<XMLNode*> nodes = getNodes("ListItem");
+ for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+ int iIndex = (*it)->getAttributeNumerical("index");
+ float32 fValue = (*it)->getAttributeNumerical("value");
+ ASTRA_ASSERT(iIndex < _iSize);
+ _pfData[iIndex] = fValue;
+ }
+ deleteNodes(nodes);
+}
+
+//-----------------------------------------------------------------------------
+// Is attribute?
+bool XMLNode::hasAttribute(string _sName)
+{
+ xml_attribute<> *attr = fDOMElement->first_attribute(_sName.c_str());
+ return (attr != 0);
+}
+
+//-----------------------------------------------------------------------------
+// Get attribute - STRING
+string XMLNode::getAttribute(string _sName, string _sDefaultValue)
+{
+ xml_attribute<> *attr = fDOMElement->first_attribute(_sName.c_str());
+
+ if (!attr) return _sDefaultValue;
+
+ return attr->value();
+}
+
+//-----------------------------------------------------------------------------
+// Get attribute - NUMERICAL
+float32 XMLNode::getAttributeNumerical(string _sName, float32 _fDefaultValue)
+{
+ if (!hasAttribute(_sName)) return _fDefaultValue;
+ return boost::lexical_cast<float32>(getAttribute(_sName));
+}
+double XMLNode::getAttributeNumericalDouble(string _sName, double _fDefaultValue)
+{
+ if (!hasAttribute(_sName)) return _fDefaultValue;
+ return boost::lexical_cast<double>(getAttribute(_sName));
+}
+
+//-----------------------------------------------------------------------------
+// Get attribute - BOOLEAN
+bool XMLNode::getAttributeBool(string _sName, bool _bDefaultValue)
+{
+ if (!hasAttribute(_sName)) return _bDefaultValue;
+ string res = getAttribute(_sName);
+ return ((res == "1") || (res == "yes") || (res == "true") || (res == "on"));
+}
+
+//-----------------------------------------------------------------------------
+// Has option?
+bool XMLNode::hasOption(string _sKey)
+{
+ xml_node<> *iter;
+ for (iter = fDOMElement->first_node("Option"); iter; iter = iter->next_sibling("Option")) {
+ xml_attribute<> *attr = iter->first_attribute("key");
+ if (attr && _sKey == attr->value())
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Get option - STRING
+string XMLNode::getOption(string _sKey, string _sDefaultValue)
+{
+ xml_node<> *iter;
+ for (iter = fDOMElement->first_node("Option"); iter; iter = iter->next_sibling("Option")) {
+ xml_attribute<> *attr = iter->first_attribute("key");
+ if (attr && _sKey == attr->value()) {
+ attr = iter->first_attribute("value");
+ if (!attr)
+ return "";
+ return attr->value();
+ }
+ }
+ return _sDefaultValue;
+}
+
+//-----------------------------------------------------------------------------
+// Get option - NUMERICAL
+float32 XMLNode::getOptionNumerical(string _sKey, float32 _fDefaultValue)
+{
+ if (!hasOption(_sKey)) return _fDefaultValue;
+ return boost::lexical_cast<float32>(getOption(_sKey));
+}
+
+//-----------------------------------------------------------------------------
+// Get option - BOOL
+bool XMLNode::getOptionBool(string _sKey, bool _bDefaultValue)
+{
+ bool bHasOption = hasOption(_sKey);
+ if (!bHasOption) return _bDefaultValue;
+ string res = getOption(_sKey);
+ return ((res == "1") || (res == "yes") || (res == "true") || (res == "on"));
+}
+
+//-----------------------------------------------------------------------------
+// Get option - NUMERICAL ARRAY
+vector<float32> XMLNode::getOptionNumericalArray(string _sKey)
+{
+ if (!hasOption(_sKey)) return vector<float32>();
+
+ list<XMLNode*> nodes = getNodes("Option");
+ for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
+ if ((*it)->getAttribute("key") == _sKey) {
+ vector<float32> vals = (*it)->getContentNumericalArray();
+ deleteNodes(nodes);
+ return vals;
+ }
+ }
+
+ deleteNodes(nodes);
+ return vector<float32>();
+}
+
+//-----------------------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// BUILD NODE
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Add child node - EMPTY
+XMLNode* XMLNode::addChildNode(string _sNodeName)
+{
+ xml_document<> *doc = fDOMElement->document();
+ char *node_name = doc->allocate_string(_sNodeName.c_str());
+ xml_node<> *node = doc->allocate_node(node_element, node_name);
+ fDOMElement->append_node(node);
+
+ // TODO: clean up: this 'new' requires callers to do memory management
+ return new XMLNode(node);
+}
+
+//-----------------------------------------------------------------------------
+// Add child node - STRING
+XMLNode* XMLNode::addChildNode(string _sNodeName, string _sText)
+{
+ XMLNode* res = addChildNode(_sNodeName);
+ res->setContent(_sText);
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+// Add child node - FLOAT
+XMLNode* XMLNode::addChildNode(string _sNodeName, float32 _fValue)
+{
+ XMLNode* res = addChildNode(_sNodeName);
+ res->setContent(_fValue);
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+// Add child node - LIST
+XMLNode* XMLNode::addChildNode(string _sNodeName, float32* _pfList, int _iSize)
+{
+ XMLNode* res = addChildNode(_sNodeName);
+ res->setContent(_pfList, _iSize);
+ return res;
+}
+
+//-----------------------------------------------------------------------------
+// Set content - STRING
+void XMLNode::setContent(string _sText)
+{
+ xml_document<> *doc = fDOMElement->document();
+ char *text = doc->allocate_string(_sText.c_str());
+ fDOMElement->value(text);
+}
+
+//-----------------------------------------------------------------------------
+// Set content - FLOAT
+void XMLNode::setContent(float32 _fValue)
+{
+ setContent(boost::lexical_cast<string>(_fValue));
+}
+
+//-----------------------------------------------------------------------------
+// Set content - LIST
+void XMLNode::setContent(float32* pfList, int _iSize)
+{
+ addAttribute("listsize", _iSize);
+ for (int i = 0; i < _iSize; i++) {
+ XMLNode* item = addChildNode("ListItem");
+ item->addAttribute("index", i);
+ item->addAttribute("value",pfList[i]);
+ delete item;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Add attribute - STRING
+void XMLNode::addAttribute(string _sName, string _sText)
+{
+ xml_document<> *doc = fDOMElement->document();
+ char *name = doc->allocate_string(_sName.c_str());
+ char *text = doc->allocate_string(_sText.c_str());
+ xml_attribute<> *attr = doc->allocate_attribute(name, text);
+ fDOMElement->append_attribute(attr);
+}
+
+//-----------------------------------------------------------------------------
+// Add attribute - FLOAT
+void XMLNode::addAttribute(string _sName, float32 _fValue)
+{
+ addAttribute(_sName, boost::lexical_cast<string>(_fValue));
+}
+
+//-----------------------------------------------------------------------------
+// Add option - STRING
+void XMLNode::addOption(string _sName, string _sText)
+{
+ XMLNode* node = addChildNode("Option");
+ node->addAttribute("key", _sName);
+ node->addAttribute("value", _sText);
+ delete node;
+}
+
+//-----------------------------------------------------------------------------
+// Add option - FLOAT
+void XMLNode::addOption(string _sName, float32 _sText)
+{
+ XMLNode* node = addChildNode("Option");
+ node->addAttribute("key", _sName);
+ node->addAttribute("value", _sText);
+ delete node;
+}
+//-----------------------------------------------------------------------------
+
+
diff --git a/src/astra.def b/src/astra.def
new file mode 100644
index 0000000..585324c
--- /dev/null
+++ b/src/astra.def
@@ -0,0 +1,6 @@
+; MatlabDLL.def : Declares the module parameters for the DLL.
+
+LIBRARY "astra"
+
+EXPORTS
+ ; Explicit exports can go here
diff --git a/src/swrap.cpp b/src/swrap.cpp
new file mode 100644
index 0000000..be8238e
--- /dev/null
+++ b/src/swrap.cpp
@@ -0,0 +1,47 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+#ifndef _MSC_VER
+
+#include "astra/swrap.h"
+#include <cerrno>
+
+errno_t fopen_s(FILE** pFile, const char* filename, const char* mode)
+{
+ if (!pFile)
+ return EINVAL;
+
+ FILE* x = fopen(filename, mode);
+ if (!x)
+ return errno;
+
+ *pFile = x;
+ return 0;
+}
+
+#endif
diff --git a/tests/main.cpp b/tests/main.cpp
new file mode 100644
index 0000000..6fc963e
--- /dev/null
+++ b/tests/main.cpp
@@ -0,0 +1,38 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+
+#define BOOST_TEST_DYN_LINK
+
+// Generate main()
+#define BOOST_AUTO_TEST_MAIN
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
diff --git a/tests/test_AstraObjectManager.cpp b/tests/test_AstraObjectManager.cpp
new file mode 100644
index 0000000..893efb9
--- /dev/null
+++ b/tests/test_AstraObjectManager.cpp
@@ -0,0 +1,79 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+
+#include "astra/AstraObjectManager.h"
+
+namespace astra {
+DEFINE_SINGLETON(CAstraObjectManager<int>);
+}
+
+BOOST_AUTO_TEST_CASE( testAstraObjectManager )
+{
+ astra::CAstraObjectManager<int> man;
+
+ int i1 = man.store(new int(1));
+ BOOST_REQUIRE(man.hasIndex(i1));
+ BOOST_CHECK(*(man.get(i1)) == 1);
+
+ int i2 = man.store(new int(2));
+ BOOST_REQUIRE(man.hasIndex(i2));
+ BOOST_CHECK(*(man.get(i1)) == 1);
+ BOOST_CHECK(*(man.get(i2)) == 2);
+
+ man.remove(i1);
+
+ BOOST_CHECK(!man.hasIndex(i1));
+ BOOST_REQUIRE(man.hasIndex(i2));
+
+ int i3 = man.store(new int(3));
+ BOOST_REQUIRE(man.hasIndex(i3));
+ BOOST_CHECK(*(man.get(i2)) == 2);
+ BOOST_CHECK(*(man.get(i3)) == 3);
+
+ int* pi4 = new int(4);
+ int i4 = man.store(pi4);
+ BOOST_REQUIRE(man.hasIndex(i4));
+ BOOST_CHECK(*(man.get(i2)) == 2);
+ BOOST_CHECK(*(man.get(i3)) == 3);
+ BOOST_CHECK(*(man.get(i4)) == 4);
+
+ BOOST_CHECK(man.getIndex(pi4) == i4);
+
+ man.clear();
+
+ BOOST_CHECK(!man.hasIndex(i1));
+ BOOST_CHECK(!man.hasIndex(i2));
+ BOOST_CHECK(!man.hasIndex(i3));
+ BOOST_CHECK(!man.hasIndex(i4));
+ BOOST_CHECK(!man.getIndex(pi4));
+}
diff --git a/tests/test_FanFlatProjectionGeometry2D.cpp b/tests/test_FanFlatProjectionGeometry2D.cpp
new file mode 100644
index 0000000..a07fbf8
--- /dev/null
+++ b/tests/test_FanFlatProjectionGeometry2D.cpp
@@ -0,0 +1,119 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include <cmath>
+
+#include "astra/FanFlatProjectionGeometry2D.h"
+
+BOOST_AUTO_TEST_CASE( testFanFlatProjectionGeometry2D_Constructor )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f };
+ astra::CFanFlatProjectionGeometry2D geom(4, 8, 0.5f, angles, 1.0f, 2.0f);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK( geom.getProjectionAngleCount() == 4 );
+ BOOST_CHECK( geom.getDetectorCount() == 8 );
+ BOOST_CHECK( geom.getDetectorWidth() == 0.5f );
+ BOOST_CHECK( geom.getProjectionAngle(0) == 0.0f );
+ BOOST_CHECK( geom.getProjectionAngle(1) == 1.0f );
+ BOOST_CHECK( geom.getProjectionAngle(2) == 2.0f );
+ BOOST_CHECK( geom.getProjectionAngle(3) == 3.0f );
+ BOOST_CHECK( geom.getProjectionAngles()[0] == 0.0f );
+ BOOST_CHECK( geom.getProjectionAngles()[3] == 3.0f );
+ BOOST_CHECK( geom.getOriginSourceDistance() == 1.0f );
+ BOOST_CHECK( geom.getOriginDetectorDistance() == 2.0f );
+}
+
+BOOST_AUTO_TEST_CASE( testFanFlatProjectionGeometry2D_Offsets )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f };
+ astra::CFanFlatProjectionGeometry2D geom(4, 8, 0.5f, angles, 1.0f, 2.0f);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK( geom.getSourceDetectorDistance() == 3.0f );
+ BOOST_CHECK_SMALL( geom.getProjectionAngleDegrees(2) - 114.591559026165f, 1e-5f );
+
+ // CHECKME: where is the center of the detector array?
+ BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.0f) == 3.5f );
+ BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.625f) == 4.75f );
+ BOOST_CHECK( geom.detectorOffsetToIndex(-0.1f) == 3 );
+
+ BOOST_CHECK( geom.indexToDetectorOffset(0) == -1.75f );
+ BOOST_CHECK( geom.indexToDetectorOffset(1) == -1.25f );
+
+ int angle, detector;
+ geom.indexToAngleDetectorIndex(10, angle, detector);
+ BOOST_CHECK( angle == 1 );
+ BOOST_CHECK( detector == 2 );
+
+ float t, theta;
+ geom.getRayParams(0, 2, t, theta);
+ BOOST_CHECK_SMALL( tan(theta) + 0.25f, astra::eps );
+ BOOST_CHECK_SMALL( 17.0f*t*t - 1.0f, astra::eps );
+
+ // TODO: add test with large angle
+}
+
+
+BOOST_AUTO_TEST_CASE( testFanFlatProjectionGeometry2D_Clone )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f };
+ astra::CFanFlatProjectionGeometry2D geom(4, 8, 0.5f, angles, 1.0f, 2.0f);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFanFlatProjectionGeometry2D* geom2;
+ geom2 = dynamic_cast<astra::CFanFlatProjectionGeometry2D*>(geom.clone());
+
+ BOOST_REQUIRE( geom2 );
+ BOOST_REQUIRE( geom2->isInitialized() );
+
+ BOOST_CHECK( geom.isEqual(geom2) );
+ BOOST_CHECK( geom2->getProjectionAngleCount() == 4 );
+ BOOST_CHECK( geom2->getDetectorCount() == 8 );
+ BOOST_CHECK( geom2->getDetectorWidth() == 0.5f );
+ BOOST_CHECK( geom2->getProjectionAngle(0) == 0.0f );
+ BOOST_CHECK( geom2->getProjectionAngle(1) == 1.0f );
+ BOOST_CHECK( geom2->getProjectionAngle(2) == 2.0f );
+ BOOST_CHECK( geom2->getProjectionAngle(3) == 3.0f );
+ BOOST_CHECK( geom2->getProjectionAngles()[0] == 0.0f );
+ BOOST_CHECK( geom2->getProjectionAngles()[3] == 3.0f );
+ BOOST_CHECK( geom2->getOriginSourceDistance() == 1.0f );
+ BOOST_CHECK( geom2->getOriginDetectorDistance() == 2.0f );
+ delete geom2;
+}
+
diff --git a/tests/test_Float32Data2D.cpp b/tests/test_Float32Data2D.cpp
new file mode 100644
index 0000000..54d642b
--- /dev/null
+++ b/tests/test_Float32Data2D.cpp
@@ -0,0 +1,229 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include "astra/Float32Data2D.h"
+
+
+// Utility class to test Float32Data2D
+class CTestFloat32Data2D : public astra::CFloat32Data2D {
+public:
+ CTestFloat32Data2D(int _iWidth, int _iHeight)
+ {
+ m_bInitialized = _initialize(_iWidth, _iHeight);
+ }
+ CTestFloat32Data2D(int _iWidth, int _iHeight, const astra::float32* _pfData)
+ {
+ m_bInitialized = _initialize(_iWidth, _iHeight, _pfData);
+ }
+
+ CTestFloat32Data2D(int _iWidth, int _iHeight, astra::float32 _fScalar)
+ {
+ m_bInitialized = _initialize(_iWidth, _iHeight, _fScalar);
+ }
+
+ CTestFloat32Data2D() { }
+
+};
+
+
+struct TestFloat32Data2D {
+ static astra::float32 d[];
+ TestFloat32Data2D() : data(2,2,d)
+ {
+ }
+
+ ~TestFloat32Data2D()
+ {
+ }
+
+ CTestFloat32Data2D data;
+};
+
+astra::float32 TestFloat32Data2D::d[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+
+BOOST_AUTO_TEST_CASE( testFloat32Data2D_Constructor1 )
+{
+ CTestFloat32Data2D data(2,2);
+
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getWidth() == 2 );
+ BOOST_CHECK( data.getHeight() == 2 );
+ BOOST_CHECK( data.getSize() == 4 );
+ BOOST_CHECK( data.getDimensionCount() == 2 );
+
+ BOOST_REQUIRE( data.getDataConst() != 0 );
+ BOOST_REQUIRE( data.getData() != 0 );
+ BOOST_REQUIRE( data.getData2D() != 0 );
+ BOOST_REQUIRE( data.getData2DConst() != 0 );
+ BOOST_REQUIRE( data.getData2D()[0] != 0 );
+ BOOST_REQUIRE( data.getData2DConst()[0] != 0 );
+
+ data.setData(1.0f);
+
+ // CHECKME: should this be necessary?
+ data.updateStatistics();
+
+ BOOST_CHECK( data.getGlobalMin() == 1.0f );
+ BOOST_CHECK( data.getGlobalMax() == 1.0f );
+ BOOST_CHECK( data.getGlobalMean() == 1.0f );
+
+ BOOST_CHECK( data.getData()[0] == 1.0f );
+ BOOST_CHECK( data.getDataConst()[0] == 1.0f );
+ BOOST_CHECK( data.getData2D()[0][0] == 1.0f );
+ BOOST_CHECK( data.getData2DConst()[0][0] == 1.0f );
+}
+
+BOOST_AUTO_TEST_CASE( testFloat32Data2D_Constructor2 )
+{
+ CTestFloat32Data2D data(2,2,1.5f);
+
+ // CHECKME: should this be necessary?
+ data.updateStatistics();
+
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getWidth() == 2 );
+ BOOST_CHECK( data.getHeight() == 2 );
+ BOOST_CHECK( data.getSize() == 4 );
+ BOOST_CHECK( data.getDimensionCount() == 2 );
+
+ BOOST_REQUIRE( data.getDataConst() != 0 );
+ BOOST_REQUIRE( data.getData() != 0 );
+ BOOST_REQUIRE( data.getData2D() != 0 );
+ BOOST_REQUIRE( data.getData2DConst() != 0 );
+ BOOST_REQUIRE( data.getData2D()[0] != 0 );
+ BOOST_REQUIRE( data.getData2DConst()[0] != 0 );
+
+ BOOST_CHECK( data.getGlobalMin() == 1.5f );
+ BOOST_CHECK( data.getGlobalMax() == 1.5f );
+ BOOST_CHECK( data.getGlobalMean() == 1.5f );
+
+ BOOST_CHECK( data.getData()[0] == 1.5f );
+ BOOST_CHECK( data.getDataConst()[0] == 1.5f );
+ BOOST_CHECK( data.getData2D()[0][0] == 1.5f );
+ BOOST_CHECK( data.getData2DConst()[0][0] == 1.5f );
+}
+
+BOOST_AUTO_TEST_CASE( testFloat32Data2D_Constructor3 )
+{
+ astra::float32 d[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ CTestFloat32Data2D data(2,2,d);
+
+ // CHECKME: should this be necessary?
+ data.updateStatistics();
+
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getWidth() == 2 );
+ BOOST_CHECK( data.getHeight() == 2 );
+ BOOST_CHECK( data.getSize() == 4 );
+ BOOST_CHECK( data.getDimensionCount() == 2 );
+
+ BOOST_REQUIRE( data.getDataConst() != 0 );
+ BOOST_REQUIRE( data.getData() != 0 );
+ BOOST_REQUIRE( data.getData2D() != 0 );
+ BOOST_REQUIRE( data.getData2DConst() != 0 );
+ BOOST_REQUIRE( data.getData2D()[0] != 0 );
+ BOOST_REQUIRE( data.getData2DConst()[0] != 0 );
+
+ BOOST_CHECK( data.getGlobalMin() == 1.0f );
+ BOOST_CHECK( data.getGlobalMax() == 4.0f );
+
+ BOOST_CHECK( data.getData()[0] == 1.0f );
+ BOOST_CHECK( data.getDataConst()[0] == 1.0f );
+ BOOST_CHECK( data.getData2D()[0][0] == 1.0f );
+ BOOST_CHECK( data.getData2DConst()[0][0] == 1.0f );
+
+}
+
+BOOST_FIXTURE_TEST_CASE( testFloat32Data2D_Operators, TestFloat32Data2D )
+{
+ // Note: all operations below involve exactly representable floats,
+ // so there is no need to use epsilons in the checks
+
+ data.updateStatistics();
+
+ // FIXME: should those be correct here?
+ BOOST_CHECK( data.getGlobalMin() == 1.0f );
+ BOOST_CHECK( data.getGlobalMax() == 4.0f );
+ BOOST_CHECK( data.getGlobalMean() == 2.5f );
+
+ data *= 2.0f;
+
+ BOOST_CHECK( data.getDataConst()[0] == 2.0f );
+ BOOST_CHECK( data.getDataConst()[3] == 8.0f );
+
+ data /= 0.5f;
+
+ BOOST_CHECK( data.getDataConst()[0] == 4.0f );
+ BOOST_CHECK( data.getDataConst()[3] == 16.0f );
+
+ astra::float32 d[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ CTestFloat32Data2D data2(2,2,d);
+
+ data += data2;
+
+ BOOST_CHECK( data.getDataConst()[0] == 5.0f );
+ BOOST_CHECK( data.getDataConst()[3] == 20.0f );
+
+ data *= data2;
+
+ BOOST_CHECK( data.getDataConst()[0] == 5.0f );
+ BOOST_CHECK( data.getDataConst()[3] == 80.0f );
+
+ data -= data2;
+ BOOST_CHECK( data.getDataConst()[0] == 4.0f );
+ BOOST_CHECK( data.getDataConst()[3] == 76.0f );
+
+ data += 0.5f;
+ BOOST_CHECK( data.getDataConst()[0] == 4.5f );
+ BOOST_CHECK( data.getDataConst()[3] == 76.5f );
+
+ data -= 0.5f;
+ BOOST_CHECK( data.getDataConst()[0] == 4.0f );
+ BOOST_CHECK( data.getDataConst()[3] == 76.0f );
+}
+
+BOOST_FIXTURE_TEST_CASE( testFloat32Data2D_Update, TestFloat32Data2D )
+{
+ data.getData()[2] = 42.0f;
+ data.getData()[1] = -37.0f;
+ data.updateStatistics();
+
+ BOOST_CHECK( data.getGlobalMin() == -37.0f );
+ BOOST_CHECK( data.getGlobalMax() == 42.0f );
+ BOOST_CHECK( data.getGlobalMean() == 2.5f );
+}
diff --git a/tests/test_Float32ProjectionData2D.cpp b/tests/test_Float32ProjectionData2D.cpp
new file mode 100644
index 0000000..1fddeec
--- /dev/null
+++ b/tests/test_Float32ProjectionData2D.cpp
@@ -0,0 +1,115 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include "astra/Float32ProjectionData2D.h"
+#include "astra/ParallelProjectionGeometry2D.h"
+
+// Note: most of the features of CFloat32ProjectionData2D are tested by
+// the CFloat32Data2D tests.
+
+BOOST_AUTO_TEST_CASE( testFloat32ProjectionData2D_Constructor1 )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f };
+ astra::CParallelProjectionGeometry2D geom(2, 4, 0.5f, angles);
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFloat32ProjectionData2D data(&geom);
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getType() == astra::CFloat32Data2D::PROJECTION );
+ BOOST_CHECK( data.getGeometry()->isEqual(&geom) );
+}
+
+BOOST_AUTO_TEST_CASE( testFloat32ProjectionData2D_Constructor2 )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f };
+ astra::float32 d[] = { 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.f };
+ astra::CParallelProjectionGeometry2D geom(2, 4, 0.5f, angles);
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFloat32ProjectionData2D data(&geom, d);
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getType() == astra::CFloat32Data2D::PROJECTION );
+ BOOST_CHECK( data.getGeometry()->isEqual(&geom) );
+
+ // CHECKME: should this be necessary?
+ data.updateStatistics();
+
+ BOOST_CHECK( data.getGlobalMax() == 10.0f );
+}
+
+BOOST_AUTO_TEST_CASE( testFloat32ProjectionData2D_Constructor3 )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f };
+ astra::CParallelProjectionGeometry2D geom(2, 4, 0.5f, angles);
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFloat32ProjectionData2D data(&geom, 3.5f);
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getType() == astra::CFloat32Data2D::PROJECTION );
+ BOOST_CHECK( data.getGeometry()->isEqual(&geom) );
+
+ // CHECKME: should this be necessary?
+ data.updateStatistics();
+
+ BOOST_CHECK( data.getGlobalMax() == 3.5f );
+}
+
+BOOST_AUTO_TEST_CASE( testFloat32ProjectionData2D_Clone )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f };
+ astra::CParallelProjectionGeometry2D geom(2, 4, 0.5f, angles);
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFloat32ProjectionData2D data(&geom, 3.5f);
+ BOOST_REQUIRE( data.isInitialized() );
+
+ astra::CFloat32ProjectionData2D data2(data);
+ BOOST_REQUIRE( data2.isInitialized() );
+
+ BOOST_CHECK( data2.getGeometry()->isEqual(&geom) );
+ BOOST_CHECK( data2.getDataConst()[0] == 3.5f );
+ BOOST_CHECK( data2.getDataConst()[3] == 3.5f );
+
+ astra::CFloat32ProjectionData2D data3;
+ data3 = data;
+ BOOST_REQUIRE( data3.isInitialized() );
+
+ BOOST_CHECK( data3.getGeometry()->isEqual(&geom) );
+ BOOST_CHECK( data3.getDataConst()[0] == 3.5f );
+ BOOST_CHECK( data3.getDataConst()[3] == 3.5f );
+}
diff --git a/tests/test_Float32VolumeData2D.cpp b/tests/test_Float32VolumeData2D.cpp
new file mode 100644
index 0000000..29dde3a
--- /dev/null
+++ b/tests/test_Float32VolumeData2D.cpp
@@ -0,0 +1,110 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include "astra/Float32VolumeData2D.h"
+
+// Note: most of the features of CFloat32VolumeData2D are tested by
+// the CFloat32Data2D tests.
+
+BOOST_AUTO_TEST_CASE( testFloat32VolumeData2D_Constructor1 )
+{
+ astra::CVolumeGeometry2D geom(16, 32);
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFloat32VolumeData2D data(&geom);
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getType() == astra::CFloat32Data2D::VOLUME );
+ BOOST_CHECK( data.getGeometry()->isEqual(&geom) );
+}
+
+BOOST_AUTO_TEST_CASE( testFloat32VolumeData2D_Constructor1odd )
+{
+ astra::CVolumeGeometry2D geom(16, 32);
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFloat32VolumeData2D data(&geom, 1.0f);
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getType() == astra::CFloat32Data2D::VOLUME );
+ BOOST_CHECK( data.getGeometry()->isEqual(&geom) );
+
+ // CHECKME: should this be necessary?
+ data.updateStatistics();
+ BOOST_CHECK( data.getGlobalMax() == 1.0f );
+}
+
+BOOST_AUTO_TEST_CASE( testFloat32VolumeData2D_Constructor2 )
+{
+ astra::float32 d[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ astra::CVolumeGeometry2D geom(2, 2);
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFloat32VolumeData2D data(&geom, d);
+ BOOST_REQUIRE( data.isInitialized() );
+
+ BOOST_CHECK( data.getType() == astra::CFloat32Data2D::VOLUME );
+
+ BOOST_CHECK( data.getGeometry()->isEqual(&geom) );
+
+ // CHECKME: should this be necessary?
+ data.updateStatistics();
+ BOOST_CHECK( data.getGlobalMax() == 4.0f );
+}
+
+BOOST_AUTO_TEST_CASE( testFloat32VolumeData2D_Clone )
+{
+ astra::float32 d[] = { 1.0f, 2.0f, 3.0f, 4.0f };
+ astra::CVolumeGeometry2D geom(2, 2);
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CFloat32VolumeData2D data(&geom, d);
+ BOOST_REQUIRE( data.isInitialized() );
+
+ astra::CFloat32VolumeData2D data2(data);
+ BOOST_REQUIRE( data2.isInitialized() );
+
+ BOOST_CHECK( data2.getGeometry()->isEqual(&geom) );
+ BOOST_CHECK( data2.getDataConst()[0] == 1.0f );
+ BOOST_CHECK( data2.getDataConst()[3] == 4.0f );
+
+ astra::CFloat32VolumeData2D data3;
+ data3 = data;
+ BOOST_REQUIRE( data3.isInitialized() );
+
+ BOOST_CHECK( data3.getGeometry()->isEqual(&geom) );
+ BOOST_CHECK( data3.getDataConst()[0] == 1.0f );
+ BOOST_CHECK( data3.getDataConst()[3] == 4.0f );
+}
diff --git a/tests/test_Fourier.cpp b/tests/test_Fourier.cpp
new file mode 100644
index 0000000..2602edb
--- /dev/null
+++ b/tests/test_Fourier.cpp
@@ -0,0 +1,182 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include "astra/Fourier.h"
+
+BOOST_AUTO_TEST_CASE( testFourier_DFT_1D_1 )
+{
+ astra::float32 inR[5] = { 1.0f, 1.0f, 0.0f, 0.0f, 1.0f };
+ astra::float32 inI[5] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ astra::float32 outR[5];
+ astra::float32 outI[5];
+
+ astra::discreteFourierTransform1D(5, inR, inI, outR, outI, 1, 1, false);
+
+ astra::float32 expected1R[5] = { 3.0f, 1.618034f, -0.618034f, -0.618034f, 1.618034f };
+ for (unsigned int i = 0; i < 5; ++i) {
+ BOOST_CHECK_SMALL(outR[i] - expected1R[i], 0.00001f);
+ BOOST_CHECK_SMALL(outI[i], 0.00001f);
+ }
+
+ astra::discreteFourierTransform1D(5, outR, outI, inR, inI, 1, 1, true);
+ astra::float32 expected2R[5] = { 1.0f, 1.0f, 0.0f, 0.0f, 1.0f };
+ for (unsigned int i = 0; i < 5; ++i) {
+ BOOST_CHECK_SMALL(inR[i] - expected2R[i], 0.00001f);
+ BOOST_CHECK_SMALL(inI[i], 0.00001f);
+ }
+}
+
+BOOST_AUTO_TEST_CASE( testFourier_DFT_2D_1 )
+{
+ astra::float32 inR[25] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f, 1.0f };
+ astra::float32 inI[25] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ astra::float32 outR[25];
+ astra::float32 outI[25];
+
+ astra::discreteFourierTransform2D(5, 5, inR, inI, outR, outI, false);
+
+ astra::float32 expected1R[25] =
+ { 13.0f , 5.236068f, 0.763932f, 0.763932f, 5.236068f,
+ 5.236068f,-0.618034f,-2.0f ,-2.0f ,-0.618034f,
+ 0.763932f,-2.0f , 1.618034f, 1.618034f,-2.0f ,
+ 0.763932f,-2.0f , 1.618034f, 1.618034f,-2.0f ,
+ 5.236068f,-0.618034f,-2.0f ,-2.0f ,-0.618034f };
+ for (unsigned int i = 0; i < 25; ++i) {
+ BOOST_CHECK_SMALL(outR[i] - expected1R[i], 0.00001f);
+ BOOST_CHECK_SMALL(outI[i], 0.00001f);
+ }
+
+ astra::discreteFourierTransform2D(5, 5, outR, outI, inR, inI, true);
+ astra::float32 expected2R[25] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f, 1.0f };
+ for (unsigned int i = 0; i < 25; ++i) {
+ BOOST_CHECK_SMALL(inR[i] - expected2R[i], 0.00001f);
+ BOOST_CHECK_SMALL(inI[i], 0.00001f);
+ }
+
+
+}
+
+
+BOOST_AUTO_TEST_CASE( testFourier_FFT_1D_1 )
+{
+ astra::float32 inR[8] = { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f };
+ astra::float32 inI[8] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ astra::float32 outR[5];
+ astra::float32 outI[5];
+
+ astra::fastTwoPowerFourierTransform1D(8, inR, inI, outR, outI, 1, 1, false);
+
+ astra::float32 expected1R[8] = { 5.0f, 2.414214f, -1.0f, -0.414214f, 1.0f, -0.414214f, -1.0f, 2.414214f };
+ for (unsigned int i = 0; i < 8; ++i) {
+ BOOST_CHECK_SMALL(outR[i] - expected1R[i], 0.00001f);
+ BOOST_CHECK_SMALL(outI[i], 0.00001f);
+ }
+
+ astra::fastTwoPowerFourierTransform1D(8, outR, outI, inR, inI, 1, 1, true);
+ astra::float32 expected2R[8] = { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f };
+ for (unsigned int i = 0; i < 8; ++i) {
+ BOOST_CHECK_SMALL(inR[i] - expected2R[i], 0.00001f);
+ BOOST_CHECK_SMALL(inI[i], 0.00001f);
+ }
+
+}
+
+BOOST_AUTO_TEST_CASE( testFourier_FFT_2D_1 )
+{
+ astra::float32 inR[64] = { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f };
+ astra::float32 inI[64] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+ astra::float32 outR[64];
+ astra::float32 outI[64];
+
+ astra::discreteFourierTransform2D(8, 8, inR, inI, outR, outI, false);
+
+ astra::float32 expected1R[64] =
+ { 25.0f, 12.656854f, 1.0f, 1.343146f, 1.0f, 1.343146f, 1.0f, 12.656854f,
+ 12.656854f, 3.0f, -3.828427f, -1.0f, -1.0f, -1.0f, -3.828427f, 3.0f,
+ 1.0f, -3.828427f, -3.0f, 1.828427f, 1.0f, 1.828427f, -3.0f, -3.828427f,
+ 1.343146f, -1.0f, 1.828427f, 3.0f, -1.0f, 3.0f, 1.828427f, -1.0f,
+ 1.0f, -1.0f, 1.0f, -1.0f, -7.0f, -1.0f, 1.0f, -1.0f,
+ 1.343146f, -1.0f, 1.828427f, 3.0f, -1.0f, 3.0f, 1.828427f, -1.0f,
+ 1.0f, -3.828427f, -3.0f, 1.828427f, 1.0f, 1.828427f, -3.0f, -3.828427f,
+ 12.656854f, 3.0f, -3.828427f, -1.0f, -1.0f, -1.0f, -3.828427f, 3.0f };
+ for (unsigned int i = 0; i < 64; ++i) {
+ BOOST_CHECK_SMALL(outR[i] - expected1R[i], 0.00002f);
+ BOOST_CHECK_SMALL(outI[i], 0.00001f);
+ }
+
+
+ astra::discreteFourierTransform2D(8, 8, outR, outI, inR, inI, true);
+ astra::float32 expected2R[64] = { 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f };
+ for (unsigned int i = 0; i < 64; ++i) {
+ BOOST_CHECK_SMALL(inR[i] - expected2R[i], 0.00001f);
+ BOOST_CHECK_SMALL(inI[i], 0.00001f);
+ }
+
+
+}
+
diff --git a/tests/test_ParallelBeamLineKernelProjector2D.cpp b/tests/test_ParallelBeamLineKernelProjector2D.cpp
new file mode 100644
index 0000000..86bc54f
--- /dev/null
+++ b/tests/test_ParallelBeamLineKernelProjector2D.cpp
@@ -0,0 +1,82 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include "astra/ParallelBeamLineKernelProjector2D.h"
+#include "astra/ParallelProjectionGeometry2D.h"
+#include "astra/VolumeGeometry2D.h"
+
+struct TestParallelBeamLineKernelProjector2D {
+ TestParallelBeamLineKernelProjector2D()
+ {
+ astra::float32 angles[] = { 1.0f };
+ BOOST_REQUIRE( projGeom.initialize(1, 9, 1.0f, angles) );
+ BOOST_REQUIRE( volGeom.initialize(6, 4) );
+ BOOST_REQUIRE( proj.initialize(&projGeom, &volGeom) );
+ }
+ ~TestParallelBeamLineKernelProjector2D()
+ {
+
+ }
+
+ astra::CParallelBeamLineKernelProjector2D proj;
+ astra::CParallelProjectionGeometry2D projGeom;
+ astra::CVolumeGeometry2D volGeom;
+};
+
+BOOST_FIXTURE_TEST_CASE( testParallelBeamLineKernelProjector2D_General, TestParallelBeamLineKernelProjector2D )
+{
+
+}
+
+BOOST_FIXTURE_TEST_CASE( testParallelBeamLineKernelProjector2D_Rectangle, TestParallelBeamLineKernelProjector2D )
+{
+ int iMax = proj.getProjectionWeightsCount(0);
+ BOOST_REQUIRE(iMax > 0);
+
+ astra::SPixelWeight* pPix = new astra::SPixelWeight[iMax];
+ BOOST_REQUIRE(pPix);
+
+ int iCount;
+ proj.computeSingleRayWeights(0, 4, pPix, iMax, iCount);
+ BOOST_REQUIRE(iCount <= iMax);
+
+ astra::float32 fWeight = 0;
+ for (int i = 0; i < iCount; ++i)
+ fWeight += pPix[i].m_fWeight;
+
+ BOOST_CHECK_SMALL(fWeight - 7.13037f, 0.00001f);
+}
+
+
diff --git a/tests/test_ParallelBeamLinearKernelProjector2D.cpp b/tests/test_ParallelBeamLinearKernelProjector2D.cpp
new file mode 100644
index 0000000..9100db4
--- /dev/null
+++ b/tests/test_ParallelBeamLinearKernelProjector2D.cpp
@@ -0,0 +1,172 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include "astra/ParallelBeamLineKernelProjector2D.h"
+#include "astra/ParallelBeamLinearKernelProjector2D.h"
+#include "astra/ParallelBeamStripKernelProjector2D.h"
+#include "astra/ParallelProjectionGeometry2D.h"
+#include "astra/VolumeGeometry2D.h"
+#include "astra/ProjectionGeometry2D.h"
+
+#include <ctime>
+
+using astra::float32;
+
+struct TestParallelBeamLinearKernelProjector2D {
+ TestParallelBeamLinearKernelProjector2D()
+ {
+ astra::float32 angles[] = { 2.6f };
+ BOOST_REQUIRE( projGeom.initialize(1, 3, 1.0f, angles) );
+ BOOST_REQUIRE( volGeom.initialize(3, 2) );
+ BOOST_REQUIRE( proj.initialize(&projGeom, &volGeom) );
+ }
+ ~TestParallelBeamLinearKernelProjector2D()
+ {
+
+ }
+
+ astra::CParallelBeamLinearKernelProjector2D proj;
+ astra::CParallelProjectionGeometry2D projGeom;
+ astra::CVolumeGeometry2D volGeom;
+};
+
+BOOST_FIXTURE_TEST_CASE( testParallelBeamLinearKernelProjector2D_General, TestParallelBeamLinearKernelProjector2D )
+{
+
+}
+
+
+// Compute linear kernel for a single volume pixel/detector pixel combination
+float32 compute_linear_kernel(const astra::CProjectionGeometry2D& projgeom, const astra::CVolumeGeometry2D& volgeom,
+ int iX, int iY, int iDet, float32 fAngle)
+{
+ // projection of center of volume pixel on detector array
+ float32 fDetProj = (iX - (volgeom.getGridColCount()-1.0f)/2.0f ) * volgeom.getPixelLengthX() * cos(fAngle) - (iY - (volgeom.getGridRowCount()-1.0f)/2.0f ) * volgeom.getPixelLengthY() * sin(fAngle);
+
+ // start of detector pixel on detector array
+ float32 fDetStart = projgeom.indexToDetectorOffset(iDet) - 0.5f;
+
+// printf("(%d,%d,%d): %f in (%f,%f)\n", iX,iY,iDet,fDetProj, fDetStart, fDetStart+1.0f);
+
+ // projection of center of next volume pixel on detector array
+ float32 fDetStep;
+ // length of projection ray through volume pixel
+ float32 fWeight;
+
+ if (fabs(cos(fAngle)) > fabs(sin(fAngle))) {
+ fDetStep = volgeom.getPixelLengthY() * fabs(cos(fAngle));
+ fWeight = volgeom.getPixelLengthX() * 1.0f / fabs(cos(fAngle));
+ } else {
+ fDetStep = volgeom.getPixelLengthX() * fabs(sin(fAngle));
+ fWeight = volgeom.getPixelLengthY() * 1.0f / fabs(sin(fAngle));
+ }
+
+// printf("step: %f\n weight: %f\n", fDetStep, fWeight);
+
+ // center of detector pixel on detector array
+ float32 fDetCenter = fDetStart + 0.5f;
+
+ // unweighted contribution of this volume pixel:
+ // linear interpolation between
+ // fDetCenter - fDetStep |---> 0
+ // fDetCenter |---> 1
+ // fDetCenter + fDetStep |---> 0
+ float32 fBase;
+ if (fDetCenter <= fDetProj) {
+ fBase = (fDetCenter - (fDetProj - fDetStep))/fDetStep;
+ } else {
+ fBase = ((fDetProj + fDetStep) - fDetCenter)/fDetStep;
+ }
+// printf("base: %f\n", fBase);
+ if (fBase < 0) fBase = 0;
+ return fBase * fWeight;
+}
+
+BOOST_AUTO_TEST_CASE( testParallelBeamLinearKernelProjector2D_Rectangles )
+{
+ astra::CParallelBeamLinearKernelProjector2D proj;
+ astra::CParallelProjectionGeometry2D projGeom;
+ astra::CVolumeGeometry2D volGeom;
+
+ const unsigned int iRandomTestCount = 100;
+
+ unsigned int iSeed = time(0);
+ srand(iSeed);
+
+ for (unsigned int iTest = 0; iTest < iRandomTestCount; ++iTest) {
+ int iDetectorCount = 1 + (rand() % 100);
+ int iRows = 1 + (rand() % 100);
+ int iCols = 1 + (rand() % 100);
+
+
+ astra::float32 angles[] = { rand() * 2.0f*astra::PI / RAND_MAX };
+ projGeom.initialize(1, iDetectorCount, 0.8f, angles);
+ volGeom.initialize(iCols, iRows);
+ proj.initialize(&projGeom, &volGeom);
+
+ int iMax = proj.getProjectionWeightsCount(0);
+ BOOST_REQUIRE(iMax > 0);
+
+ astra::SPixelWeight* pPix = new astra::SPixelWeight[iMax];
+ BOOST_REQUIRE(pPix);
+
+ astra::float32 fWeight = 0;
+ for (int iDet = 0; iDet < projGeom.getDetectorCount(); ++iDet) {
+ int iCount;
+ proj.computeSingleRayWeights(0, iDet, pPix, iMax, iCount);
+ BOOST_REQUIRE(iCount <= iMax);
+
+ astra::float32 fW = 0;
+ for (int i = 0; i < iCount; ++i) {
+ float32 fTest = compute_linear_kernel(
+ projGeom,
+ volGeom,
+ pPix[i].m_iIndex % volGeom.getGridColCount(),
+ pPix[i].m_iIndex / volGeom.getGridColCount(),
+ iDet,
+ projGeom.getProjectionAngle(0));
+ BOOST_CHECK_SMALL( pPix[i].m_fWeight - fTest, 0.00037f);
+ fW += pPix[i].m_fWeight;
+ }
+
+ fWeight += fW;
+
+ }
+
+ delete[] pPix;
+ }
+}
+
+
diff --git a/tests/test_ParallelProjectionGeometry2D.cpp b/tests/test_ParallelProjectionGeometry2D.cpp
new file mode 100644
index 0000000..809c6fa
--- /dev/null
+++ b/tests/test_ParallelProjectionGeometry2D.cpp
@@ -0,0 +1,120 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include "astra/ParallelProjectionGeometry2D.h"
+
+BOOST_AUTO_TEST_CASE( testParallelProjectionGeometry2D_Constructor )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f };
+ astra::CParallelProjectionGeometry2D geom(4, 8, 0.5f, angles);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK( geom.getProjectionAngleCount() == 4 );
+ BOOST_CHECK( geom.getDetectorCount() == 8 );
+ BOOST_CHECK( geom.getDetectorWidth() == 0.5f );
+ BOOST_CHECK( geom.getProjectionAngle(0) == 0.0f );
+ BOOST_CHECK( geom.getProjectionAngle(1) == 1.0f );
+ BOOST_CHECK( geom.getProjectionAngle(2) == 2.0f );
+ BOOST_CHECK( geom.getProjectionAngle(3) == 3.0f );
+ BOOST_CHECK( geom.getProjectionAngles()[0] == 0.0f );
+ BOOST_CHECK( geom.getProjectionAngles()[3] == 3.0f );
+}
+
+BOOST_AUTO_TEST_CASE( testParallelProjectionGeometry2D_Offsets )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f };
+ astra::CParallelProjectionGeometry2D geom(4, 8, 0.5f, angles);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK_SMALL( geom.getProjectionAngleDegrees(2) - 114.59155902f, 1e-5f );
+
+ BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.0f) == 3.5f );
+ BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.625f) == 4.75f );
+ BOOST_CHECK( geom.detectorOffsetToIndex(-0.1f) == 3 );
+
+ BOOST_CHECK( geom.indexToDetectorOffset(0) == -1.75f );
+ BOOST_CHECK( geom.indexToDetectorOffset(1) == -1.25f );
+
+ int angle, detector;
+ geom.indexToAngleDetectorIndex(10, angle, detector);
+ BOOST_CHECK( angle == 1 );
+ BOOST_CHECK( detector == 2 );
+
+ float t, theta;
+ geom.getRayParams(1, 2, t, theta);
+ BOOST_CHECK( theta == 1.0f );
+ BOOST_CHECK( t == -0.75f );
+
+ // TODO: add test with large angle
+}
+
+BOOST_AUTO_TEST_CASE( testParallelProjectionGeometry2D_Offsets_odd )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f };
+ astra::CParallelProjectionGeometry2D geom(4, 7, 0.5f, angles);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.0f) == 3.0f );
+ BOOST_CHECK( geom.detectorOffsetToIndexFloat(0.625f) == 4.25f );
+}
+
+
+BOOST_AUTO_TEST_CASE( testParallelProjectionGeometry2D_Clone )
+{
+ astra::float32 angles[] = { 0.0f, 1.0f, 2.0f, 3.0f };
+ astra::CParallelProjectionGeometry2D geom(4, 8, 0.5f, angles);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ astra::CProjectionGeometry2D* geom2 = geom.clone();
+
+ BOOST_REQUIRE( geom2->isInitialized() );
+
+ BOOST_CHECK( geom.isEqual(geom2) );
+ BOOST_CHECK( geom2->getProjectionAngleCount() == 4 );
+ BOOST_CHECK( geom2->getDetectorCount() == 8 );
+ BOOST_CHECK( geom2->getDetectorWidth() == 0.5f );
+ BOOST_CHECK( geom2->getProjectionAngle(0) == 0.0f );
+ BOOST_CHECK( geom2->getProjectionAngle(1) == 1.0f );
+ BOOST_CHECK( geom2->getProjectionAngle(2) == 2.0f );
+ BOOST_CHECK( geom2->getProjectionAngle(3) == 3.0f );
+ BOOST_CHECK( geom2->getProjectionAngles()[0] == 0.0f );
+ BOOST_CHECK( geom2->getProjectionAngles()[3] == 3.0f );
+ delete geom2;
+}
+
diff --git a/tests/test_VolumeGeometry2D.cpp b/tests/test_VolumeGeometry2D.cpp
new file mode 100644
index 0000000..4ae88d3
--- /dev/null
+++ b/tests/test_VolumeGeometry2D.cpp
@@ -0,0 +1,150 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+
+#include "astra/VolumeGeometry2D.h"
+
+BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Constructor1 )
+{
+ astra::CVolumeGeometry2D geom(16, 32);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK( geom.getGridColCount() == 16 );
+ BOOST_CHECK( geom.getGridRowCount() == 32 );
+ BOOST_CHECK( geom.getGridTotCount() == 512 );
+ BOOST_CHECK( geom.getWindowLengthX() == 16.0f );
+ BOOST_CHECK( geom.getWindowLengthY() == 32.0f );
+ BOOST_CHECK( geom.getWindowArea() == 512.0f );
+ BOOST_CHECK( geom.getPixelLengthX() == 1.0f );
+ BOOST_CHECK( geom.getPixelLengthY() == 1.0f );
+ BOOST_CHECK( geom.getPixelArea() == 1.0f );
+ BOOST_CHECK( geom.getWindowMinX() == -8.0f );
+ BOOST_CHECK( geom.getWindowMaxX() == 8.0f );
+ BOOST_CHECK( geom.getWindowMinY() == -16.0f );
+ BOOST_CHECK( geom.getWindowMaxY() == 16.0f );
+}
+
+BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Constructor1odd )
+{
+ astra::CVolumeGeometry2D geom(5, 7);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK( geom.getGridColCount() == 5 );
+ BOOST_CHECK( geom.getGridRowCount() == 7 );
+ BOOST_CHECK( geom.getGridTotCount() == 35 );
+ BOOST_CHECK( geom.getWindowLengthX() == 5.0f );
+ BOOST_CHECK( geom.getWindowLengthY() == 7.0f );
+ BOOST_CHECK( geom.getWindowArea() == 35.0f );
+ BOOST_CHECK( geom.getPixelLengthX() == 1.0f );
+ BOOST_CHECK( geom.getPixelLengthY() == 1.0f );
+ BOOST_CHECK( geom.getPixelArea() == 1.0f );
+ BOOST_CHECK( geom.getWindowMinX() == -2.5f );
+ BOOST_CHECK( geom.getWindowMaxX() == 2.5f );
+ BOOST_CHECK( geom.getWindowMinY() == -3.5f );
+ BOOST_CHECK( geom.getWindowMaxY() == 3.5f );
+}
+
+BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Constructor2 )
+{
+ astra::CVolumeGeometry2D geom(16, 32, -1.0f, -2.0f, 3.0f, 4.0f);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK( geom.getGridColCount() == 16 );
+ BOOST_CHECK( geom.getGridRowCount() == 32 );
+ BOOST_CHECK( geom.getGridTotCount() == 512 );
+ BOOST_CHECK( geom.getWindowLengthX() == 4.0f );
+ BOOST_CHECK( geom.getWindowLengthY() == 6.0f );
+ BOOST_CHECK( geom.getWindowArea() == 24.0f );
+ BOOST_CHECK( geom.getPixelLengthX() == 0.25f );
+ BOOST_CHECK( geom.getPixelLengthY() == 0.1875f );
+ BOOST_CHECK( geom.getPixelArea() == 0.046875f );
+ BOOST_CHECK( geom.getWindowMinX() == -1.0f );
+ BOOST_CHECK( geom.getWindowMaxX() == 3.0f );
+ BOOST_CHECK( geom.getWindowMinY() == -2.0f );
+ BOOST_CHECK( geom.getWindowMaxY() == 4.0f );
+}
+
+BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Clone )
+{
+ astra::CVolumeGeometry2D geom(16, 32, -1.0f, -2.0f, 3.0f, 4.0f);
+
+ astra::CVolumeGeometry2D* geom2 = geom.clone();
+
+ BOOST_REQUIRE( geom2->isInitialized() );
+
+ BOOST_CHECK( geom.isEqual(geom2) );
+ BOOST_CHECK( geom2->getGridColCount() == 16 );
+ BOOST_CHECK( geom2->getGridRowCount() == 32 );
+ BOOST_CHECK( geom2->getGridTotCount() == 512 );
+ BOOST_CHECK( geom2->getWindowLengthX() == 4.0f );
+ BOOST_CHECK( geom2->getWindowLengthY() == 6.0f );
+ BOOST_CHECK( geom2->getWindowArea() == 24.0f );
+ BOOST_CHECK( geom2->getPixelLengthX() == 0.25f );
+ BOOST_CHECK( geom2->getPixelLengthY() == 0.1875f );
+ BOOST_CHECK( geom2->getPixelArea() == 0.046875f );
+ BOOST_CHECK( geom2->getWindowMinX() == -1.0f );
+ BOOST_CHECK( geom2->getWindowMaxX() == 3.0f );
+ BOOST_CHECK( geom2->getWindowMinY() == -2.0f );
+ BOOST_CHECK( geom2->getWindowMaxY() == 4.0f );
+
+ delete geom2;
+}
+
+BOOST_AUTO_TEST_CASE( testVolumeGeometry2D_Offsets )
+{
+ astra::CVolumeGeometry2D geom(16, 32, -1.0f, -2.0f, 3.0f, 4.0f);
+
+ BOOST_REQUIRE( geom.isInitialized() );
+
+ BOOST_CHECK( geom.pixelRowColToIndex(1,2) == 18 );
+
+ int r,c;
+ geom.pixelIndexToRowCol(66, r, c);
+ BOOST_CHECK( r == 4 );
+ BOOST_CHECK( c == 2 );
+
+ BOOST_CHECK( geom.pixelColToCenterX(2) == -0.375f );
+ BOOST_CHECK( geom.pixelColToMinX(2) == -0.5f );
+ BOOST_CHECK( geom.pixelColToMaxX(2) == -0.25f );
+
+ BOOST_CHECK( geom.pixelRowToCenterY(29) == -1.53125f );
+ BOOST_CHECK( geom.pixelRowToMinY(29) == -1.625f );
+ BOOST_CHECK( geom.pixelRowToMaxY(29) == -1.4375f );
+
+ BOOST_CHECK( geom.coordXToCol(0.1f) == 4 );
+ BOOST_CHECK( geom.coordYToRow(0.1f) == 20 );
+}
diff --git a/tests/test_XMLDocument.cpp b/tests/test_XMLDocument.cpp
new file mode 100644
index 0000000..adabdd6
--- /dev/null
+++ b/tests/test_XMLDocument.cpp
@@ -0,0 +1,158 @@
+/*
+-----------------------------------------------------------------------
+Copyright 2012 iMinds-Vision Lab, University of Antwerp
+
+Contact: astra@ua.ac.be
+Website: http://astra.ua.ac.be
+
+
+This file is part of the
+All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox").
+
+The ASTRA Toolbox 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.
+
+The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+
+-----------------------------------------------------------------------
+$Id$
+*/
+
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+#include <boost/test/auto_unit_test.hpp>
+
+#include "astra/XMLDocument.h"
+
+BOOST_AUTO_TEST_CASE( testXMLDocument_Constructor1 )
+{
+ astra::XMLDocument *doc = astra::XMLDocument::createDocument("test");
+ BOOST_REQUIRE(doc);
+
+ astra::XMLNode *root = doc->getRootNode();
+
+ BOOST_REQUIRE(root);
+
+ BOOST_CHECK(root->getName() == "test");
+ BOOST_CHECK(root->getContent().empty());
+}
+
+BOOST_AUTO_TEST_CASE( testXMLDocument_FileIO )
+{
+ astra::XMLDocument *doc = astra::XMLDocument::createDocument("test");
+
+ doc->saveToFile("test.xml");
+
+ astra::XMLDocument *doc2 = astra::XMLDocument::readFromFile("test.xml");
+ astra::XMLNode *root = doc2->getRootNode();
+
+ BOOST_REQUIRE(root);
+
+ BOOST_CHECK(root->getName() == "test");
+ BOOST_CHECK(root->getContent().empty());
+
+}
+
+BOOST_AUTO_TEST_CASE( testXMLDocument_CreateNodes )
+{
+ astra::XMLDocument *doc = astra::XMLDocument::createDocument("test");
+ BOOST_REQUIRE(doc);
+
+ astra::XMLNode *root = doc->getRootNode();
+ BOOST_REQUIRE(root);
+
+ astra::XMLNode *node = root->addChildNode("child");
+ BOOST_REQUIRE(node);
+
+ node->addAttribute("attr", "val");
+
+ doc->saveToFile("test2.xml");
+
+ delete node;
+ delete root;
+ delete doc;
+
+ doc = astra::XMLDocument::readFromFile("test2.xml");
+ BOOST_REQUIRE(doc);
+ root = doc->getRootNode();
+ BOOST_REQUIRE(node);
+ node = root->getSingleNode("child");
+ BOOST_REQUIRE(node);
+
+ BOOST_CHECK(node->hasAttribute("attr"));
+ BOOST_CHECK(node->getAttribute("attr") == "val");
+
+ delete node;
+ delete root;
+ delete doc;
+}
+
+BOOST_AUTO_TEST_CASE( testXMLDocument_Options )
+{
+ astra::XMLDocument *doc = astra::XMLDocument::createDocument("test");
+ BOOST_REQUIRE(doc);
+
+ astra::XMLNode *root = doc->getRootNode();
+ BOOST_REQUIRE(root);
+
+ BOOST_CHECK(!root->hasOption("opt"));
+
+ root->addOption("opt", "val");
+
+ BOOST_CHECK(root->hasOption("opt"));
+
+ BOOST_CHECK(root->getOption("opt") == "val");
+
+}
+
+BOOST_AUTO_TEST_CASE( testXMLDocument_List )
+{
+ astra::XMLDocument *doc = astra::XMLDocument::createDocument("test");
+ BOOST_REQUIRE(doc);
+
+ astra::XMLNode *root = doc->getRootNode();
+ BOOST_REQUIRE(root);
+
+ astra::XMLNode *node = root->addChildNode("child");
+ BOOST_REQUIRE(node);
+
+
+ float fl[] = { 1.0, 3.5, 2.0, 4.75 };
+
+ node->setContent(fl, sizeof(fl)/sizeof(fl[0]));
+
+ doc->saveToFile("test3.xml");
+
+ delete node;
+ delete root;
+ delete doc;
+
+ doc = astra::XMLDocument::readFromFile("test3.xml");
+ BOOST_REQUIRE(doc);
+ root = doc->getRootNode();
+ BOOST_REQUIRE(root);
+ node = root->getSingleNode("child");
+ BOOST_REQUIRE(node);
+
+ std::vector<astra::float32> f = node->getContentNumericalArray();
+
+ BOOST_CHECK(f[0] == fl[0]);
+ BOOST_CHECK(f[1] == fl[1]);
+ BOOST_CHECK(f[2] == fl[2]);
+ BOOST_CHECK(f[3] == fl[3]);
+
+ delete node;
+ delete root;
+ delete doc;
+
+}
+
diff --git a/tests/tests_vc08.vcproj b/tests/tests_vc08.vcproj
new file mode 100644
index 0000000..90c5d55
--- /dev/null
+++ b/tests/tests_vc08.vcproj
@@ -0,0 +1,699 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="tests"
+ ProjectGUID="{32C1BDD3-38C2-4C80-A03C-2129782F59B5}"
+ RootNamespace="tests"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\lib\include\;..\include\"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32D.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\lib\win32\;..\bin\win32"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\lib\include\;..\include\"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64D.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\lib\x64\;..\bin\x64"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\lib\include\;..\include\"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra32.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\lib\win32\;..\bin\win32"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\lib\include\;..\include\"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="Astra64.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\lib\x64\;..\bin\x64"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\lib\include\;..\include\"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32D.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\lib\win32\;..\bin\win32"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CUDA|x64"
+ OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\lib\include\;..\include\"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64D.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\lib\x64\;..\bin\x64"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|Win32"
+ OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\lib\include\;..\include\"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda32.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\lib\win32\;..\bin\win32"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CUDA|x64"
+ OutputDirectory="$(SolutionDir)\tests\$(PlatformName)\$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)\obj\"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\lib\include\;..\include\"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="AstraCuda64.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="..\lib\x64\;..\bin\x64"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Test Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\test_FanFlatProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\test_Float32Data2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\test_Float32ProjectionData2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\test_Float32VolumeData2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\test_Fourier.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\test_ParallelBeamLinearKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\test_ParallelBeamLineKernelProjector2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\test_ParallelProjectionGeometry2D.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\test_VolumeGeometry2D.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Main"
+ >
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>