From f1402849e5be2c2d9ce26a0d7f4c74b5748b8a74 Mon Sep 17 00:00:00 2001 From: dmayerich Date: Sat, 24 Aug 2013 15:03:22 -0500 Subject: [PATCH] renewed commit --- CHECK_OPENGL_ERROR.h | 15 +++++++++++++++ PerformanceDataTemplate.h | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cudaHandleError.h | 41 +++++++++++++++++++++++++++++++++++++++++ cuda_callable.h | 10 ++++++++++ objJedi.cpp | 1531 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ objJedi.h | 1856 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rect.h | 0 rts/cuda_callable.h | 10 ++++++++++ rts/cuda_handle_error.h | 23 +++++++++++++++++++++++ rts/cuda_timer.h | 21 +++++++++++++++++++++ rts/legendre.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ rts/material.h | 530 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts/point.h | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts/rect.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts/rtcomplex.h | 434 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts/sbessel.h | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts/vector.h | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsCamera.h | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsCameraController.cpp | 407 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsCameraController.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsConstants.h | 15 +++++++++++++++ rtsCubeSampler.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsCubeSampler.h | 32 ++++++++++++++++++++++++++++++++ rtsDTGrid1D.h | 624 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsDTGrid1D_v1.h | 594 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsDTGrid2D.h | 1072 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsDTGrid2D_v1.h | 740 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsDTGrid3D.h | 1098 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsFilamentNetwork.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsFilamentNetwork.h | 35 +++++++++++++++++++++++++++++++++++ rtsFilename.h | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsFunction3D.h | 913 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsGUIConsole.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsGraph.h | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsImage.h | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsImplicit3D.h | 2091 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsInputState.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsLinearAlgebra.h | 15 +++++++++++++++ rtsMath.cpp | 757 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsMath.h | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsMatrix4x4.h | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsNetwork.h | 1902 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsOctree.h | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsParser.h | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsPoint3d.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsProgressBar.cpp | 28 ++++++++++++++++++++++++++++ rtsQuaternion.h | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsSkeleton.h | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsSkeletonizer.h | 680 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsSourceCode.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsUtilities.cpp | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsUtilities.h | 20 ++++++++++++++++++++ rtsVector3d.h | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsVolume.cpp | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rtsVolume.h | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_cudaBrewer.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_cudaCufftShift.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glBrewer.glsl | 0 rts_glBrewer.h | 17 +++++++++++++++++ rts_glFilamentNetwork.cpp | 17 +++++++++++++++++ rts_glFilamentNetwork.h | 26 ++++++++++++++++++++++++++ rts_glIntegrateTexture.cpp | 0 rts_glIntegrateTexture.h | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glOBJ.cpp | 465 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glOBJ.h | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glRenderToTexture.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glRenderToTexture.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ rts_glRenderableDTGrid.cpp | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glRenderableDTGrid.h | 38 ++++++++++++++++++++++++++++++++++++++ rts_glShaderObject.h | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glShaderProgram.h | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glShaderUniform.h | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glTextureMap.cpp | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glTextureMap.h | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glTrueEyes.h | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glUtilities.h | 12 ++++++++++++ rts_glVolumeViewer.cpp | 446 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glVolumeViewer.h | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_glutRenderWindow.h | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_itkFunctions.h | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_itkImage.h | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_itkVolume.h | 781 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_old_Camera.cpp | 382 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_old_Camera.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_vtkFunctions.h | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_winFileDialog.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rts_winFileDialog.h | 18 ++++++++++++++++++ rts_winFiles.h | 41 +++++++++++++++++++++++++++++++++++++++++ rtsf_LoadTexture.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ temp_rtsBoundingVolumes.h | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ temp_rtsSignedDistance.h | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ temp_rts_glFilamentNetwork.cpp | 403 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ temp_rts_glFilamentNetwork.h | 37 +++++++++++++++++++++++++++++++++++++ validate/CMakeLists.txt | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ validate/FindRTS.cmake | 14 ++++++++++++++ validate/compare.h | 27 +++++++++++++++++++++++++++ validate/main.cpp | 19 +++++++++++++++++++ validate/validate-bessel.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ validate/validate-complex.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ validate/validate-complex.cu | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ validate/validate-legendre.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ 101 files changed, 25830 insertions(+), 0 deletions(-) create mode 100755 CHECK_OPENGL_ERROR.h create mode 100755 PerformanceDataTemplate.h create mode 100755 cudaHandleError.h create mode 100644 cuda_callable.h create mode 100755 objJedi.cpp create mode 100755 objJedi.h create mode 100644 rect.h create mode 100644 rts/cuda_callable.h create mode 100644 rts/cuda_handle_error.h create mode 100644 rts/cuda_timer.h create mode 100644 rts/legendre.h create mode 100644 rts/material.h create mode 100644 rts/point.h create mode 100644 rts/rect.h create mode 100644 rts/rtcomplex.h create mode 100644 rts/sbessel.h create mode 100644 rts/vector.h create mode 100755 rtsCamera.h create mode 100755 rtsCameraController.cpp create mode 100755 rtsCameraController.h create mode 100755 rtsConstants.h create mode 100755 rtsCubeSampler.cpp create mode 100755 rtsCubeSampler.h create mode 100755 rtsDTGrid1D.h create mode 100755 rtsDTGrid1D_v1.h create mode 100755 rtsDTGrid2D.h create mode 100755 rtsDTGrid2D_v1.h create mode 100755 rtsDTGrid3D.h create mode 100755 rtsFilamentNetwork.cpp create mode 100755 rtsFilamentNetwork.h create mode 100755 rtsFilename.h create mode 100755 rtsFunction3D.h create mode 100755 rtsGUIConsole.h create mode 100755 rtsGraph.h create mode 100755 rtsImage.h create mode 100755 rtsImplicit3D.h create mode 100755 rtsInputState.h create mode 100755 rtsLinearAlgebra.h create mode 100755 rtsMath.cpp create mode 100755 rtsMath.h create mode 100755 rtsMatrix4x4.h create mode 100755 rtsNetwork.h create mode 100755 rtsOctree.h create mode 100755 rtsParser.h create mode 100755 rtsPoint3d.h create mode 100755 rtsProgressBar.cpp create mode 100755 rtsQuaternion.h create mode 100755 rtsSkeleton.h create mode 100755 rtsSkeletonizer.h create mode 100755 rtsSourceCode.h create mode 100755 rtsUtilities.cpp create mode 100755 rtsUtilities.h create mode 100755 rtsVector3d.h create mode 100755 rtsVolume.cpp create mode 100755 rtsVolume.h create mode 100755 rts_cudaBrewer.h create mode 100755 rts_cudaCufftShift.h create mode 100755 rts_glBrewer.glsl create mode 100755 rts_glBrewer.h create mode 100755 rts_glFilamentNetwork.cpp create mode 100755 rts_glFilamentNetwork.h create mode 100755 rts_glIntegrateTexture.cpp create mode 100755 rts_glIntegrateTexture.h create mode 100755 rts_glOBJ.cpp create mode 100755 rts_glOBJ.h create mode 100755 rts_glRenderToTexture.cpp create mode 100755 rts_glRenderToTexture.h create mode 100755 rts_glRenderableDTGrid.cpp create mode 100755 rts_glRenderableDTGrid.h create mode 100755 rts_glShaderObject.h create mode 100755 rts_glShaderProgram.h create mode 100755 rts_glShaderUniform.h create mode 100755 rts_glTextureMap.cpp create mode 100755 rts_glTextureMap.h create mode 100755 rts_glTrueEyes.h create mode 100755 rts_glUtilities.h create mode 100755 rts_glVolumeViewer.cpp create mode 100755 rts_glVolumeViewer.h create mode 100755 rts_glutRenderWindow.h create mode 100755 rts_itkFunctions.h create mode 100755 rts_itkImage.h create mode 100755 rts_itkVolume.h create mode 100755 rts_old_Camera.cpp create mode 100755 rts_old_Camera.h create mode 100755 rts_vtkFunctions.h create mode 100755 rts_winFileDialog.cpp create mode 100755 rts_winFileDialog.h create mode 100755 rts_winFiles.h create mode 100755 rtsf_LoadTexture.h create mode 100755 temp_rtsBoundingVolumes.h create mode 100755 temp_rtsSignedDistance.h create mode 100755 temp_rts_glFilamentNetwork.cpp create mode 100755 temp_rts_glFilamentNetwork.h create mode 100755 validate/CMakeLists.txt create mode 100755 validate/FindRTS.cmake create mode 100644 validate/compare.h create mode 100644 validate/main.cpp create mode 100644 validate/validate-bessel.cpp create mode 100644 validate/validate-complex.cpp create mode 100644 validate/validate-complex.cu create mode 100644 validate/validate-legendre.cpp diff --git a/CHECK_OPENGL_ERROR.h b/CHECK_OPENGL_ERROR.h new file mode 100755 index 0000000..d9324ef --- /dev/null +++ b/CHECK_OPENGL_ERROR.h @@ -0,0 +1,15 @@ +#ifndef RTS_OPENGL_ERROR +#define RTS_OPENGL_ERROR + +#include +#include +#include + +#define CHECK_OPENGL_ERROR \ +{ GLenum error; \ + while ( (error = glGetError()) != GL_NO_ERROR) { \ + printf( "OpenGL ERROR: %s\nCHECK POINT: %s (line %d)\n", gluErrorString(error), __FILE__, __LINE__ ); \ + } \ +} + +#endif \ No newline at end of file diff --git a/PerformanceDataTemplate.h b/PerformanceDataTemplate.h new file mode 100755 index 0000000..9b5684e --- /dev/null +++ b/PerformanceDataTemplate.h @@ -0,0 +1,138 @@ +// add the following to a cpp file: +// PerformanceData PD; + + +#pragma once +#include +using namespace std; + +enum PerformanceDataType +{ + PD_DISPLAY=0, + PD_SPS, + PD_UNUSED0, + + //my stuff + SIMULATE_SPECTRUM, + SIMULATE_GPU, + KRAMERS_KRONIG, + + + + //end my stuff + PERFORMANCE_DATA_TYPE_COUNT +}; + +static char PDTypeNames[][255] = { + "Display ", + "Simulation Total ", + " ----------------- ", + //my stuff + "Simulate Spectrum ", + " GPU Portion ", + "Kramers-Kronig ", + + //end my stuff + +}; +#ifdef WIN32 +#include +#include +#include + +#include +#include + +//------------------------------------------------------------------------------- + +class PerformanceData +{ +public: + PerformanceData() { ClearAll(); QueryPerformanceFrequency(&cps); } + ~PerformanceData(){} + + void ClearAll() + { + for ( int i=0; i maxTime[type] ) maxTime[type] = t; + totalTime[type] -= times[type][ pos[type] ]; + times[type][ pos[type] ] = t; + totalTime[type] += t; + pos[type]++; + if ( pos[type] == 0 ) dataReady[type] = true; + } + + void PrintResult( ostream &os,int i=PERFORMANCE_DATA_TYPE_COUNT) + { + os.setf(ios::fixed); + if ((i=0)){ + double a = GetAvrgTime(i); + if ( a ) + os<< PDTypeNames[i]<<" : avrg="< +#include "cuda_runtime.h" +#include "device_launch_parameters.h" + +#ifndef CUDA_HANDLE_ERROR_H +#define CUDA_HANDLE_ERROR_H + +//handle error macro +static void HandleError( cudaError_t err, const char *file, int line ) { + if (err != cudaSuccess) { + FILE* outfile = fopen("cudaErrorLog.txt", "w"); + fprintf(outfile, "%s in %s at line %d\n", cudaGetErrorString( err ), file, line ); + fclose(outfile); + exit( EXIT_FAILURE ); + printf("%s in %s at line %d\n", cudaGetErrorString( err ), file, line ); + } +} +#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ )) + +static cudaEvent_t tStartEvent; +static cudaEvent_t tStopEvent; +static void gpuStartTimer() +{ + //set up timing events + cudaEventCreate(&tStartEvent); + cudaEventCreate(&tStopEvent); + cudaEventRecord(tStartEvent, 0); +} + +static float gpuStopTimer() +{ + cudaEventRecord(tStopEvent, 0); + cudaEventSynchronize(tStopEvent); + float elapsedTime; + cudaEventElapsedTime(&elapsedTime, tStartEvent, tStopEvent); + cudaEventDestroy(tStartEvent); + cudaEventDestroy(tStopEvent); + return elapsedTime; +} + +#endif diff --git a/cuda_callable.h b/cuda_callable.h new file mode 100644 index 0000000..eefc437 --- /dev/null +++ b/cuda_callable.h @@ -0,0 +1,10 @@ +#ifndef CUDA_CALLABLE + +//define the CUDA_CALLABLE macro (will prefix all members) +#ifdef __CUDACC__ +#define CUDA_CALLABLE __host__ __device__ +#else +#define CUDA_CALLABLE +#endif + +#endif diff --git a/objJedi.cpp b/objJedi.cpp new file mode 100755 index 0000000..8b87934 --- /dev/null +++ b/objJedi.cpp @@ -0,0 +1,1531 @@ +/*BUG NOTES +The standard function calls for inserting vertices don't work anymore. I've fixed points +but everything beyond that has to be updated. +*/ + +#include "objJedi.h" +#include "rtsvector3D.h" +#include "rtspoint3D.h" +#include +//variable for use in global functions +rtsOBJ g_OBJ; + +/********UTILITY METHODS*******************************/ +void rtsOBJ::Scale(float scale_x, float scale_y, float scale_z) +{ + vector::iterator i; + for(i = v_list.begin(); i!= v_list.end(); i++) + { + (*i).x *= scale_x; + (*i).y *= scale_y; + (*i).z *= scale_z; + } +} + +void rtsOBJ::Translate(float trans_x, float trans_y, float trans_z) +{ + vector::iterator i; + for(i = v_list.begin(); i!= v_list.end(); i++) + { + (*i).x += trans_x; + (*i).y += trans_y; + (*i).z += trans_z; + } + +} + +float rtsOBJ::GetDistance(float x, float y, float z) +{ + //gets the distance between the specified point and the nearest surface of the OBJ + //currently only works for lines + + //cout<<"Primitives: "< p0, p1, p2; + double min_dist = 255; + double dist, numerator, denominator; + int p, l; + vector3D v, w; + double c1, c2, b; + point3D Pb; + + //for each line + for(l=0; l OBJ_POLYGON) + return OBJ_ERROR; + + //otherwise, go ahead and set the mode + g_CurrentMode = mode; + //set the number of vertices to zero + g_NumVertices = 0; + + //reset the current state primitive state + current_primitive_mask = 0x0; + + return OBJ_OK; +} + +OBJint rtsOBJ::objEnd() +{ + OBJint error = OBJ_OK; + //check to make sure the number of rendered vertices is valid for the current mode + switch(g_CurrentMode) + { + case OBJ_NONE: + //can't quit if we haven't started + error = OBJ_ERROR; + break; + case OBJ_LINES: + //if less than two vertices or an odd number of vertices + if(g_NumVertices < 2 || g_NumVertices%2 != 0) + { + //if there wasn't a vertex at all + if(g_NumVertices == 0) + error = OBJ_ERROR; + //if there was at least one vertex + else + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + } + break; + case OBJ_LINE_STRIP: + //if less than two vertices + if(g_NumVertices < 2) + { + //if there wasn't a vertex at all + if(g_NumVertices == 0) + error = OBJ_ERROR; + //if there was at least one vertex + else + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + } + break; + case OBJ_LINE_LOOP: + //if less than three vertices + if(g_NumVertices < 3) + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + //connect the first and last points + else + { + error = f_TerminateLineLoop(); + } + break; + case OBJ_TRIANGLES: + //if less than three vertices or not a power of three + if(g_NumVertices < 3 || g_NumVertices%3 !=0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_TRIANGLE_STRIP: + //if less than three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_TRIANGLE_FAN: + //if less than three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_QUADS: + if(g_NumVertices < 4 || g_NumVertices%4 != 0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_QUAD_STRIP: + //has to be at least 4 vertices and an even number + if(g_NumVertices < 4 || g_NumVertices%2 != 0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_POLYGON: + //has to be at least three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + } + + //reset the attribute mask + g_AttributeMask = 0x0; + //just for closure, reset the attribute reset mask + g_AttributeResetMask = 0x0; + //stop rendering + g_CurrentMode = OBJ_NONE; + return error; +} + +OBJint rtsOBJ::f_InsertVertexf(float x, float y, float z, float w, unsigned char mask) +{ + //make sure we're rendering + if(g_CurrentMode == OBJ_NONE) + return OBJ_ERROR; + + //insert the vertex into the vertex vector + vertex_position v; + v.x = x; v.y = y; v.z=z; v.w=w; v.mask = mask; + v_list.push_back(v); + f_AdjustExtents(v); //set the bounding box + //insert texture coordinate and normal if specified for this primitive + if((current_primitive_mask & OBJ_VT) && (vt_changed)) + vt_list.push_back(current_vt); + if((current_primitive_mask & OBJ_VN) && (vn_changed)) + vn_list.push_back(current_vn); + + + //increment the number of vertices inserted + g_NumVertices++; + + //handle each case of the vertex creation individually + OBJint error = OBJ_OK; + switch(g_CurrentMode) + { + case OBJ_POINTS: + error = f_InsertPointVertex(); + break; + case OBJ_LINES: + error = f_InsertLineVertex(); + break; + case OBJ_LINE_LOOP: + error = f_InsertLineLoopVertex(); + break; + case OBJ_LINE_STRIP: + error = f_InsertLineStripVertex(); + break; + case OBJ_TRIANGLES: + error = f_InsertTriangleVertex(); + break; + case OBJ_TRIANGLE_STRIP: + error = f_InsertTriangleStripVertex(); + break; + case OBJ_TRIANGLE_FAN: + error = f_InsertTriangleFanVertex(); + break; + case OBJ_QUADS: + error = f_InsertQuadVertex(); + break; + case OBJ_QUAD_STRIP: + error = f_InsertQuadStripVertex(); + break; + case OBJ_POLYGON: + error = f_InsertPolygonVertex(); + break; + } + //set the reset mask to zero + g_AttributeResetMask = 0x0; + + //set the attribute mask to include vertex position + g_AttributeMask = g_AttributeMask | OBJ_V; + + //return the result of the insertion + return error; +} + +OBJint rtsOBJ::objVertex1f(float x) +{ + return f_InsertVertexf(x, 0.0, 0.0, 0.0, OBJ_V_X); +} + +OBJint rtsOBJ::objVertex2f(float x, float y) +{ + return f_InsertVertexf(x, y, 0.0, 0.0, OBJ_V_X | OBJ_V_Y); +} + +OBJint rtsOBJ::objVertex3f(float x, float y, float z) +{ + return f_InsertVertexf(x, y, z, 0.0, OBJ_V_X | OBJ_V_Y | OBJ_V_Z); + +} + +OBJint rtsOBJ::objVertex4f(float x, float y, float z, float w) +{ + return f_InsertVertexf(x, y, z, w, OBJ_V_X | OBJ_V_Y | OBJ_V_Z | OBJ_V_W); +} + +OBJint rtsOBJ::objNormal3f(float i, float j, float k) +{ + return f_InsertNormalf(i, j, k, OBJ_VN_I | OBJ_VN_J | OBJ_VN_K); +} +OBJint rtsOBJ::objNormal2f(float i, float j) +{ + return f_InsertNormalf(i, j, 0.0, OBJ_VN_I | OBJ_VN_J); +} + +OBJint rtsOBJ::objNormal1f(float i) +{ + return f_InsertNormalf(i, 0.0, 0.0, OBJ_VN_I); +} + +OBJint rtsOBJ::f_InsertNormalf(float i, float j, float k, unsigned char mask) +{ + /*DEPRECATED + //if the mode is not rendering faces, there is an error + if(g_CurrentMode < OBJ_TRIANGLES) + return OBJ_ERROR; + //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) + if(!(g_AttributeMask & OBJ_VN)) + { + //if a vertex has been rendered, then we can't change the attribute, so exit + if(g_NumVertices > 0) + return OBJ_ERROR; + else + //otherwise, just set the attribute flag + g_AttributeMask = g_AttributeMask | OBJ_VN; + } + + + //insert the new normal into the normal list for the file + vertex_normal new_vn; + new_vn.i = i; new_vn.j = j; new_vn.k = k; + new_vn.mask = mask; + vn_list.push_back(new_vn); + */ + current_vn.i = i; //set the current texture state to the given coordinates + current_vn.j = j; + current_vn.k = k; + current_vn.mask = mask; //set the mask as appropriate + vn_changed = true; //the texture coordinate state has changed + current_primitive_mask = current_primitive_mask | OBJ_VN; //the current primitive now uses texture coordinates (if it didn't previously) + + return OBJ_OK; +} + +OBJint rtsOBJ::objTexCoord3f(float u, float v, float w) +{ + return f_InsertTexCoordf(u, v, w, OBJ_VT_U | OBJ_VT_V | OBJ_VT_W); +} + +OBJint rtsOBJ::objTexCoord2f(float u, float v) +{ + return f_InsertTexCoordf(u, v, 0.0, OBJ_VT_U | OBJ_VT_V); +} + +OBJint rtsOBJ::objTexCoord1f(float u) +{ + return f_InsertTexCoordf(u, 0.0, 0.0, OBJ_VT_U); +} + +OBJint rtsOBJ::f_InsertTexCoordf(float u, float v, float w, unsigned char mask) +{ + /* + DEPRECATED + //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) + if(!(g_AttributeMask & OBJ_VT)) + { + //if a vertex has been rendered, then we can't change the attribute, so exit + if(g_NumVertices > 0) + return OBJ_ERROR; + else + //otherwise, just set the attribute flag + g_AttributeMask = g_AttributeMask | OBJ_VT; + } + + //insert the new texture coordinate into the list for the file + vertex_texture new_vt; + new_vt.u = u; new_vt.v = v; new_vt.w = w; + new_vt.mask = mask; + vt_list.push_back(new_vt); + */ + current_vt.u = u; //set the current texture state to the given coordinates + current_vt.v = v; + current_vt.w = w; + current_vt.mask = mask; //set the mask as appropriate + vt_changed = true; //the texture coordinate state has changed + current_primitive_mask = current_primitive_mask | OBJ_VT; //the current primitive now uses texture coordinates (if it didn't previously) + + return OBJ_OK; +} + + +void rtsOBJ::insertVertexPosition(float x, float y, float z, unsigned char mask) +{ + vertex_position v; + v.x = x; + v.y = y; + v.z = z; + v.mask = mask; + + v_list.push_back(v); +} + +void rtsOBJ::insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist) +{ + //create the new primitive + primitive line; + line.type = OBJ_LINES; + line.mask = 0; + + //set the mask based on the passed data + if(pointlist != NULL) + line.mask = line.mask | OBJ_V; + if(normallist != NULL) + line.mask = line.mask | OBJ_VN; + if(texturelist != NULL) + line.mask = line.mask | OBJ_VT; + + //insert the line + int v; + vertex new_vert; + for(v=0; v 1) + points.push_back(p_index); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertLineVertex() +{ + //if this is an odd vertex, create a new line + if(g_NumVertices%2 == 1) + { + f_CreateNewLine(); + } + + f_InsertNewLineVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertLineLoopVertex() +{ + //technically, this is the same as inserting a line strip vertex + f_InsertLineStripVertex(); + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertLineStripVertex() +{ + if(g_NumVertices == 1) + { + f_CreateNewLine(); + } + + f_InsertNewLineVertex(); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertTriangleVertex() +{ + //if this is the first vertex in a triangle, create a new triangle + if(g_NumVertices%3 == 1) + { + f_CreateNewFace(); + } + + + f_InsertNewFaceVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertTriangleStripVertex() +{ + //in the special case of the first three vertices, just create a triangle + if(g_NumVertices <4) + f_InsertTriangleVertex(); + else + { + + //create a new face for the new triangle + f_CreateNewFace(); + + //insert the last two vertices from the previous triangle + f_InsertPreviousFaceVertex(1); + f_InsertPreviousFaceVertex(2); + //insert the new vertex + f_InsertNewFaceVertex(); + } + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertTriangleFanVertex() +{ + //in the special case of the first three vertices, just create a triangle + if(g_NumVertices <4) + f_InsertTriangleVertex(); + else + { + //create a new face for the new triangle + f_CreateNewFace(); + //add the previous vertices to the face + f_InsertFirstFaceVertex(0); + f_InsertPreviousFaceVertex(2); + //insert the current vertex + f_InsertNewFaceVertex(); + } + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertQuadVertex() +{ + //if this is the first vertex in a quad, create a new quad + if(g_NumVertices%4 == 1) + { + f_CreateNewFace(); + } + + f_InsertNewFaceVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertQuadStripVertex() +{ + //in the case of one of the first four vertices, just create a quad + if(g_NumVertices < 5) + f_InsertQuadVertex(); + //if the vertex is odd (it will be the third vertex of a quad) + else if(g_NumVertices%2 == 1) + { + //create a new face for the new quad + f_CreateNewFace(); + //add the previous two vertices + f_InsertPreviousFaceVertex(2); + f_InsertPreviousFaceVertex(3); + //add the current vertex + f_InsertNewFaceVertex(); + } + else + { + //if this is the last vertex of the quad, just add it + f_InsertNewFaceVertex(); + + } + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertPolygonVertex() +{ + //if this is the first vertex, create the quad + if(g_NumVertices == 1) + { + f_CreateNewFace(); + } + f_InsertNewFaceVertex(); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertPreviousFaceVertex(unsigned int v_index) +{ + /*Finds the vertex used in the previous face with the given index and + inserts it into the current face. This limits the redundancy in the file + for re-used vertices (in strips and fans). This also transfers texture + and normal information.*/ + + //find the index of the previous face + unsigned int prev_f_index = primitives.size() - 2; + //find the index of the current face + unsigned int f_index = prev_f_index +1; + //add the vertex information from the previous face to this face + primitives[f_index].p.push_back(primitives[prev_f_index].p[v_index]); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertFirstFaceVertex(unsigned int v_index) +{ + /*Finds the vertex used in the first face (since the last objBegin()) + with the given index and inserts it at the end of the current face. + This includes texture and normal information.*/ + + //The result depends on the type of face being rendered + //So far, this function only applies to triangle fans + if(g_CurrentMode != OBJ_TRIANGLE_FAN) + return OBJ_ERROR; + + //calculate the number of faces that have been rendered + unsigned int num_faces = g_NumVertices - 2; + //find the index of the first face + unsigned int first_f_index = primitives.size() - num_faces; + //find the index of the current face + unsigned int f_index = primitives.size() - 1; + //transfer the vertex information from the first face to this one + primitives[f_index].p.push_back(primitives[first_f_index].p[v_index]); + + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertNewFaceVertex() +{ + /*This inserts information about the current vertex into the current face*/ + //find the new vertex index + vertex p; + p.v = v_list.size() -1; + p.vt = vt_list.size() - 1; + p.vn = vn_list.size() -1; + //find the face index + unsigned int f_index = primitives.size() -1; + //INSERT VERTEX AND ATTRIBUTE DATA + //just add the vertex to the face + primitives[f_index].p.push_back(p); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertNewLineVertex() +{ + /*This inserts information about the current vertex into the current line*/ + //find the new vertex index + vertex p; + p.v = v_list.size() -1; + p.vt = vt_list.size() - 1; + //find the line index + unsigned int l_index = primitives.size() -1; + + //ADD VERTEX AND ATTRIBUTE INFORMATION + //add the vertex to the line + primitives[l_index].p.push_back(p); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_CreateNewFace() +{ + primitive new_f; + new_f.type = OBJ_FACE; + new_f.mask = g_AttributeMask; + faces.push_back(primitives.size()); + primitives.push_back(new_f); + + + return OBJ_OK; +} + +OBJint rtsOBJ::f_CreateNewLine() +{ + primitive new_l; + new_l.type = OBJ_LINES; + new_l.mask = g_AttributeMask; + lines.push_back(primitives.size()); + primitives.push_back(new_l); + + return OBJ_OK; +} + + +OBJint rtsOBJ::f_TerminateLineLoop() +{ + /*This function just terminates the line loop by setting the last vertex + to the first vertex.*/ + if(g_CurrentMode != OBJ_LINE_LOOP) + return OBJ_ERROR; + //find the index for the current line + unsigned int l_index = lines.size() -1; + //insert the first vertex as the last vertex + primitives[l_index].p.push_back(primitives[l_index].p[0]); + + return OBJ_OK; +} + +void rtsOBJ::f_OutputVertices() +{ + //get the number of vertices in the object + unsigned int v_num = v_list.size(); + for(unsigned int i=0; i>new_vertex.x; + new_vertex.mask = OBJ_V_X; + + if(infile.peek() == ' ') + { + infile>>new_vertex.y; + new_vertex.mask = new_vertex.mask | OBJ_V_Y; + } + if(infile.peek() == ' ') + { + infile>>new_vertex.z; + new_vertex.mask = new_vertex.mask | OBJ_V_Z; + } + if(infile.peek() == ' ') + { + infile>>new_vertex.w; + new_vertex.mask = new_vertex.mask | OBJ_V_W; + } + int c = infile.peek(); + //ignore the rest of the line + infile.ignore(1000, '\n'); + c = infile.peek(); + + //cout<<"vertex read: "<>new_normal.i; + new_normal.mask = OBJ_VN_I; + //get every other component + if(infile.peek() == ' ') + { + infile>>new_normal.j; + new_normal.mask = new_normal.mask | OBJ_VN_J; + } + if(infile.peek() == ' ') + { + infile>>new_normal.k; + new_normal.mask = new_normal.mask | OBJ_VN_K; + } + //ignore the rest of the line + infile.ignore(1000, '\n'); + //insert the normal + vn_list.push_back(new_normal); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_ReadTexCoord(ifstream &infile) +{ + vertex_texture new_texcoord; + infile>>new_texcoord.u; + new_texcoord.mask = OBJ_VT_U; + //get every other component + if(infile.peek() == ' ') + { + infile>>new_texcoord.v; + new_texcoord.mask = new_texcoord.mask | OBJ_VT_V; + } + if(infile.peek() == ' ') + { + infile>>new_texcoord.w; + new_texcoord.mask = new_texcoord.mask | OBJ_VT_W; + } + + //ignore the rest of the line + infile.ignore(1000, '\n'); + //insert the texture coordinate + vt_list.push_back(new_texcoord); + + return OBJ_OK; + +} + +OBJint rtsOBJ::f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask) +{ + //store the line vertex + infile>>new_point.v; + new_point.v--; + mask = OBJ_V; + //new_face.v.push_back(new_v - 1); + if(infile.peek() == '/') + { + infile.get(); + //if there actually is a texcoord + if(infile.peek() != '/') + { + infile>>new_point.vt; //get the index + new_point.vt--; + mask = mask | OBJ_VT; //update the mask + //new_face.vt.push_back(new_vt - 1); + } + } + //check for a normal + if(infile.peek() == '/') + { + infile.get(); + infile>>new_point.vn; //get the index + new_point.vn--; + mask = mask | OBJ_VN; //update the mask + } + + return OBJ_OK; +} + +OBJint rtsOBJ::f_ReadPrimitive(ifstream &infile, primitive_type type) +{ + //create a new point list + primitive new_primitive; + new_primitive.type = type; + //until the end of the line + while(infile.peek() != '\n') + { + //read each point + if(infile.peek() == ' ') + infile.get(); + else + { + vertex new_point; + f_ReadVertex(infile, new_point, new_primitive.mask); + new_primitive.p.push_back(new_point); + } + } + //ignore the rest of the line + infile.ignore(1000, '\n'); + + //push the id of the primitive into the new list + //:DEBUG: + if(type == OBJ_POINTS) + points.push_back(primitives.size()); + else if(type == OBJ_LINES) + lines.push_back(primitives.size()); + else if(type == OBJ_FACE) + faces.push_back(primitives.size()); + + primitives.push_back(new_primitive); //push the new primitive + + return OBJ_OK; +} + + +OBJint rtsOBJ::f_AdjustExtents(vertex_position v) +{ + if(v.x < m_bounds.min.x) + m_bounds.min.x = v.x; + if(v.y < m_bounds.min.y) + m_bounds.min.y = v.y; + if(v.z < m_bounds.min.z) + m_bounds.min.z = v.z; + + if(v.x > m_bounds.max.x) m_bounds.max.x = v.x; + if(v.y > m_bounds.max.y) m_bounds.max.y = v.y; + if(v.z > m_bounds.max.z) m_bounds.max.z = v.z; + + return OBJ_OK; +} + +OBJint rtsOBJ::f_LoadOBJ(const char* filename) +{ + f_ClearAll(); + //open the file as a stream + ifstream infile; + infile.open(filename); + if(!infile.is_open()) + return OBJ_ERROR; + + unsigned int vertices = 0; + + string token; + infile>>token; + while(!infile.eof()) + { + //if the token is some vertex property + if(token == "v") + f_ReadPosition(infile); + else if(token == "vn") + f_ReadNormal(infile); + else if(token == "vt") + f_ReadTexCoord(infile); + else if(token == "p") + f_ReadPrimitive(infile, OBJ_POINTS); + else if(token == "l") + f_ReadPrimitive(infile, OBJ_LINES); + else if(token == "f") + f_ReadPrimitive(infile, OBJ_FACE); + else + infile.ignore(9999, '\n'); + //vertices++; + + infile>>token; + } + +} + +OBJint rtsOBJ::f_LoadSWC(const char* filename) +{ + f_ClearAll(); + //open the file as a stream + ifstream infile; + infile.open(filename); + if(!infile.is_open()) + return OBJ_ERROR; + + vector swcVertices; + float token; + objBegin(OBJ_LINES); + while(!infile.eof()) + { + vertex_position v; + infile>>token; //get the id + infile>>token; //get the fiber type + infile>>v.x; //get the node position + infile>>v.y; + infile>>v.z; + infile>>token; //get the radius + infile>>token; //get the parent + + //insert the node into the swc vector + swcVertices.push_back(v); + //now draw the line from the parent to the current node + if(token != -1) + { + objVertex3f(swcVertices[token-1].x, swcVertices[token-1].y, swcVertices[token-1].z); + objVertex3f(v.x, v.y, v.z); + } + } + objEnd(); + + + return OBJ_OK; + +} +OBJint rtsOBJ::LoadFile(const char* filename) +{ + string strFilename = filename; + int length = strFilename.length(); + string extension = strFilename.substr(strFilename.length() - 3, 3); + if(!extension.compare(string("obj"))) + return f_LoadOBJ(filename); + else if(!extension.compare(string("swc"))) + return f_LoadSWC(filename); + else return f_LoadOBJ(filename); + +} + +OBJint rtsOBJ::SaveFile(const char* filename) +{ + //open the file as a stream + ofstream outfile; + outfile.open(filename); + if(!outfile.is_open()) + return OBJ_ERROR; + + //output vertex positions + vector::iterator v; + for(v=v_list.begin(); v!= v_list.end(); v++) + { + outfile<<"v"; + if((*v).mask & OBJ_V_X) + { + outfile<<' '<<(*v).x; + if((*v).mask & OBJ_V_Y) + { + outfile<<' '<<(*v).y; + if((*v).mask & OBJ_V_Z) + { + outfile<<' '<<(*v).z; + if((*v).mask & OBJ_V_W) + outfile<<' '<<(*v).w; + } + } + } + outfile<<'\n'; + } + + //output vertex texture coordinates + vector::iterator vt; + for(vt=vt_list.begin(); vt!= vt_list.end(); vt++) + { + outfile<<"vt"; + if((*vt).mask & OBJ_VT_U) + { + outfile<<' '<<(*vt).u; + if((*vt).mask & OBJ_VT_V) + { + outfile<<' '<<(*vt).v; + if((*vt).mask & OBJ_VT_W) + outfile<<' '<<(*vt).w; + } + } + outfile<<'\n'; + } + + //output vertex normal coordinates + vector::iterator vn; + for(vn=vn_list.begin(); vn!= vn_list.end(); vn++) + { + outfile<<"vn"; + if((*vn).mask & OBJ_VN_I) + { + outfile<<' '<<(*vn).i; + if((*vn).mask & OBJ_VN_J) + { + outfile<<' '<<(*vn).j; + if((*vn).mask & OBJ_VN_K) + outfile<<' '<<(*vn).k; + } + } + outfile<<'\n'; + } + + //output each primitive + vector::iterator p; + vector::iterator vert; + for(p=primitives.begin(); p!= primitives.end(); p++) + { + switch((*p).type) + { + case OBJ_POINTS: + outfile<<"p"; //output the points token + break; + case OBJ_LINES: + outfile<<"l"; //output the lines token + break; + case OBJ_FACE: + outfile<<"f"; //output the face token + break; + } + + //for each vertex in the list for the primitive + for(vert = (*p).p.begin(); vert != (*p).p.end(); vert++) + { + outfile<<' '<<(*vert).v + 1; + if((*p).mask & OBJ_VT) + outfile<<'/'<<(*vert).vt + 1; + if((*p).mask & OBJ_VN) + { + if(!((*p).mask & OBJ_VT)) + outfile<<'/'; + outfile<<'/'<<(*vert).vn + 1; + } + } + outfile<<'\n'; + + } + + + +} + +//get methods +unsigned int rtsOBJ::getNumVertices(){return v_list.size();} +unsigned int rtsOBJ::getNumLines(){return lines.size();} +unsigned int rtsOBJ::getNumFaces(){return faces.size();} +unsigned int rtsOBJ::getNumPointLists(){return points.size();} +unsigned int rtsOBJ::getNumTexCoords(){return vt_list.size();} +unsigned int rtsOBJ::getNumNormals(){return vn_list.size();} + +//these functions return the coordinate index as well as the value +unsigned int rtsOBJ::getNumFaceVertices(unsigned int face){return primitives[face].p.size();} +unsigned int rtsOBJ::getFaceVertex(unsigned int face, unsigned int vertex){return primitives[face].p[vertex].v;} +unsigned int rtsOBJ::getFaceNormal(unsigned int face, unsigned int normal){return primitives[face].p[normal].vn;} +unsigned int rtsOBJ::getFaceTexCoord(unsigned int face, unsigned int texcoord){return primitives[face].p[texcoord].vt;} +unsigned int rtsOBJ::getNumLineVertices(unsigned int line){return primitives[line].p.size();} +unsigned int rtsOBJ::getLineVertex(unsigned int line, unsigned int vertex){return primitives[line].p[vertex].v;} +unsigned int rtsOBJ::getLineTexCoord(unsigned int line, unsigned int texcoord){return primitives[line].p[texcoord].vt;} +point3D rtsOBJ::getVertex3d(unsigned int index) +{ + return point3D(v_list[index].x, v_list[index].y, v_list[index].z); +} +point3D rtsOBJ::getTexCoord3d(unsigned int index) +{ + return point3D(vt_list[index].u, vt_list[index].v, vt_list[index].w); +} +point3D rtsOBJ::getNormal3d(unsigned int index) +{ + return point3D(vn_list[index].i, vn_list[index].j, vn_list[index].k); +} +vertex_position rtsOBJ::getVertex(unsigned int index){return v_list[index];} +vertex_texture rtsOBJ::getTexCoord(unsigned int index){return vt_list[index];} +vertex_normal rtsOBJ::getNormal(unsigned int index){return vn_list[index];} + + +unsigned int rtsOBJ::getPrimitiveType(unsigned int primitive) +{ + /* + switch(primitives[i].type) + { + case OBJ_POINTS: + return OBJ_POINTS; + break; + case OBJ_LINES: + return OBJ_LINES; + break; + case OBJ_FACE: + f_RenderFace(i); + break; + }*/ + return 0; +} +/****************************************************/ +/*******Iterator Methods*****************************/ +/****************************************************/ + +rtsOBJ::iterator rtsOBJ::begin() +{ + //create an iterator that will be returned and assign it to this OBJ + iterator result; + result.obj = this; + result.end_object = false; + result.end_primitive = false; + + //if there are no primitives, return the end iterator + if(primitives.size() == 0) + return end(); + + //start at the beginning of the primitive array + result.primitive_index = 0; + + return result; +} + +rtsOBJ::iterator rtsOBJ::end() +{ + //create an end iterator to return + iterator result; + result.obj = this; + result.end_primitive = true; + result.primitive_index = result.obj->primitives.size(); + + return result; +} + +void rtsOBJ::iterator::operator++() +{ + primitive_index++; + if(primitive_index >= obj->primitives.size()) + (*this) = obj->end(); + +} + +bool rtsOBJ::iterator::operator ==(rtsOBJ::iterator operand) +{ + if(operand.primitive_index == primitive_index) + return true; + else return false; +} + +bool rtsOBJ::iterator::operator !=(rtsOBJ::iterator operand) +{ + if(operand.primitive_index != primitive_index) + return true; + else return false; +} + +unsigned int rtsOBJ::iterator::operator*() +{ + return primitive_index; +} + +void rtsOBJ::iterator::print() +{ + cout<<"This is a test"< +#include +#include +#include +using namespace std; + +//masks for valid vertex components +#define OBJ_V_X 0x1 +#define OBJ_V_Y 0x2 +#define OBJ_V_Z 0x4 +#define OBJ_V_W 0x8 + +#define OBJ_VT_U 0x1 +#define OBJ_VT_V 0x2 +#define OBJ_VT_W 0x4 + +#define OBJ_VN_I 0x1 +#define OBJ_VN_J 0x2 +#define OBJ_VN_K 0x4 + +#define OBJ_V 0x1 +#define OBJ_VT 0x2 +#define OBJ_VN 0x4 + +//primitive types +typedef unsigned char primitive_type; + +#define OBJ_END 0x0 +#define OBJ_POINTS 0x1 +#define OBJ_LINES 0x2 +#define OBJ_FACE 0x3 + + +#define OBJ_INVALID ULONG_MAX +//define the point structures +struct vertex_position{float x,y,z,w; unsigned char mask;}; +struct vertex_texture{float u,v,w; unsigned char mask;}; +struct vertex_normal{float i,j,k; unsigned char mask;}; +//the point structure contains indices to the relative 3-vectors in the lists +struct vertex +{ + unsigned int v; + unsigned int vt; + unsigned int vn; +}; + +struct primitive +{ + vector p; //indices to the point + unsigned char mask; //mask describing which features (v, vt, vn) are used + primitive_type type; //the type of primitive (points, lines, face) +}; + +//axis-aligned bounding box +struct AABB +{ + vertex_position min; + vertex_position max; +}; + +//create variable types +typedef unsigned int OBJint; + +//define the OBJ data class +class rtsOBJ +{ +private: + + /*Current state variables. These variables are committed to the OBJ object + when a vertex is added. However, we are careful to only add them once (if they don't + change with every vertex. + */ + vertex_texture current_vt; + vertex_normal current_vn; + bool vt_changed; //true if a new vt or vn was inserted since the last vertex + bool vn_changed; + unsigned char current_primitive_mask; //defines what coordinates are being used by the current primitive + //global variable storing the current render mode + OBJint g_CurrentMode; + //output file stream + ofstream g_objFile; + //obj file object + //objData g_OBJ; + //number of vertices since the last BEGIN + unsigned int g_NumVertices; + /*Attribute mask. This indicates what attributes are stored for each vertex. + Only a single mask applies to each vertex between objBegin() and objEnd(). The + attribute mask is flipped the first time an attribute is set but it is fixed after + the first vertex is passed.*/ + unsigned char g_AttributeMask; + /*Attribute reset mask. This indicates whether or not an attribute has been + reset since the last vertex was rendered. This applies to OBJ_VT and OBJ_VN*/ + unsigned char g_AttributeResetMask; + //latest texture coordinate sent + unsigned int g_LatestVT; + //latest vertex normal sent + unsigned int g_LatestVN; + + //extents of the points in the OBJ file + AABB m_bounds; + + OBJint f_InsertPointVertex(); + OBJint f_InsertLineVertex(); + OBJint f_InsertLineLoopVertex(); + OBJint f_InsertLineStripVertex(); + OBJint f_InsertTriangleVertex(); + OBJint f_InsertTriangleStripVertex(); + OBJint f_InsertTriangleFanVertex(); + OBJint f_InsertQuadVertex(); + OBJint f_InsertQuadStripVertex(); + OBJint f_InsertPolygonVertex(); + OBJint f_InsertPreviousFaceVertex(unsigned int v_index); + OBJint f_InsertFirstFaceVertex(unsigned int v_index); + OBJint f_InsertNewFaceVertex(); + OBJint f_InsertNewLineVertex(); + OBJint f_CreateNewFace(); + OBJint f_CreateNewLine(); + OBJint f_TerminateLineLoop(); + OBJint f_LoadOBJ(const char* filename); + OBJint f_LoadSWC(const char* filename); + + //insert coordinate commands + //these are used to handle coordinates of different dimensions (and are called by the associated public function) + OBJint f_InsertVertexf(float x, float y, float z, float w, unsigned char mask); + OBJint f_InsertTexCoordf(float u, float v, float w, unsigned char mask); + OBJint f_InsertNormalf(float i, float j, float k, unsigned char mask); + //output functions + void f_OutputVertices(); + void f_OutputPoints(); + void f_OutputLines(); + void f_OutputFaces(); + void f_OutputVertexNormals(); + void f_OutputTextureCoordinates(); + void f_ClearAll(); + + //methods for reading from a file + OBJint f_ReadPosition(ifstream &infile); + OBJint f_ReadNormal(ifstream &infile); + OBJint f_ReadTexCoord(ifstream &infile); + OBJint f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask); + OBJint f_ReadPrimitive(ifstream &infile, primitive_type type); + OBJint f_AdjustExtents(vertex_position v); + +public: + /*These vectors store the vertex and primitive data from the obj file. + All vertices, texture coordinates, and normals are stored in m_v, m_vt, m_vn + respectively. The vectors for each primitive store an index into m_v, m_vt, + and m_vn identifying the associated coordinate. Basically, the data is stored + in a structure very similar to the OBJ file itself. + */ + vector v_list; + vector vt_list; + vector vn_list; + vector primitives; + + vector points; + vector lines; + vector faces; + +public: + + OBJint objOpen(const char* filename); + OBJint objBegin(OBJint obj_mode); + OBJint objEnd(); + OBJint objClose(); + OBJint objNormal3f(float i, float j, float k); + OBJint objNormal2f(float i, float j); + OBJint objNormal1f(float i); + OBJint objTexCoord3f(float u, float v, float w); + OBJint objTexCoord2f(float u, float v); + OBJint objTexCoord1f(float u); + OBJint objVertex1f(float x); + OBJint objVertex2f(float x, float y); + OBJint objVertex3f(float x, float y, float z); + OBJint objVertex4f(float x, float y, float z, float w); + OBJint LoadFile(const char* filename); + OBJint SaveFile(const char* filename); + + //direct insertion methods + void insertVertexPosition(float x, float y, float z, unsigned char mask = OBJ_V_X | OBJ_V_Y | OBJ_V_Z); + void insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist); + + //get methods + unsigned int getNumVertices(); + unsigned int getNumLines(); + unsigned int getNumFaces(); + unsigned int getNumPointLists(); + unsigned int getNumTexCoords(); + unsigned int getNumNormals(); + + //these functions return the coordinate index as well as the value + unsigned int getNumFaceVertices(unsigned int face); + unsigned int getFaceVertex(unsigned int face, unsigned int vertex); + unsigned int getFaceNormal(unsigned int face, unsigned int normal); + unsigned int getFaceTexCoord(unsigned int face, unsigned int texcoord); + unsigned int getNumLineVertices(unsigned int line); + unsigned int getLineVertex(unsigned int line, unsigned int vertex); + unsigned int getLineTexCoord(unsigned int line, unsigned int texcoord); + point3D getVertex3d(unsigned int index); + point3D getTexCoord3d(unsigned int index); + point3D getNormal3d(unsigned int index); + vertex_position getVertex(unsigned int index); + vertex_texture getTexCoord(unsigned int index); + vertex_normal getNormal(unsigned int index); + AABB getBoundingBox(){return m_bounds;} + void Scale(float scale_x, float scale_y, float scale_z); + void Translate(float trans_x, float trans_y, float trans_z); + + float GetDistance(float x, float y, float z); + + //return data about primitives + unsigned int getPrimitiveType(unsigned int primitive); + + //constructors + rtsOBJ(); + void CopyOBJ(const rtsOBJ& obj); + //assignment + rtsOBJ& operator=(const rtsOBJ& obj) + { + CopyOBJ(obj); + return *this; + } + //copy + rtsOBJ(const rtsOBJ& obj) + { + CopyOBJ(obj); + //return *this; + } + + + + //Iterator stuff + class iterator + { + friend class rtsOBJ; + private: + rtsOBJ* obj; + bool end_primitive; + bool end_object; + unsigned int primitive_index; + public: + unsigned int operator*(); + void operator++(); + bool operator==(rtsOBJ::iterator operand); + bool operator!=(rtsOBJ::iterator operand); + unsigned int size(){return obj->primitives[primitive_index].p.size();}; + void print(); + }; + + iterator begin(); + iterator end(); +}; + +//define error codes +#define OBJ_OK 0x0100 +#define OBJ_ERROR 0x0101 + +//define the different modes +#define OBJ_NONE 0x0 +#define OBJ_POINTS 0x1 +#define OBJ_LINES 0x2 +#define OBJ_LINE_STRIP 0x3 +#define OBJ_LINE_LOOP 0x4 +#define OBJ_TRIANGLES 0x5 +#define OBJ_TRIANGLE_STRIP 0x6 +#define OBJ_TRIANGLE_FAN 0x7 +#define OBJ_QUADS 0x8 +#define OBJ_QUAD_STRIP 0x9 +#define OBJ_POLYGON 0x10 + + + + + + +//initialize the OBJ file +OBJint objOpen(char* filename); +//close the obj file +OBJint objClose(); + +//start rendering in a certain mode +OBJint objBegin(OBJint mode); +//stop the current rendering sequence +OBJint objEnd(void); +//render a vertex to the file +OBJint objVertex1f(float x); +OBJint objVertex2f(float x, float y); +OBJint objVertex3f(float x, float y, float z); +OBJint objVertex4f(float x, float y, float z, float w); +//set a normal vector for a vertex +OBJint objNormal3f(float i, float j, float k); +OBJint objNormal2f(float i, float j); +OBJint objNormal1f(float i); +//set a texture coordinate for a vertex +OBJint objTexCoord3f(float u, float v, float w); +OBJint objTexCoord2f(float u, float v); +OBJint objTexCoord1f(float u); + +//global variable for global functions +extern rtsOBJ g_OBJ; + +/*BUG NOTES +The standard function calls for inserting vertices don't work anymore. I've fixed points +but everything beyond that has to be updated. +*/ + +#include "objJedi.h" +#include "rtsVector3d.h" +#include "rtsPoint3d.h" +#include +//variable for use in global functions +rtsOBJ g_OBJ; + +/********UTILITY METHODS*******************************/ +void rtsOBJ::Scale(float scale_x, float scale_y, float scale_z) +{ + vector::iterator i; + for(i = v_list.begin(); i!= v_list.end(); i++) + { + (*i).x *= scale_x; + (*i).y *= scale_y; + (*i).z *= scale_z; + } +} + +void rtsOBJ::Translate(float trans_x, float trans_y, float trans_z) +{ + vector::iterator i; + for(i = v_list.begin(); i!= v_list.end(); i++) + { + (*i).x += trans_x; + (*i).y += trans_y; + (*i).z += trans_z; + } + +} + +float rtsOBJ::GetDistance(float x, float y, float z) +{ + //gets the distance between the specified point and the nearest surface of the OBJ + //currently only works for lines + + //cout<<"Primitives: "< p0, p1, p2; + float min_dist = 255; + float dist; + unsigned int p, l; + vector3D v, w; + float c1, c2, b; + point3D Pb; + + //for each line + for(l=0; l OBJ_POLYGON) + return OBJ_ERROR; + + //otherwise, go ahead and set the mode + g_CurrentMode = mode; + //set the number of vertices to zero + g_NumVertices = 0; + + //reset the current state primitive state + current_primitive_mask = 0x0; + + return OBJ_OK; +} + +OBJint rtsOBJ::objEnd() +{ + OBJint error = OBJ_OK; + //check to make sure the number of rendered vertices is valid for the current mode + switch(g_CurrentMode) + { + case OBJ_NONE: + //can't quit if we haven't started + error = OBJ_ERROR; + break; + case OBJ_LINES: + //if less than two vertices or an odd number of vertices + if(g_NumVertices < 2 || g_NumVertices%2 != 0) + { + //if there wasn't a vertex at all + if(g_NumVertices == 0) + error = OBJ_ERROR; + //if there was at least one vertex + else + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + } + break; + case OBJ_LINE_STRIP: + //if less than two vertices + if(g_NumVertices < 2) + { + //if there wasn't a vertex at all + if(g_NumVertices == 0) + error = OBJ_ERROR; + //if there was at least one vertex + else + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + } + break; + case OBJ_LINE_LOOP: + //if less than three vertices + if(g_NumVertices < 3) + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + //connect the first and last points + else + { + error = f_TerminateLineLoop(); + } + break; + case OBJ_TRIANGLES: + //if less than three vertices or not a power of three + if(g_NumVertices < 3 || g_NumVertices%3 !=0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_TRIANGLE_STRIP: + //if less than three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_TRIANGLE_FAN: + //if less than three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_QUADS: + if(g_NumVertices < 4 || g_NumVertices%4 != 0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_QUAD_STRIP: + //has to be at least 4 vertices and an even number + if(g_NumVertices < 4 || g_NumVertices%2 != 0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_POLYGON: + //has to be at least three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + } + + //reset the attribute mask + g_AttributeMask = 0x0; + //just for closure, reset the attribute reset mask + g_AttributeResetMask = 0x0; + //stop rendering + g_CurrentMode = OBJ_NONE; + return error; +} + +OBJint rtsOBJ::f_InsertVertexf(float x, float y, float z, float w, unsigned char mask) +{ + //make sure we're rendering + if(g_CurrentMode == OBJ_NONE) + return OBJ_ERROR; + + //insert the vertex into the vertex vector + vertex_position v; + v.x = x; v.y = y; v.z=z; v.w=w; v.mask = mask; + v_list.push_back(v); + f_AdjustExtents(v); //set the bounding box + //insert texture coordinate and normal if specified for this primitive + if((current_primitive_mask & OBJ_VT) && (vt_changed)) + vt_list.push_back(current_vt); + if((current_primitive_mask & OBJ_VN) && (vn_changed)) + vn_list.push_back(current_vn); + + + //increment the number of vertices inserted + g_NumVertices++; + + //handle each case of the vertex creation individually + OBJint error = OBJ_OK; + switch(g_CurrentMode) + { + case OBJ_POINTS: + error = f_InsertPointVertex(); + break; + case OBJ_LINES: + error = f_InsertLineVertex(); + break; + case OBJ_LINE_LOOP: + error = f_InsertLineLoopVertex(); + break; + case OBJ_LINE_STRIP: + error = f_InsertLineStripVertex(); + break; + case OBJ_TRIANGLES: + error = f_InsertTriangleVertex(); + break; + case OBJ_TRIANGLE_STRIP: + error = f_InsertTriangleStripVertex(); + break; + case OBJ_TRIANGLE_FAN: + error = f_InsertTriangleFanVertex(); + break; + case OBJ_QUADS: + error = f_InsertQuadVertex(); + break; + case OBJ_QUAD_STRIP: + error = f_InsertQuadStripVertex(); + break; + case OBJ_POLYGON: + error = f_InsertPolygonVertex(); + break; + } + //set the reset mask to zero + g_AttributeResetMask = 0x0; + + //set the attribute mask to include vertex position + g_AttributeMask = g_AttributeMask | OBJ_V; + + //return the result of the insertion + return error; +} + +OBJint rtsOBJ::objVertex1f(float x) +{ + return f_InsertVertexf(x, 0.0, 0.0, 0.0, OBJ_V_X); +} + +OBJint rtsOBJ::objVertex2f(float x, float y) +{ + return f_InsertVertexf(x, y, 0.0, 0.0, OBJ_V_X | OBJ_V_Y); +} + +OBJint rtsOBJ::objVertex3f(float x, float y, float z) +{ + return f_InsertVertexf(x, y, z, 0.0, OBJ_V_X | OBJ_V_Y | OBJ_V_Z); + +} + +OBJint rtsOBJ::objVertex4f(float x, float y, float z, float w) +{ + return f_InsertVertexf(x, y, z, w, OBJ_V_X | OBJ_V_Y | OBJ_V_Z | OBJ_V_W); +} + +OBJint rtsOBJ::objNormal3f(float i, float j, float k) +{ + return f_InsertNormalf(i, j, k, OBJ_VN_I | OBJ_VN_J | OBJ_VN_K); +} +OBJint rtsOBJ::objNormal2f(float i, float j) +{ + return f_InsertNormalf(i, j, 0.0, OBJ_VN_I | OBJ_VN_J); +} + +OBJint rtsOBJ::objNormal1f(float i) +{ + return f_InsertNormalf(i, 0.0, 0.0, OBJ_VN_I); +} + +OBJint rtsOBJ::f_InsertNormalf(float i, float j, float k, unsigned char mask) +{ + /*DEPRECATED + //if the mode is not rendering faces, there is an error + if(g_CurrentMode < OBJ_TRIANGLES) + return OBJ_ERROR; + //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) + if(!(g_AttributeMask & OBJ_VN)) + { + //if a vertex has been rendered, then we can't change the attribute, so exit + if(g_NumVertices > 0) + return OBJ_ERROR; + else + //otherwise, just set the attribute flag + g_AttributeMask = g_AttributeMask | OBJ_VN; + } + + + //insert the new normal into the normal list for the file + vertex_normal new_vn; + new_vn.i = i; new_vn.j = j; new_vn.k = k; + new_vn.mask = mask; + vn_list.push_back(new_vn); + */ + current_vn.i = i; //set the current texture state to the given coordinates + current_vn.j = j; + current_vn.k = k; + current_vn.mask = mask; //set the mask as appropriate + vn_changed = true; //the texture coordinate state has changed + current_primitive_mask = current_primitive_mask | OBJ_VN; //the current primitive now uses texture coordinates (if it didn't previously) + + return OBJ_OK; +} + +OBJint rtsOBJ::objTexCoord3f(float u, float v, float w) +{ + return f_InsertTexCoordf(u, v, w, OBJ_VT_U | OBJ_VT_V | OBJ_VT_W); +} + +OBJint rtsOBJ::objTexCoord2f(float u, float v) +{ + return f_InsertTexCoordf(u, v, 0.0, OBJ_VT_U | OBJ_VT_V); +} + +OBJint rtsOBJ::objTexCoord1f(float u) +{ + return f_InsertTexCoordf(u, 0.0, 0.0, OBJ_VT_U); +} + +OBJint rtsOBJ::f_InsertTexCoordf(float u, float v, float w, unsigned char mask) +{ + /* + DEPRECATED + //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) + if(!(g_AttributeMask & OBJ_VT)) + { + //if a vertex has been rendered, then we can't change the attribute, so exit + if(g_NumVertices > 0) + return OBJ_ERROR; + else + //otherwise, just set the attribute flag + g_AttributeMask = g_AttributeMask | OBJ_VT; + } + + //insert the new texture coordinate into the list for the file + vertex_texture new_vt; + new_vt.u = u; new_vt.v = v; new_vt.w = w; + new_vt.mask = mask; + vt_list.push_back(new_vt); + */ + current_vt.u = u; //set the current texture state to the given coordinates + current_vt.v = v; + current_vt.w = w; + current_vt.mask = mask; //set the mask as appropriate + vt_changed = true; //the texture coordinate state has changed + current_primitive_mask = current_primitive_mask | OBJ_VT; //the current primitive now uses texture coordinates (if it didn't previously) + + return OBJ_OK; +} + + +void rtsOBJ::insertVertexPosition(float x, float y, float z, unsigned char mask) +{ + vertex_position v; + v.x = x; + v.y = y; + v.z = z; + v.mask = mask; + + v_list.push_back(v); +} + +void rtsOBJ::insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist) +{ + //create the new primitive + primitive line; + line.type = OBJ_LINES; + line.mask = 0; + + //set the mask based on the passed data + if(pointlist != NULL) + line.mask = line.mask | OBJ_V; + if(normallist != NULL) + line.mask = line.mask | OBJ_VN; + if(texturelist != NULL) + line.mask = line.mask | OBJ_VT; + + //insert the line + unsigned int v; + vertex new_vert; + for(v=0; v 1) + points.push_back(p_index); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertLineVertex() +{ + //if this is an odd vertex, create a new line + if(g_NumVertices%2 == 1) + { + f_CreateNewLine(); + } + + f_InsertNewLineVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertLineLoopVertex() +{ + //technically, this is the same as inserting a line strip vertex + f_InsertLineStripVertex(); + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertLineStripVertex() +{ + if(g_NumVertices == 1) + { + f_CreateNewLine(); + } + + f_InsertNewLineVertex(); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertTriangleVertex() +{ + //if this is the first vertex in a triangle, create a new triangle + if(g_NumVertices%3 == 1) + { + f_CreateNewFace(); + } + + + f_InsertNewFaceVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertTriangleStripVertex() +{ + //in the special case of the first three vertices, just create a triangle + if(g_NumVertices < 4) + f_InsertTriangleVertex(); + else + { + + //create a new face for the new triangle + f_CreateNewFace(); + + //make sure to get the ordering right: + // Even vertices provide the previous two vertices "in order": (v2, v3, v4) + // Odd vertices provide the previous two vertices in reverse order: (v1, v3, v2) + if(g_NumVertices % 2 == 1) + { + f_InsertPreviousFaceVertex(2); + f_InsertPreviousFaceVertex(1); + f_InsertNewFaceVertex(); + } + else + { + f_InsertPreviousFaceVertex(1); + f_InsertNewFaceVertex(); + f_InsertPreviousFaceVertex(2); + } + } + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertTriangleFanVertex() +{ + //in the special case of the first three vertices, just create a triangle + if(g_NumVertices <4) + f_InsertTriangleVertex(); + else + { + //create a new face for the new triangle + f_CreateNewFace(); + //add the previous vertices to the face + f_InsertFirstFaceVertex(0); + f_InsertPreviousFaceVertex(2); + //insert the current vertex + f_InsertNewFaceVertex(); + } + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertQuadVertex() +{ + //if this is the first vertex in a quad, create a new quad + if(g_NumVertices%4 == 1) + { + f_CreateNewFace(); + } + + f_InsertNewFaceVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertQuadStripVertex() +{ + //in the case of one of the first four vertices, just create a quad + if(g_NumVertices < 5) + f_InsertQuadVertex(); + //if the vertex is odd (it will be the third vertex of a quad) + else if(g_NumVertices%2 == 1) + { + //create a new face for the new quad + f_CreateNewFace(); + //add the previous two vertices + f_InsertPreviousFaceVertex(2); + f_InsertPreviousFaceVertex(3); + //add the current vertex + f_InsertNewFaceVertex(); + } + else + { + //if this is the last vertex of the quad, just add it + f_InsertNewFaceVertex(); + + } + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertPolygonVertex() +{ + //if this is the first vertex, create the quad + if(g_NumVertices == 1) + { + f_CreateNewFace(); + } + f_InsertNewFaceVertex(); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertPreviousFaceVertex(unsigned int v_index) +{ + /*Finds the vertex used in the previous face with the given index and + inserts it into the current face. This limits the redundancy in the file + for re-used vertices (in strips and fans). This also transfers texture + and normal information.*/ + + //find the index of the previous face + unsigned int prev_f_index = primitives.size() - 2; + //find the index of the current face + unsigned int f_index = prev_f_index +1; + //add the vertex information from the previous face to this face + primitives[f_index].p.push_back(primitives[prev_f_index].p[v_index]); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertFirstFaceVertex(unsigned int v_index) +{ + /*Finds the vertex used in the first face (since the last objBegin()) + with the given index and inserts it at the end of the current face. + This includes texture and normal information.*/ + + //The result depends on the type of face being rendered + //So far, this function only applies to triangle fans + if(g_CurrentMode != OBJ_TRIANGLE_FAN) + return OBJ_ERROR; + + //calculate the number of faces that have been rendered + unsigned int num_faces = g_NumVertices - 2; + //find the index of the first face + unsigned int first_f_index = primitives.size() - num_faces; + //find the index of the current face + unsigned int f_index = primitives.size() - 1; + //transfer the vertex information from the first face to this one + primitives[f_index].p.push_back(primitives[first_f_index].p[v_index]); + + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertNewFaceVertex() +{ + /*This inserts information about the current vertex into the current face*/ + //find the new vertex index + vertex p; + p.v = v_list.size() -1; + p.vt = vt_list.size() - 1; + p.vn = vn_list.size() -1; + //find the face index + unsigned int f_index = primitives.size() -1; + //INSERT VERTEX AND ATTRIBUTE DATA + //just add the vertex to the face + primitives[f_index].p.push_back(p); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertNewLineVertex() +{ + /*This inserts information about the current vertex into the current line*/ + //find the new vertex index + vertex p; + p.v = v_list.size() -1; + p.vt = vt_list.size() - 1; + //find the line index + unsigned int l_index = primitives.size() -1; + + //ADD VERTEX AND ATTRIBUTE INFORMATION + //add the vertex to the line + primitives[l_index].p.push_back(p); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_CreateNewFace() +{ + primitive new_f; + new_f.type = OBJ_FACE; + new_f.mask = g_AttributeMask; + faces.push_back(primitives.size()); + primitives.push_back(new_f); + + + return OBJ_OK; +} + +OBJint rtsOBJ::f_CreateNewLine() +{ + primitive new_l; + new_l.type = OBJ_LINES; + new_l.mask = g_AttributeMask; + lines.push_back(primitives.size()); + primitives.push_back(new_l); + + return OBJ_OK; +} + + +OBJint rtsOBJ::f_TerminateLineLoop() +{ + /*This function just terminates the line loop by setting the last vertex + to the first vertex.*/ + if(g_CurrentMode != OBJ_LINE_LOOP) + return OBJ_ERROR; + //find the index for the current line + unsigned int l_index = lines.size() -1; + //insert the first vertex as the last vertex + primitives[l_index].p.push_back(primitives[l_index].p[0]); + + return OBJ_OK; +} + +void rtsOBJ::f_OutputVertices() +{ + //get the number of vertices in the object + unsigned int v_num = v_list.size(); + for(unsigned int i=0; i>new_vertex.x; + new_vertex.mask = OBJ_V_X; + + if(infile.peek() == ' ') + { + infile>>new_vertex.y; + new_vertex.mask = new_vertex.mask | OBJ_V_Y; + } + if(infile.peek() == ' ') + { + infile>>new_vertex.z; + new_vertex.mask = new_vertex.mask | OBJ_V_Z; + } + if(infile.peek() == ' ') + { + infile>>new_vertex.w; + new_vertex.mask = new_vertex.mask | OBJ_V_W; + } + int c = infile.peek(); + //ignore the rest of the line + infile.ignore(1000, '\n'); + c = infile.peek(); + + //cout<<"vertex read: "<>new_normal.i; + new_normal.mask = OBJ_VN_I; + //get every other component + if(infile.peek() == ' ') + { + infile>>new_normal.j; + new_normal.mask = new_normal.mask | OBJ_VN_J; + } + if(infile.peek() == ' ') + { + infile>>new_normal.k; + new_normal.mask = new_normal.mask | OBJ_VN_K; + } + //ignore the rest of the line + infile.ignore(1000, '\n'); + //insert the normal + vn_list.push_back(new_normal); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_ReadTexCoord(ifstream &infile) +{ + vertex_texture new_texcoord; + infile>>new_texcoord.u; + new_texcoord.mask = OBJ_VT_U; + //get every other component + if(infile.peek() == ' ') + { + infile>>new_texcoord.v; + new_texcoord.mask = new_texcoord.mask | OBJ_VT_V; + } + if(infile.peek() == ' ') + { + infile>>new_texcoord.w; + new_texcoord.mask = new_texcoord.mask | OBJ_VT_W; + } + + //ignore the rest of the line + infile.ignore(1000, '\n'); + //insert the texture coordinate + vt_list.push_back(new_texcoord); + + return OBJ_OK; + +} + +OBJint rtsOBJ::f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask) +{ + //store the line vertex + infile>>new_point.v; + new_point.v--; + mask = OBJ_V; + //new_face.v.push_back(new_v - 1); + if(infile.peek() == '/') + { + infile.get(); + //if there actually is a texcoord + if(infile.peek() != '/') + { + infile>>new_point.vt; //get the index + new_point.vt--; + mask = mask | OBJ_VT; //update the mask + //new_face.vt.push_back(new_vt - 1); + } + } + //check for a normal + if(infile.peek() == '/') + { + infile.get(); + infile>>new_point.vn; //get the index + new_point.vn--; + mask = mask | OBJ_VN; //update the mask + } + + return OBJ_OK; +} + +OBJint rtsOBJ::f_ReadPrimitive(ifstream &infile, primitive_type type) +{ + //create a new point list + primitive new_primitive; + new_primitive.type = type; + //until the end of the line + while(infile.peek() != '\n') + { + //read each point + if(infile.peek() == ' ') + infile.get(); + else + { + vertex new_point; + f_ReadVertex(infile, new_point, new_primitive.mask); + new_primitive.p.push_back(new_point); + } + } + //ignore the rest of the line + infile.ignore(1000, '\n'); + + //push the id of the primitive into the new list + //:DEBUG: + if(type == OBJ_POINTS) + points.push_back(primitives.size()); + else if(type == OBJ_LINES) + lines.push_back(primitives.size()); + else if(type == OBJ_FACE) + faces.push_back(primitives.size()); + + primitives.push_back(new_primitive); //push the new primitive + + return OBJ_OK; +} + + +OBJint rtsOBJ::f_AdjustExtents(vertex_position v) +{ + if(v.x < m_bounds.min.x) + m_bounds.min.x = v.x; + if(v.y < m_bounds.min.y) + m_bounds.min.y = v.y; + if(v.z < m_bounds.min.z) + m_bounds.min.z = v.z; + + if(v.x > m_bounds.max.x) m_bounds.max.x = v.x; + if(v.y > m_bounds.max.y) m_bounds.max.y = v.y; + if(v.z > m_bounds.max.z) m_bounds.max.z = v.z; + + return OBJ_OK; +} + +OBJint rtsOBJ::f_LoadOBJ(const char* filename) +{ + f_ClearAll(); + //open the file as a stream + ifstream infile; + infile.open(filename); + if(!infile) + exit(1); + + unsigned int vertices = 0; + + string token; + infile>>token; + while(!infile.eof()) + { + //if the token is some vertex property + if(token == "v") + f_ReadPosition(infile); + else if(token == "vn") + f_ReadNormal(infile); + else if(token == "vt") + f_ReadTexCoord(infile); + else if(token == "p") + f_ReadPrimitive(infile, OBJ_POINTS); + else if(token == "l") + f_ReadPrimitive(infile, OBJ_LINES); + else if(token == "f") + f_ReadPrimitive(infile, OBJ_FACE); + else + infile.ignore(9999, '\n'); + //vertices++; + + infile>>token; + } + +} + +OBJint rtsOBJ::f_LoadSWC(const char* filename) +{ + f_ClearAll(); + //open the file as a stream + ifstream infile; + infile.open(filename); + if(!infile.is_open()) + return OBJ_ERROR; + + vector swcVertices; + float token; + objBegin(OBJ_LINES); + while(!infile.eof()) + { + vertex_position v; + infile>>token; //get the id + infile>>token; //get the fiber type + infile>>v.x; //get the node position + infile>>v.y; + infile>>v.z; + infile>>token; //get the radius + infile>>token; //get the parent + + //insert the node into the swc vector + swcVertices.push_back(v); + //now draw the line from the parent to the current node + if(token != -1) + { + unsigned int i = (unsigned int)token - 1; + objVertex3f(swcVertices[i].x, swcVertices[i].y, swcVertices[i].z); + objVertex3f(v.x, v.y, v.z); + } + } + objEnd(); + + + return OBJ_OK; + +} +OBJint rtsOBJ::LoadFile(const char* filename) +{ + string strFilename = filename; + int length = strFilename.length(); + string extension = strFilename.substr(strFilename.length() - 3, 3); + if(!extension.compare(string("obj"))) + return f_LoadOBJ(filename); + else if(!extension.compare(string("swc"))) + return f_LoadSWC(filename); + else return f_LoadOBJ(filename); + +} + +OBJint rtsOBJ::SaveFile(const char* filename) +{ + //open the file as a stream + ofstream outfile; + outfile.open(filename); + if(!outfile.is_open()) + return OBJ_ERROR; + + //output vertex positions + vector::iterator v; + for(v=v_list.begin(); v!= v_list.end(); v++) + { + outfile<<"v"; + if((*v).mask & OBJ_V_X) + { + outfile<<' '<<(*v).x; + if((*v).mask & OBJ_V_Y) + { + outfile<<' '<<(*v).y; + if((*v).mask & OBJ_V_Z) + { + outfile<<' '<<(*v).z; + if((*v).mask & OBJ_V_W) + outfile<<' '<<(*v).w; + } + } + } + outfile<<'\n'; + } + + //output vertex texture coordinates + vector::iterator vt; + for(vt=vt_list.begin(); vt!= vt_list.end(); vt++) + { + outfile<<"vt"; + if((*vt).mask & OBJ_VT_U) + { + outfile<<' '<<(*vt).u; + if((*vt).mask & OBJ_VT_V) + { + outfile<<' '<<(*vt).v; + if((*vt).mask & OBJ_VT_W) + outfile<<' '<<(*vt).w; + } + } + outfile<<'\n'; + } + + //output vertex normal coordinates + vector::iterator vn; + for(vn=vn_list.begin(); vn!= vn_list.end(); vn++) + { + outfile<<"vn"; + if((*vn).mask & OBJ_VN_I) + { + outfile<<' '<<(*vn).i; + if((*vn).mask & OBJ_VN_J) + { + outfile<<' '<<(*vn).j; + if((*vn).mask & OBJ_VN_K) + outfile<<' '<<(*vn).k; + } + } + outfile<<'\n'; + } + + //output each primitive + vector::iterator p; + vector::iterator vert; + for(p=primitives.begin(); p!= primitives.end(); p++) + { + switch((*p).type) + { + case OBJ_POINTS: + outfile<<"p"; //output the points token + break; + case OBJ_LINES: + outfile<<"l"; //output the lines token + break; + case OBJ_FACE: + outfile<<"f"; //output the face token + break; + } + + //for each vertex in the list for the primitive + for(vert = (*p).p.begin(); vert != (*p).p.end(); vert++) + { + outfile<<' '<<(*vert).v + 1; + if((*p).mask & OBJ_VT) + outfile<<'/'<<(*vert).vt + 1; + if((*p).mask & OBJ_VN) + { + if(!((*p).mask & OBJ_VT)) + outfile<<'/'; + outfile<<'/'<<(*vert).vn + 1; + } + } + outfile<<'\n'; + + } + + + +} + +//get methods +unsigned int rtsOBJ::getNumVertices(){return v_list.size();} +unsigned int rtsOBJ::getNumLines(){return lines.size();} +unsigned int rtsOBJ::getNumFaces(){return faces.size();} +unsigned int rtsOBJ::getNumPointLists(){return points.size();} +unsigned int rtsOBJ::getNumTexCoords(){return vt_list.size();} +unsigned int rtsOBJ::getNumNormals(){return vn_list.size();} + +//these functions return the coordinate index as well as the value +unsigned int rtsOBJ::getNumFaceVertices(unsigned int face){return primitives[face].p.size();} +unsigned int rtsOBJ::getFaceVertex(unsigned int face, unsigned int vertex){return primitives[face].p[vertex].v;} +unsigned int rtsOBJ::getFaceNormal(unsigned int face, unsigned int normal){return primitives[face].p[normal].vn;} +unsigned int rtsOBJ::getFaceTexCoord(unsigned int face, unsigned int texcoord){return primitives[face].p[texcoord].vt;} +unsigned int rtsOBJ::getNumLineVertices(unsigned int line){return primitives[line].p.size();} +unsigned int rtsOBJ::getLineVertex(unsigned int line, unsigned int vertex){return primitives[line].p[vertex].v;} +unsigned int rtsOBJ::getLineTexCoord(unsigned int line, unsigned int texcoord){return primitives[line].p[texcoord].vt;} +point3D rtsOBJ::getVertex3d(unsigned int index) +{ + return point3D(v_list[index].x, v_list[index].y, v_list[index].z); +} +point3D rtsOBJ::getTexCoord3d(unsigned int index) +{ + return point3D(vt_list[index].u, vt_list[index].v, vt_list[index].w); +} +point3D rtsOBJ::getNormal3d(unsigned int index) +{ + return point3D(vn_list[index].i, vn_list[index].j, vn_list[index].k); +} +vertex_position rtsOBJ::getVertex(unsigned int index){return v_list[index];} +vertex_texture rtsOBJ::getTexCoord(unsigned int index){return vt_list[index];} +vertex_normal rtsOBJ::getNormal(unsigned int index){return vn_list[index];} + + +unsigned int rtsOBJ::getPrimitiveType(unsigned int primitive) +{ + /* + switch(primitives[i].type) + { + case OBJ_POINTS: + return OBJ_POINTS; + break; + case OBJ_LINES: + return OBJ_LINES; + break; + case OBJ_FACE: + f_RenderFace(i); + break; + }*/ + return 0; +} +/****************************************************/ +/*******Iterator Methods*****************************/ +/****************************************************/ + +rtsOBJ::iterator rtsOBJ::begin() +{ + //create an iterator that will be returned and assign it to this OBJ + iterator result; + result.obj = this; + result.end_object = false; + result.end_primitive = false; + + //if there are no primitives, return the end iterator + if(primitives.size() == 0) + return end(); + + //start at the beginning of the primitive array + result.primitive_index = 0; + + return result; +} + +rtsOBJ::iterator rtsOBJ::end() +{ + //create an end iterator to return + iterator result; + result.obj = this; + result.end_primitive = true; + result.primitive_index = result.obj->primitives.size(); + + return result; +} + +void rtsOBJ::iterator::operator++() +{ + primitive_index++; + if(primitive_index >= obj->primitives.size()) + (*this) = obj->end(); + +} + +bool rtsOBJ::iterator::operator ==(rtsOBJ::iterator operand) +{ + if(operand.primitive_index == primitive_index) + return true; + else return false; +} + +bool rtsOBJ::iterator::operator !=(rtsOBJ::iterator operand) +{ + if(operand.primitive_index != primitive_index) + return true; + else return false; +} + +unsigned int rtsOBJ::iterator::operator*() +{ + return primitive_index; +} + +void rtsOBJ::iterator::print() +{ + cout<<"This is a test"< +#include "cuda_runtime.h" +#include "device_launch_parameters.h" + +#ifndef CUDA_HANDLE_ERROR_H +#define CUDA_HANDLE_ERROR_H + +//handle error macro +static void HandleError( cudaError_t err, const char *file, int line ) { + if (err != cudaSuccess) { + //FILE* outfile = fopen("cudaErrorLog.txt", "w"); + //fprintf(outfile, "%s in %s at line %d\n", cudaGetErrorString( err ), file, line ); + //fclose(outfile); + printf("%s in %s at line %d\n", cudaGetErrorString( err ), file, line ); + //exit( EXIT_FAILURE ); + + } +} +#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ )) + + + +#endif diff --git a/rts/cuda_timer.h b/rts/cuda_timer.h new file mode 100644 index 0000000..fd2786d --- /dev/null +++ b/rts/cuda_timer.h @@ -0,0 +1,21 @@ +static cudaEvent_t tStartEvent; +static cudaEvent_t tStopEvent; + +static void gpuStartTimer() +{ + //set up timing events + cudaEventCreate(&tStartEvent); + cudaEventCreate(&tStopEvent); + cudaEventRecord(tStartEvent, 0); +} + +static float gpuStopTimer() +{ + cudaEventRecord(tStopEvent, 0); + cudaEventSynchronize(tStopEvent); + float elapsedTime; + cudaEventElapsedTime(&elapsedTime, tStartEvent, tStopEvent); + cudaEventDestroy(tStartEvent); + cudaEventDestroy(tStopEvent); + return elapsedTime; +} \ No newline at end of file diff --git a/rts/legendre.h b/rts/legendre.h new file mode 100644 index 0000000..fceca36 --- /dev/null +++ b/rts/legendre.h @@ -0,0 +1,45 @@ +#ifndef RTS_LEGENDRE_H +#define RTS_LEGENDRE_H + +#include "rts/cuda_callable.h" + +namespace rts{ + +template +CUDA_CALLABLE void init_legendre(T x, T& P0, T& P1) +{ + //compute the first two Legendre polynomials + P0 = 1; + P1 = x; +} + +template +CUDA_CALLABLE void shift_legendre(int n, T x, T& P0, T& P1) +{ + //compute the next (order n) Legendre polynomial + T Pnew = ( (2 * n - 1) * x * P1 - (n-1) * P0 ) / n; + + //shift and add the new value to the array + P0 = P1; + P1 = Pnew; +} + +template +CUDA_CALLABLE void legendre(int n, T x, T* P) +{ + P[0] = 1; + + if(n >= 1) + P[1] = x; + + for(int i=2; i<=n; i++) + { + P[i] = ( (2 * i - 1) * x * P[i-1] - (i-1) * P[i-2] ) / i; + } + +} + +} + + +#endif diff --git a/rts/material.h b/rts/material.h new file mode 100644 index 0000000..d7d763d --- /dev/null +++ b/rts/material.h @@ -0,0 +1,530 @@ +#ifndef MATERIALSTRUCT_H +#define MATERIALSTRUCT_H + +#include +#include +#include +#include +#include +#include +#include +#include "rts/rtcomplex.h" + +#define PI 3.14159 + +namespace rts{ + + enum field_type {field_microns, field_wavenumber, field_n, field_k, field_A, field_ignore}; + + //conversion functions + + //convert wavenumber to lambda + template + static T _wn(T inverse_cm) + { + return (T)10000.0/inverse_cm; + } + + template + static T _2wn(T lambda) + { + return (T)10000.0/lambda; + } + + //convert absorbance to k + template + static T _A(T absorbance, T lambda) + { + return (absorbance * lambda) / (4 * PI); + } + template + static T _2A(T k, T lambda) + { + return (4 * PI * k)/lambda; + } + + //define the dispersion as a single wavelength/refractive index pair + template + struct refIndex + { + //wavelength (in microns) + T lambda; + rtcomplex n; + }; + + template + struct entryType + { + //list of value types per entry + std::vector valueList; + + entryType(std::string format) + { + //location of the end of a parameter + size_t e; + + //string storing a token + std::string token; + + do + { + //find the end of the first parameter + e = format.find_first_of(','); + + //get the substring up to the comma + token = format.substr(0, e); + + //turn the token into a val_type + if(token == "microns") + valueList.push_back(field_microns); + else if(token == "wavenumber") + valueList.push_back(field_wavenumber); + else if(token == "n") + valueList.push_back(field_n); + else if(token == "k") + valueList.push_back(field_k); + else if(token == "A") + valueList.push_back(field_A); + else + valueList.push_back(field_ignore); + + //remove the first token from the format string + format = format.substr(e+1, format.length()-1); + }while(e != std::string::npos); + + + + } + + void addValue(field_type value) + { + valueList.push_back(value); + } + + refIndex inputEntry(std::string line, T scaleA = 1.0) + { + T val; + std::stringstream ss(line); + + //create a new refractive index + refIndex newRI; + + + //read the entry from an input string + for(int i=0; i>val; + + //store the value in the appropriate location + switch(valueList[i]) + { + case field_microns: + newRI.lambda = val; + break; + case field_wavenumber: + newRI.lambda = _wn(val); + break; + case field_n: + newRI.n.real(val); + break; + case field_k: + newRI.n.imag(val); + break; + case field_A: + newRI.n.imag(_A(val * scaleA, newRI.lambda)); + break; + } + } + + //return the refractive index associated with the entry + return newRI; + + } + + std::string outputEntry(refIndex material) + { + //std::string result; + std::stringstream ss; + + //for each field in the entry + for(int i=0; i 0) + ss<<"\t"; + //store the value in the appropriate location + switch(valueList[i]) + { + case field_microns: + ss< + class material + { + //dispersion (refractive index as a function of wavelength) + std::vector< refIndex > dispersion; + + //average refractive index (approximately 1.4) + T n0; + + void add(refIndex ri) + { + //refIndex converted = convert(ri, measurement); + dispersion.push_back(ri); + } + + //comparison function for sorting + static bool compare(refIndex a, refIndex b) + { + return (a.lambda < b.lambda); + } + + //comparison function for searching lambda + static bool findCeiling(refIndex a, refIndex b) + { + return (a.lambda > b.lambda); + } + + public: + + unsigned int nSamples() + { + return dispersion.size(); + } + material computeN(T _n0, unsigned int n_samples = 0, T pf = 2) + { + /* This function computes the real part of the refractive index + from the imaginary part. The Hilbert transform is required. I + use an FFT in order to simplify this, so either the FFTW or CUFFT + packages are required. CUFFT is used if this file is passed through + a CUDA compiler. Otherwise, FFTW is used if available. + */ + + n0 = _n0; + + int N; + if(n_samples) + N = n_samples; + else + N = dispersion.size(); + + +#ifdef FFTW_AVAILABLE + //allocate memory for the FFT + rtcomplex* Chi2 = (rtcomplex*)fftw_malloc(sizeof(rtcomplex) * N * pf); + rtcomplex* Chi2FFT = (rtcomplex*)fftw_malloc(sizeof(rtcomplex) * N * pf); + rtcomplex* Chi1 = (rtcomplex*)fftw_malloc(sizeof(rtcomplex) * N * pf); + + //create an FFT plan for the forward and inverse transforms + fftw_plan planForward, planInverse; + planForward = fftw_plan_dft_1d(N*pf, (fftw_complex*)Chi2, (fftw_complex*)Chi2FFT, FFTW_FORWARD, FFTW_ESTIMATE); + planInverse = fftw_plan_dft_1d(N*pf, (fftw_complex*)Chi2FFT, (fftw_complex*)Chi1, FFTW_BACKWARD, FFTW_ESTIMATE); + + float k, alpha; + T chi_temp; + + //the spectrum will be re-sampled in uniform values of wavenumber + T nuMin = _2wn(dispersion.back().lambda); + T nuMax = _2wn(dispersion.front().lambda); + T dnu = (nuMax - nuMin)/(N-1); + T lambda, tlambda; + for(int i=0; i nMin = dispersion.back(); + //rtcomplex nMax = dispersion.front(); + T a; + for(int i=N; i j(0, 1); + for(int i=0; i N/2, multiply by -i + else + Chi2FFT[i] *= -j; + } + + //execute the inverse Fourier transform (completing the Hilbert transform) + fftw_execute(planInverse); + + //divide the Chi1 values by N + for(int i=0; i newM; + newM.dispersion.clear(); + refIndex ri; + for(int i=0; i(); + } + + material(T lambda = 1.0, T n = 1.4, T k = 0.0) + { + //create a default refractive index + refIndex def; + def.lambda = lambda; + def.n.real(n); + def.n.imag(k); + add(def); + + //set n0 + n0 = n; + } + + material(std::string filename, std::string format, T scaleA = 1.0) + { + fromFile(filename, format); + } + + void fromFile(std::string filename, std::string format, T scaleA = 1.0) + { + //clear any previous values + dispersion.clear(); + + //load the file into a string + std::ifstream ifs(filename.c_str()); + + std::string line; + + if(!ifs.is_open()) + { + std::cout<<"Error: material file not found"<(ifs)), std::istreambuf_iterator()); + fromStr(instr, format, scaleA); + + } + + void fromStr(std::string str, std::string format, T scaleA = 1.0) + { + //create a string stream to process the input data + std::stringstream ss(str); + + //this string will be read line-by-line (where each line is an entry) + std::string line; + + //create an entry structure (for now just a basic one) + entryType entry(format); + + T lambda, n, k; + while(!ss.eof()) + { + //read a line from the string + getline(ss, line); + + //if the line is not a comment, process it + if(line[0] != '#') + { + //load the entry and add it to the dispersion list + add(entry.inputEntry(line, scaleA)); + } + //generally have to peek to trigger the eof flag + ss.peek(); + } + + //sort the vector by lambda + sort(dispersion.begin(), dispersion.end(), &material::compare); + } + + //convert the material to a string + std::string toStr(std::string format = "microns,n,k") + { + std::stringstream ss; + entryType entry(format); + for(unsigned int l=0; l 0) ss<& operator[](unsigned int i) + { + return dispersion[i]; + + } + + rtcomplex getN(T l) + { + //declare an iterator + typename std::vector< refIndex >::iterator it; + + refIndex r; + r.lambda = l; + + it = search(dispersion.begin(), dispersion.end(), &r, &r + 1, &material::findCeiling); + + //if the wavelength is past the end of the list, return the back + if(it == dispersion.end()) + return dispersion.back().n; + //if the wavelength is before the beginning of the list, return the front + else if(it == dispersion.begin()) + return dispersion.front().n; + //otherwise interpolate + else + { + T lMax = (*it).lambda; + T lMin = (*(it - 1)).lambda; + //std::cout< riMin = (*(it - 1)).n; + rtcomplex riMax = (*it).n; + rtcomplex interp; + interp = rtcomplex(a, 0.0) * riMin + rtcomplex(1.0 - a, 0.0) * riMax; + return interp; + } + + } + //interpolate the given lambda value and return the index of refraction + rtcomplex operator()(T l) + { + return getN(l); + } + + + }; +} //end namespace rts + +template +std::ostream& operator<<(std::ostream& os, rts::material m) +{ + os< + +namespace rts +{ + +template +struct point +{ + T p[N]; + + CUDA_CALLABLE point() + { + + } + + //efficiency constructor, makes construction easier for 1D-4D vectors + CUDA_CALLABLE point(T x, T y = (T)0.0, T z = (T)0.0, T w = (T)0.0) + { + if(N >= 1) + p[0] = x; + if(N >= 2) + p[1] = y; + if(N >= 3) + p[2] = z; + if(N >= 4) + p[3] = w; + } + + //arithmetic operators + CUDA_CALLABLE rts::point operator+(rts::vector v) + { + rts::point r; + + //calculate the position of the resulting point + for(int i=0; i operator-(rts::vector v) + { + rts::point r; + + //calculate the position of the resulting point + for(int i=0; i operator-(rts::point rhs) + { + rts::vector r; + + //calculate the position of the resulting point + for(int i=0; i operator*(T rhs) + { + rts::point r; + + //calculate the position of the resulting point + for(int i=0; i +std::ostream& operator<<(std::ostream& os, rts::point p) +{ + os< +CUDA_CALLABLE rts::point operator*(T lhs, rts::point rhs) +{ + rts::point r; + + return rhs * lhs; +} + + + +#endif diff --git a/rts/rect.h b/rts/rect.h new file mode 100644 index 0000000..53e07f3 --- /dev/null +++ b/rts/rect.h @@ -0,0 +1,141 @@ +#ifndef RTS_RECT_H +#define RTS_RECT_H + +//enable CUDA_CALLABLE macro +#include "rts/cuda_callable.h" +#include "rts/vector.h" +#include "rts/point.h" +#include + +namespace rts{ + +//template for a rectangle class in ND space +template +struct rect +{ + /* + C------------------>O + ^ ^ + | | + Y | + | | + | | + A---------X-------->B + */ + + /*T A[N]; + T B[N]; + T C[N];*/ + + rts::point A; + rts::vector X; + rts::vector Y; + + + CUDA_CALLABLE rect() + { + + } + + CUDA_CALLABLE rect(point a, point b, point c) + { + + A = a; + X = b - a; + Y = c - a; + + } + + CUDA_CALLABLE rect(rts::point pMin, rts::point pMax, rts::vector normal) + { + + //assign the corner point + A = pMin; + + //compute the vector from pMin to pMax + rts::vector v0; + v0 = pMax - pMin; + + //compute the cross product of A and the plane normal + rts::vector v1; + v1 = v0.cross(normal); + + + //calculate point B + rts::point B; + B = A + v0 * 0.5 + v1 * 0.5; + + //calculate point C + rts::point C; + C = A + v0 * 0.5 - v1 * 0.5; + + //calculate X and Y + X = B - A; + Y = C - A; + + + + + } + + /*CUDA_CALLABLE rect(rts::point p, rts::vector x, rts::vector y, T sx, T sy) + { + //This constructor creates a rect given a position, orientation, and size + // p = center position of the rect + // x = x-axis for the rectangle + // y = y-axis for the rectangle + // sx = size of the rect along the A-B axis + // sy = size of the rect along the A-C axis + + //normalize x and y + rts::vector nx = x.norm(); + rts::vector ny = y.norm(); + + //compute X and Y + X = sx * x; + Y = sy * y; + + //compute A + A = p - 0.5 * X - 0.5 * Y; + + }*/ + + CUDA_CALLABLE rts::point p(T a, T b) + { + rts::point result; + //given the two parameters a, b = [0 1], returns the position in world space + result = A + X * a + Y * b; + + return result; + } + + CUDA_CALLABLE rts::point operator()(T a, T b) + { + return p(a, b); + } + + std::string toStr() + { + std::stringstream ss; + + ss<<"A = "< +#include +#include +#include + +namespace rts +{ + +template +struct rtcomplex +{ + T r, i; + + //default constructor + CUDA_CALLABLE rtcomplex() + { + r = 0.0; + i = 0.0; + } + + //access methods + T real() + { + return r; + } + + T real(T r_val) + { + r = r_val; + return r_val; + } + + T imag() + { + return i; + } + T imag(T i_val) + { + i = i_val; + return i_val; + } + + + + + + //constructor when given real and imaginary values + CUDA_CALLABLE rtcomplex(T r, T i) + { + this->r = r; + this->i = i; + } + + //return the current value multiplied by i + CUDA_CALLABLE rtcomplex imul() + { + rtcomplex result; + result.r = -i; + result.i = r; + + return result; + } + + //ARITHMETIC OPERATORS-------------------- + + //binary + operator (returns the result of adding two complex values) + CUDA_CALLABLE rtcomplex operator+ (const rtcomplex rhs) + { + rtcomplex result; + result.r = r + rhs.r; + result.i = i + rhs.i; + return result; + } + + CUDA_CALLABLE rtcomplex operator+ (const T rhs) + { + rtcomplex result; + result.r = r + rhs; + result.i = i; + return result; + } + + //binary - operator (returns the result of adding two complex values) + CUDA_CALLABLE rtcomplex operator- (const rtcomplex rhs) + { + rtcomplex result; + result.r = r - rhs.r; + result.i = i - rhs.i; + return result; + } + + //binary - operator (returns the result of adding two complex values) + CUDA_CALLABLE rtcomplex operator- (const T rhs) + { + rtcomplex result; + result.r = r - rhs; + result.i = i; + return result; + } + + //binary MULTIPLICATION operators (returns the result of multiplying complex values) + CUDA_CALLABLE rtcomplex operator* (const rtcomplex rhs) + { + rtcomplex result; + result.r = r * rhs.r - i * rhs.i; + result.i = r * rhs.i + i * rhs.r; + return result; + } + CUDA_CALLABLE rtcomplex operator* (const T rhs) + { + return rtcomplex(r * rhs, i * rhs); + } + + //binary DIVISION operators (returns the result of dividing complex values) + CUDA_CALLABLE rtcomplex operator/ (const rtcomplex rhs) + { + rtcomplex result; + T denom = rhs.r * rhs.r + rhs.i * rhs.i; + result.r = (r * rhs.r + i * rhs.i) / denom; + result.i = (- r * rhs.i + i * rhs.r) / denom; + + return result; + } + CUDA_CALLABLE rtcomplex operator/ (const T rhs) + { + return rtcomplex(r / rhs, i / rhs); + } + + //ASSIGNMENT operators----------------------------------- + CUDA_CALLABLE rtcomplex & operator=(const rtcomplex &rhs) + { + //check for self-assignment + if(this != &rhs) + { + this->r = rhs.r; + this->i = rhs.i; + } + return *this; + } + CUDA_CALLABLE rtcomplex & operator=(const T &rhs) + { + this->r = rhs; + this->i = 0; + + return *this; + } + + //arithmetic assignment operators + CUDA_CALLABLE rtcomplex operator+=(const rtcomplex &rhs) + { + *this = *this + rhs; + return *this; + } + CUDA_CALLABLE rtcomplex operator+=(const T &rhs) + { + *this = *this + rhs; + return *this; + } + + CUDA_CALLABLE rtcomplex operator*=(const rtcomplex &rhs) + { + *this = *this * rhs; + return *this; + } + CUDA_CALLABLE rtcomplex operator*=(const T &rhs) + { + *this = *this * rhs; + return *this; + } + //divide and assign + CUDA_CALLABLE rtcomplex operator/=(const rtcomplex &rhs) + { + *this = *this / rhs; + return *this; + } + CUDA_CALLABLE rtcomplex operator/=(const T &rhs) + { + *this = *this / rhs; + return *this; + } + + //absolute value operator (returns the absolute value of the complex number) + CUDA_CALLABLE T abs() + { + return std::sqrt(r * r + i * i); + } + + CUDA_CALLABLE rtcomplex log() + { + rtcomplex result; + result.r = std::log(std::sqrt(r * r + i * i)); + result.i = std::atan2(i, r); + + + return result; + } + + CUDA_CALLABLE rtcomplex exp() + { + rtcomplex result; + + T e_r = std::exp(r); + result.r = e_r * std::cos(i); + result.i = e_r * std::sin(i); + + return result; + } + + /*CUDA_CALLABLE complex pow(int y) + { + + return pow((double)y); + }*/ + + CUDA_CALLABLE rtcomplex pow(T y) + { + rtcomplex result; + + result = log() * y; + + return result.exp(); + } + + CUDA_CALLABLE rtcomplex sqrt() + { + rtcomplex result; + + //convert to polar coordinates + T a = std::sqrt(r*r + i*i); + T theta = std::atan2(i, r); + + //find the square root + T a_p = std::sqrt(a); + T theta_p = theta/2.0; + + //convert back to cartesian coordinates + result.r = a_p * std::cos(theta_p); + result.i = a_p * std::sin(theta_p); + + return result; + } + + std::string toStr() + { + std::stringstream ss; + ss<<"("< rhs) + { + if(r == rhs.r && i == rhs.i) + return true; + return false; + } + + CUDA_CALLABLE bool operator==(T rhs) + { + if(r == rhs && i == (T)0.0) + return true; + return false; + } + + /*//FRIEND functions + //unary minus operator (for negating the complex number) + template CUDA_CALLABLE friend complex operator-(const complex &rhs); + + //multiplication by T values when the complex number isn't on the left hand side + template CUDA_CALLABLE friend complex operator*(const A a, const complex b); + + //division by T values when the complex number isn't on the left hand side + template CUDA_CALLABLE friend complex operator/(const A a, const complex b); + + //POW function + //template CUDA_CALLABLE friend complex pow(const complex x, T y); + template CUDA_CALLABLE friend complex pow(const complex x, int y); + + //log function + template CUDA_CALLABLE friend complex log(complex x); + + //exp function + template CUDA_CALLABLE friend complex exp(complex x); + + //sqrt function + template CUDA_CALLABLE friend complex sqrt(complex x); + + //trigonometric functions + template CUDA_CALLABLE friend complex sin(complex x); + + template CUDA_CALLABLE friend complex cos(complex x);*/ + +}; + +//addition +template +CUDA_CALLABLE static rtcomplex operator+(const double a, const rtcomplex b) +{ + return rtcomplex(a + b.r, b.i); +} + +//subtraction with a real value +template +CUDA_CALLABLE static rtcomplex operator-(const double a, const rtcomplex b) +{ + return rtcomplex(a - b.r, -b.i); +} + +//minus sign +template +CUDA_CALLABLE static rtcomplex operator-(const rtcomplex &rhs) +{ + return rtcomplex(-rhs.r, -rhs.i); +} + +//multiply a T value by a complex value +template +CUDA_CALLABLE static rtcomplex operator*(const double a, const rtcomplex b) +{ + return rtcomplex(a * b.r, a * b.i); +} + +//divide a T value by a complex value +template +CUDA_CALLABLE static rtcomplex operator/(const double a, const rtcomplex b) +{ + //return complex(a * b.r, a * b.i); + rtcomplex result; + + T denom = b.r * b.r + b.i * b.i; + + result.r = (a * b.r) / denom; + result.i = -(a * b.i) / denom; + + return result; +} + +//POW function +/*template +CUDA_CALLABLE static complex pow(complex x, int y) +{ + return x.pow(y); +}*/ + +template +CUDA_CALLABLE static rtcomplex pow(rtcomplex x, T y) +{ + return x.pow(y); +} + +//log function +template +CUDA_CALLABLE static rtcomplex log(rtcomplex x) +{ + return x.log(); +} + +//exp function +template +CUDA_CALLABLE static rtcomplex exp(rtcomplex x) +{ + return x.exp(); +} + +//sqrt function +template +CUDA_CALLABLE static rtcomplex sqrt(rtcomplex x) +{ + return x.sqrt(); +} + + +template +CUDA_CALLABLE static T abs(rtcomplex a) +{ + return a.abs(); +} + +template +CUDA_CALLABLE static T real(rtcomplex a) +{ + return a.r; +} + +template +CUDA_CALLABLE static T imag(rtcomplex a) +{ + return a.i; +} + +//trigonometric functions +template +CUDA_CALLABLE rtcomplex sin(const rtcomplex x) +{ + rtcomplex result; + result.r = std::sin(x.r) * std::cosh(x.i); + result.i = std::cos(x.r) * std::sinh(x.i); + + return result; +} + +template +CUDA_CALLABLE rtcomplex cos(const rtcomplex x) +{ + rtcomplex result; + result.r = std::cos(x.r) * std::cosh(x.i); + result.i = -(std::sin(x.r) * std::sinh(x.i)); + + return result; +} + + + +} //end RTS namespace + +template +std::ostream& operator<<(std::ostream& os, rts::rtcomplex x) +{ + os< + + +namespace rts{ + +#define RTS_BESSEL_CONVERGENCE_FLOAT 0.00045 + +template +CUDA_CALLABLE void sbesselj(int n, rtcomplex x, rtcomplex* j) +{ + //compute the first bessel function + if(n >= 0) + j[0] = sin(x) / x; + + //compute the second bessel function + if(n >= 1) + j[1] = j[0] / x - cos(x) / x; + + //use the recurrence relation to compute the rest + for(int i = 2; i <= n; i++) + { + j[i] = ( (2 * i - 1) / x ) * j[i-1] - j[i-2]; + } + + //if x = 0, deal with the degenerate case + /*if( isnan(j[0].r) ) + { + j[0] = (T)1.0; + for(int i = 1; i<=n; i++) + j[i] = (T)0.0; + }*/ +} + +template +CUDA_CALLABLE void sbessely(int n, rtcomplex x, rtcomplex* y) +{ + //compute the first bessel function + if(n >= 0) + y[0] = -cos(x) / x; + + //compute the second bessel function + if(n >= 1) + y[1] = y[0] / x - sin(x) / x; + + //use the recurrence relation to compute the rest + for(int i = 2; i <= n; i++) + { + y[i] = ( (2 * i - 1) / x ) * y[i-1] - y[i-2]; + } + +} + +//spherical Hankel functions of the first kind +template +CUDA_CALLABLE void sbesselh1(int n, rtcomplex x, rtcomplex* h) +{ + //compute j_0 and j_1 + rtcomplex j[2]; + sbesselj(1, x, j); + + //compute y_0 and y_1 + rtcomplex y[2]; + sbessely(1, x, y); + + //compute the first-order Hhankel function + if(n >= 0) + h[0] = j[0] + y[0].imul(); + + //compute the second bessel function + if(n >= 1) + h[1] = j[1] + y[1].imul(); + + //use the recurrence relation to compute the rest + for(int i = 2; i <= n; i++) + { + h[i] = ( (2 * i - 1) / x ) * h[i-1] - h[i-2]; + } +} + +template +CUDA_CALLABLE void init_sbesselj(T x, T* j) +{ + /*if(x < EPSILON_FLOAT) + { + j[0] = (T)1; + j[1] = (T)0; + return; + }*/ + + //compute the first 2 bessel functions + j[0] = std::sin(x) / x; + + j[1] = j[0] / x - std::cos(x) / x; + + //deal with the degenerate case of x = 0 + /*if(isnan(j[0])) + { + j[0] = (T)1; + j[1] = (T)0; + }*/ + +} + +template +CUDA_CALLABLE void shift_sbesselj(int n, T x, T* j)//, T stability = 1.4) +{ + + /*if(x < EPSILON_FLOAT) + { + j[0] = j[1]; + j[1] = (T)0; + return; + }*/ + + T jnew; + + //compute the next (order n) Bessel function + jnew = ((2 * n - 1) * j[1])/x - j[0]; + + //if(n > stability*x) + if(n > x) + if(jnew < RTS_BESSEL_CONVERGENCE_FLOAT) + jnew = (T)0; + + //deal with the degenerate case of x = 0 + //if(isnan(jnew)) + // jnew = (T)0; + + //shift and add the new value to the array + j[0] = j[1]; + j[1] = jnew; +} + + + +} //end namespace rts + + + +#endif diff --git a/rts/vector.h b/rts/vector.h new file mode 100644 index 0000000..776d9d6 --- /dev/null +++ b/rts/vector.h @@ -0,0 +1,211 @@ +#ifndef RTS_VECTOR_H +#define RTS_VECTOR_H + +#include +//#include "rts/point.h" + +namespace rts +{ + + + +template +struct vector +{ + T v[N]; + + CUDA_CALLABLE vector() + { + //memset(v, 0, sizeof(T) * N); + } + + //efficiency constructor, makes construction easier for 1D-4D vectors + CUDA_CALLABLE vector(T x, T y = (T)0.0, T z = (T)0.0, T w = (T)0.0) + { + if(N >= 1) + v[0] = x; + if(N >= 2) + v[1] = y; + if(N >= 3) + v[2] = z; + if(N >= 4) + v[3] = w; + } + + CUDA_CALLABLE vector(const T(&data)[N]) + { + memcpy(v, data, sizeof(T) * N); + } + + CUDA_CALLABLE T len() + { + //compute and return the vector length + T sum_sq = (T)0; + for(int i=0; i cart2sph() + { + //convert the vector from cartesian to spherical coordinates + //x, y, z -> r, theta, phi + + vector sph; + sph[0] = std::sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); + sph[1] = std::atan2(v[1], v[0]); + sph[2] = std::acos(v[2] / sph[0]); + + return sph; + } + + CUDA_CALLABLE vector sph2cart() + { + //convert the vector from cartesian to spherical coordinates + //r, theta, phi -> x, y, z + + vector cart; + cart[0] = v[0] * std::cos(v[1]) * std::sin(v[2]); + cart[1] = v[0] * std::sin(v[1]) * std::sin(v[2]); + cart[2] = v[0] * std::cos(v[2]); + + return cart; + } + + CUDA_CALLABLE vector norm() + { + //compute and return the vector norm + vector result; + + //compute the vector length + T l = len(); + + //normalize + for(int i=0; i cross(vector rhs) + { + vector result; + + //compute the cross product (only valid for 3D vectors) + result[0] = v[1] * rhs[2] - v[2] * rhs[1]; + result[1] = v[2] * rhs[0] - v[0] * rhs[2]; + result[2] = v[0] * rhs[1] - v[1] * rhs[0]; + + return result; + } + + CUDA_CALLABLE T dot(vector rhs) + { + T result = (T)0; + + for(int i=0; i operator+(vector rhs) + { + vector result; + + for(int i=0; i operator-(vector rhs) + { + vector result; + + for(int i=0; i operator*(T rhs) + { + vector result; + + for(int i=0; i operator/(T rhs) + { + vector result; + + for(int i=0; i +std::ostream& operator<<(std::ostream& os, rts::vector v) +{ + os< +CUDA_CALLABLE rts::vector operator-(rts::vector v) +{ + rts::vector r; + + //negate the vector + for(int i=0; i +CUDA_CALLABLE rts::vector operator*(T lhs, rts::vector rhs) +{ + rts::vector r; + + return rhs * lhs; +} + +#endif diff --git a/rtsCamera.h b/rtsCamera.h new file mode 100755 index 0000000..0b2e4b5 --- /dev/null +++ b/rtsCamera.h @@ -0,0 +1,191 @@ +#include "rtsVector3d.h" +#include "rtsPoint3d.h" +#include "rtsQuaternion.h" + +#ifndef RTS_CAMERA_H +#define RTS_CAMERA_H + +class rtsCamera +{ + vector3D d; //direction that the camera is pointing + point3D p; //position of the camera + vector3D up; //"up" direction + float focus; //focal length of the camera + float fov; + + //private function makes sure that the up vector is orthogonal to the direction vector and both are normalized + void stabalize() + { + vector3D side = up.X(d); + up = d.X(side); + up.Normalize(); + d.Normalize(); + } + +public: + void setPosition(point3D pos) + { + p = pos; + } + void setPosition(float x, float y, float z){setPosition(point3D(x, y, z));} + + void setFocalDistance(float distance){focus = distance;} + void setFOV(float field_of_view){fov = field_of_view;} + + void LookAt(point3D pos) + { + //find the new direction + d = pos - p; + + //find the distance from the look-at point to the current position + focus = d.Length(); + + //stabalize the camera + stabalize(); + } + void LookAt(float px, float py, float pz){LookAt(point3D(px, py, pz));} + void LookAt(point3D pos, vector3D new_up){up = new_up; LookAt(pos);} + void LookAt(float px, float py, float pz, float ux, float uy, float uz){LookAt(point3D(px, py, pz), vector3D(ux, uy, uz));} + void LookAtDolly(float lx, float ly, float lz) + { + //find the current focus point + point3D f = p + focus*d; + vector3D T = point3D(lx, ly, lz) - f; + p = p + T; + } + + void Dolly(vector3D direction) + { + p = p+direction; + } + void Dolly(float x, float y, float z){Dolly(vector3D(x, y, z));} + void Push(float delta) + { + if(delta > focus) + delta = focus; + + focus -= delta; + + Dolly(d*delta); + } + + void Pan(float theta_x, float theta_y, float theta_z) + { + //x rotation is around the up axis + rtsQuaternion qx; + qx.CreateRotation(theta_x, up.x, up.y, up.z); + + //y rotation is around the side axis + vector3D side = up.X(d); + rtsQuaternion qy; + qy.CreateRotation(theta_y, side.x, side.y, side.z); + + //z rotation is around the direction vector + rtsQuaternion qz; + qz.CreateRotation(theta_z, d.x, d.y, d.z); + + //combine the rotations in x, y, z order + rtsQuaternion final = qz*qy*qx; + + //get the rotation matrix + matrix4x4 rot_matrix = final.toMatrix(); + + //apply the rotation + d = rot_matrix*d; + up = rot_matrix*up; + + //stabalize the camera + stabalize(); + + } + void Pan(float theta_x){Pan(theta_x, 0, 0);} + void Tilt(float theta_y){Pan(0, theta_y, 0);} + void Twist(float theta_z){Pan(0, 0, theta_z);} + + void Zoom(float delta) + { + fov -= delta; + if(fov < 0.5) + fov = 0.5; + if(fov > 180) + fov = 180; + } + + void OrbitFocus(float theta_x, float theta_y) + { + //find the focal point + point3D focal_point = p + focus*d; + + //center the coordinate system on the focal point + point3D centered = p - (focal_point - point3D(0, 0, 0)); + + //create the x rotation (around the up vector) + rtsQuaternion qx; + qx.CreateRotation(theta_x, up.x, up.y, up.z); + centered = qx.toMatrix()*centered; + + //get a side vector for theta_y rotation + vector3D side = up.X((point3D(0, 0, 0) - centered).Normalize()); + + rtsQuaternion qy; + qy.CreateRotation(theta_y, side.x, side.y, side.z); + centered = qy.toMatrix()*centered; + + //perform the rotation on the centered camera position + //centered = final.toMatrix()*centered; + + //re-position the camera + p = centered + (focal_point - point3D(0, 0, 0)); + + //make sure we are looking at the focal point + LookAt(focal_point); + + //stabalize the camera + stabalize(); + + } + + void Slide(float u, float v) + { + vector3D V = up.Normalize(); + vector3D U = up.X(d).Normalize(); + + p = p + (V * v) + (U * u); + } + + //accessor methods + point3D getPosition(){return p;} + vector3D getUp(){return up;} + vector3D getDirection(){return d;} + point3D getLookAt(){return p + focus*d;} + float getFOV(){return fov;} + + //output the camera settings + const void print(ostream& output) + { + output<<"Position: "<(0, 0, 0); + d = vector3D(0, 0, 1); + up = vector3D(0, 1, 0); + focus = 1; + + } +}; + + + +#endif \ No newline at end of file diff --git a/rtsCameraController.cpp b/rtsCameraController.cpp new file mode 100755 index 0000000..d53af24 --- /dev/null +++ b/rtsCameraController.cpp @@ -0,0 +1,407 @@ +#include "rtsCameraController.h" +#include +rtsCamera::rtsCamera() +{ + m_camera_state.position = point3D(10, 10, 10); + m_camera_state.lookat = point3D(0, 0, 0); + m_camera_state.up = vector3D(0, 1, 0); + m_camera_state.pers_view_angle = 60; + m_camera_state.near_plane = 1; + m_camera_state.far_plane = 100; +} + +rtsCamera::~rtsCamera() +{ + +} + +rtsCamera::rtsCamera(rtsCameraState initial_state) +{ + m_camera_state = initial_state; + + //make sure that the view and lookat vectors are orthogonal + vector3D lookat = m_camera_state.lookat - m_camera_state.position; + vector3D up = m_camera_state.up; + vector3D side = lookat.X(up); + up = side.X(lookat); + up.Normalize(); + m_camera_state.up = up; +} + +rtsCameraState rtsCamera::getState() +{ + return m_camera_state; +} + +vector3D rtsCamera::getViewVector() +{ + vector3D result = m_camera_state.lookat - m_camera_state.position; + result.Normalize(); + return result; +} + +vector3D rtsCamera::getUpVector() +{ + return m_camera_state.up; +} + +point3D rtsCamera::getPosition() +{ + return m_camera_state.position; +} + +void rtsCamera::setState(rtsCameraState camera_state) +{ + m_camera_state = camera_state; + + //re-orthogonalize the vectors + vector3D view = m_camera_state.lookat - m_camera_state.position; + vector3D side = view.X(m_camera_state.up); + m_camera_state.up = side.X(view); + m_camera_state.up.Normalize(); +} + +void rtsCamera::LookAt(point3D point) +{ + //looks at a point + + //find the new view vector + vector3D view = point - m_camera_state.position; + + //normalize the view vector + view.Normalize(); + + //prepare a new side vector and up vector + vector3D side; + vector3D up; + + //get the up vector + //if the new viewvector is at 0 or 180 degrees to the up vector + float cos_angle = view*m_camera_state.up; + if(cos_angle == 1.0f || cos_angle == -1.0f) + { + //re-calculate the up vector + up = m_camera_state.up.X(m_camera_state.lookat - m_camera_state.position); + } + else + { + //otherwise, just get the current up vector + up = m_camera_state.up; + } + + + //correct the up vector based on the new view vector + side = up.X(view); + up = view.X(side); + up.Normalize(); + + //change the camera state + m_camera_state.up = up; + m_camera_state.lookat = point; +} + +void rtsCamera::Position(point3D p) +{ + m_camera_state.position = p; +} + +void rtsCamera::Up(vector3D up) +{ + m_camera_state.up = up; +} + +void rtsCamera::DollyPosition(point3D p) +{ + vector3D adjustment = p-m_camera_state.position; + m_camera_state.position = p; + m_camera_state.lookat = m_camera_state.lookat + adjustment; +} + +point3D rtsCamera::getLookAtPoint() +{ + return m_camera_state.lookat; +} + + + +void rtsCamera::Pan(double x, double y) +{ + //first calculate the lookat and side vectors + vector3D lookatvector=m_camera_state.lookat - m_camera_state.position; + vector3D sidevector = lookatvector.X(m_camera_state.up); + sidevector.Normalize(); + + m_camera_state.position=m_camera_state.position+sidevector*x; + m_camera_state.lookat=m_camera_state.lookat+sidevector*x; + + vector3D upvector = lookatvector.X(sidevector); + upvector.Normalize(); + m_camera_state.position=m_camera_state.position+upvector*y; + m_camera_state.lookat=m_camera_state.lookat+upvector*y; +} + +void rtsCamera::RotateUpDown(double degrees) +{ + //first calculate the lookat and side vectors + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + vector3D sidevector = lookatvector.X(m_camera_state.up); + m_camera_state.up=sidevector.X(lookatvector); + m_camera_state.up.Normalize(); + sidevector.Normalize(); + + //translate the look-at point to the origin (and the camera with it) + point3D origin = point3D(0.0, 0.0, 0.0); + vector3D translateCamera = origin-m_camera_state.lookat; + + point3D translatedCamera=m_camera_state.position+translateCamera; + + //the next step is to rotate the side vector so that it lines up with the z axis + double a=sidevector.x; + double b=sidevector.y; + double c=sidevector.z; + + double d=sqrt(b*b + c*c); + + //error correction for when we are already looking down the z-axis + if(d==0) + return; + + vector3D XZplane = vector3D(translatedCamera.x, + (translatedCamera.y*c/d - translatedCamera.z*b/d), + (translatedCamera.y*b/d + translatedCamera.z*c/d)); + + vector3D Zaxis = vector3D(XZplane.x*d - XZplane.z*a, + XZplane.y, + XZplane.x*a + XZplane.z*d); + + vector3D rotated = vector3D(Zaxis.x*cos(TORADIANS(degrees)) - Zaxis.y*sin(TORADIANS(degrees)), + Zaxis.x*sin(TORADIANS(degrees)) + Zaxis.y*cos(TORADIANS(degrees)), + Zaxis.z); + + vector3D XZout = vector3D( rotated.x*(d/(a*a + d*d)) + rotated.z*(a/(a*a + d*d)), + rotated.y, + rotated.x*(-a/(a*a+d*d)) + rotated.z*(d/(a*a + d*d))); + + vector3D result = vector3D( XZout.x, + XZout.y*(c*d/(b*b + c*c)) + XZout.z*(b*d/(b*b + c*c)), + XZout.y*(-b*d/(b*b + c*c)) + XZout.z*(c*d/(b*b + c*c))); + + result=result-translateCamera; + + m_camera_state.position.x=result.x; + m_camera_state.position.y=result.y; + m_camera_state.position.z=result.z; + +} + +void rtsCamera::Yaw(double degrees) +{ + //basically, we have to rotate the look-at point around the up vector + //first, translate the look-at point so that the camera is at the origin + point3D origin(0.0, 0.0, 0.0); + point3D temp_lookat = m_camera_state.lookat - (m_camera_state.position - origin); + + //create a rotation matrix to rotate the lookat point around the up vector + float x=m_camera_state.up.x; + float y=m_camera_state.up.y; + float z=m_camera_state.up.z; + float c=cos(TORADIANS(-degrees)); + float s=sin(TORADIANS(-degrees)); + float t=1.0 - cos(TORADIANS(-degrees)); + float m00 = t*x*x + c; + float m01 = t*x*y + s*z; + float m02 = t*x*z - s*y; + float m03 = 0; + float m10 = t*x*y - s*z; + float m11 = t*y*y + c; + float m12 = t*y*z + s*x; + float m13 = 0; + float m20 = t*x*z + s*y; + float m21 = t*y*z - s*x; + float m22 = t*z*z + c; + float m23 = 0; + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + matrix4x4 rotation(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33); + point3D result = rotation*temp_lookat + (m_camera_state.position - origin); + m_camera_state.lookat = result; +} + +void rtsCamera::Pitch(double degrees) +{ + //basically, we have to rotate the look-at point and up vector around the side vector + //first, translate the look-at point so that the camera is at the origin + point3D origin(0.0, 0.0, 0.0); + + //find all three necessary vectors + vector3D temp_lookat = m_camera_state.lookat - m_camera_state.position; + double lookat_length = temp_lookat.Length(); + vector3D temp_up = m_camera_state.up; + vector3D temp_side = temp_lookat.X(temp_up); + temp_lookat.Normalize(); + temp_up.Normalize(); + temp_side.Normalize(); + + + //create a rotation matrix to rotate around the side vector + float x=temp_side.x; + float y=temp_side.y; + float z=temp_side.z; + float c=cos(TORADIANS(degrees)); + float s=sin(TORADIANS(degrees)); + float t=1.0 - cos(TORADIANS(degrees)); + float m00 = t*x*x + c; + float m01 = t*x*y + s*z; + float m02 = t*x*z - s*y; + float m03 = 0; + float m10 = t*x*y - s*z; + float m11 = t*y*y + c; + float m12 = t*y*z + s*x; + float m13 = 0; + float m20 = t*x*z + s*y; + float m21 = t*y*z - s*x; + float m22 = t*z*z + c; + float m23 = 0; + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + matrix4x4 rotation(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33); + + //rotate the up and look-at vectors around the side vector + vector3D result_lookat = rotation*temp_lookat; + vector3D result_up = rotation*temp_up; + result_lookat.Normalize(); + result_up.Normalize(); + + m_camera_state.lookat = m_camera_state.position + result_lookat * lookat_length; + m_camera_state.up = result_up; +} + + +void rtsCamera::RotateLeftRight(double degrees) +//this function rotates the camera around the up vector (which always points along hte positive +//Y world axis). +{ + //translate the look-at point to the origin (and the camera with it) + point3D origin = point3D(0.0, 0.0, 0.0); + vector3D translateCamera = origin-m_camera_state.lookat; + + point3D translatedCamera=m_camera_state.position+translateCamera; + + + //perform the rotation around the look-at point + //using the y-axis as the rotation axis + point3D newcamera; + newcamera.x=translatedCamera.x*cos(TORADIANS(degrees)) - translatedCamera.z*sin(TORADIANS(degrees)); + newcamera.z=translatedCamera.x*sin(TORADIANS(degrees)) + translatedCamera.z*cos(TORADIANS(degrees)); + newcamera.y=translatedCamera.y; + + vector3D newup; + newup.x=m_camera_state.up.x*cos(TORADIANS(degrees)) - m_camera_state.up.z*sin(TORADIANS(degrees)); + newup.z=m_camera_state.up.x*sin(TORADIANS(degrees)) + m_camera_state.up.z*cos(TORADIANS(degrees)); + newup.y=m_camera_state.up.y; + + //translate the lookat point back to it's original position (along with the camera) + newcamera=newcamera-translateCamera; + + m_camera_state.position.x=newcamera.x; + m_camera_state.position.y=newcamera.y; + m_camera_state.position.z=newcamera.z; + + m_camera_state.up.x=newup.x; + m_camera_state.up.y=newup.y; + m_camera_state.up.z=newup.z; + m_camera_state.up.Normalize(); + +} + +void rtsCamera::Forward(double distance) +{ + //calculate the lookat vector (direction of travel) + vector3D old_lookat=m_camera_state.lookat-m_camera_state.position; + old_lookat.Normalize(); + + //calculate the new position of the camera + point3D new_position = m_camera_state.position+old_lookat*distance; + //now calculate the new lookat vector + vector3D new_lookat=m_camera_state.lookat-new_position; + //find the length of the new lookat vector + /*double newlength=lookatvector.length(); + //if the length is 0 or the camera flipped + if((newlength <= 0.0)) + { + //recalculate the lookat vector using the old position + lookatvector=m_camera_state.lookat-m_camera_state.position; + lookatvector.Normalize(); + //adjust the lookat point appropriately + m_camera_state.lookat = new_position + lookatvector; + }*/ + //move the camera to the new position + m_camera_state.position = new_position; +} + +void rtsCamera::ScaleForward(double factor, double min, double max) +{ + /*This function moves the camera forward, scaling the magnitude + of the motion by the length of the view vector. Basically, the closer + the camera is to the lookat point, the slower the camera moves.*/ + + //calculate the lookat vector (direction of travel) + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + //find the length of the view vector + double length = lookatvector.Length(); + //normalize + lookatvector.Normalize(); + + //prevent motion if the bounds would be passed + double new_distance = length - (factor*length); + if(new_distance < min || new_distance > max) + factor = 0; + //move the camera + m_camera_state.position=m_camera_state.position+lookatvector*factor*length; + lookatvector=m_camera_state.lookat-m_camera_state.position; + /*double newlength=lookatvector.length(); + if((newlength < 2)) + { + lookatvector.Normalize(); + m_camera_state.lookat = m_camera_state.position + lookatvector*2; + }*/ + + +} + +void rtsCamera::DollyLeftRight(double distance) +{ + //calculate the side vector vector (direction of travel) + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + vector3D side = lookatvector.X(m_camera_state.up); + side.Normalize(); + + m_camera_state.position=m_camera_state.position+side*distance; + m_camera_state.lookat = m_camera_state.lookat + side*distance; + //lookatvector=m_camera_state.lookat-m_camera_state.position; +} + +void rtsCamera::DollyUpDown(double distance) +{ + //move along the up vector + m_camera_state.up.Normalize(); + + m_camera_state.position=m_camera_state.position+m_camera_state.up*distance; + m_camera_state.lookat = m_camera_state.lookat + m_camera_state.up*distance; + //lookatvector=m_camera_state.lookat-m_camera_state.position; +} + +void rtsCamera::Zoom(double angle) +{ + m_camera_state.pers_view_angle += angle; +} \ No newline at end of file diff --git a/rtsCameraController.h b/rtsCameraController.h new file mode 100755 index 0000000..d17c2b0 --- /dev/null +++ b/rtsCameraController.h @@ -0,0 +1,77 @@ +#include "rtsLinearAlgebra.h" + +#ifndef _RTSMATH_H +#define _RTSMATH_H + +#define CAMERA_UP -1 +#define CAMERA_DOWN 1 +#define CAMERA_LEFT -1 +#define CAMERA_RIGHT 1 + +struct rtsCameraState +{ + point3D position; + point3D lookat; + vector3D up; + float pers_view_angle; + float ortho_width; + float ortho_height; + float near_plane; + float far_plane; +}; + +class rtsCamera +{ + //members + rtsCameraState m_camera_state; + +public: + + //methods + void RotateUpDown(double degrees); + void RotateLeftRight(double degrees); + void Pan(double x, double y); + void Yaw(double degrees); + void Pitch(double degrees); + void Forward(double distance); + void ScaleForward(double factor, double min = 0, double max = 999999); + void DollyLeftRight(double distance); + void DollyUpDown(double distance); + void Zoom(double angle); + void LookAt(point3D point); + void Position(point3D point); + void Up(vector3D up); + void DollyPosition(point3D point); //moves the camera but keeps the current orientation + + //get methods + rtsCameraState getState(); + vector3D getViewVector(); + vector3D getUpVector(); + point3D getPosition(); + point3D getLookAtPoint(); + double getViewAngle(){return m_camera_state.pers_view_angle;} + double getNearPlane(){return m_camera_state.near_plane;} + double getFarPlane(){return m_camera_state.far_plane;} + double getOrthoWidth(){return m_camera_state.ortho_width;} + double getOrthoHeight(){return m_camera_state.ortho_height;} + + //set methods + void setState(rtsCameraState camera_state); + + //initialization methods + //int SetPosition(double x, double y, double z); + //int OrthogonalCamera(double width, double height, double near, double far); + //int LookAt(double x, double y, double z); //looks at a point in space + //int SetUpVector(double x, double y, double z); + /*int InitializePerspectiveCamera(double position_x, double position_y, double position_z, + double lookat_x, double lookat_y, double lookat_z, + double up_x, double up_y, double up_z, + double angle, double near_dist, double far_dist);*/ + //int InitializeCamera(); //initializes a camera to defaults + + rtsCamera(); + rtsCamera(rtsCameraState initial_state); + ~rtsCamera(); +}; + +#endif \ No newline at end of file diff --git a/rtsConstants.h b/rtsConstants.h new file mode 100755 index 0000000..70e683f --- /dev/null +++ b/rtsConstants.h @@ -0,0 +1,15 @@ +#define RTS_OK 0 +#define RTS_ERROR 99 + + +#define RTS_EMPTY 1 //an element can't be deleted if it contains no data +#define RTS_INVALID_ID 2 //an object with this identifier does not exist +#define RTS_INVALID_CONSTANT 3 //an invalid constant passed as a parameter + +//objects +#define RTS_END_OBJECT 4 //reached the end of an object's elements + +//utility constants +#define RTS_NULL 0 + +#define RTS_NO_INTERSECTION 1 //there is no intersection in intersection calculations \ No newline at end of file diff --git a/rtsCubeSampler.cpp b/rtsCubeSampler.cpp new file mode 100755 index 0000000..eab89b1 --- /dev/null +++ b/rtsCubeSampler.cpp @@ -0,0 +1,56 @@ +#include "rtsCubeSampler.h" + +vector rtsCubeSampler::Evaluate() +{ + /*This function evaluates the cube with the given parameters and returns + a vector of sample normalized sample vectors.*/ + + //find a valid up vector + vector3D u(0.0, 1.0, 0.0); + //calculate the side vector + vector3D s = u.cross(m_main_vector); + //orthogonalize the up vector + u = m_main_vector.cross(s); + //normalize all three vectors + m_main_vector.normalize(); + u.normalize(); + s.normalize(); + + //create a vector representing each side of the cube + vector3D sides[6]; + sides[0] = m_main_vector; + sides[1] = (m_main_vector)*(-1); + sides[2] = u; + sides[3] = u*(-1); + sides[4] = s; + sides[5] = s*(-1); + + //calculate the step size along the basis vectors for a side + double step = 1.0/((double)m_squared_samples_per_side); + + //evaluate the cube, storing the result in an STL vector + vector result; + for(int k=0; k<6; k++) + for(int i=0; i= cos(TORADIANS(max_angle))) + result.push_back(final_vector); + } + + //return the vector of results + return result; +} \ No newline at end of file diff --git a/rtsCubeSampler.h b/rtsCubeSampler.h new file mode 100755 index 0000000..9d92b3c --- /dev/null +++ b/rtsCubeSampler.h @@ -0,0 +1,32 @@ +/*This class returns a series of normalized vectors that sample the surface of a cube*/ +/*TODO: +-)Implement random sampling +-)Allow the user to provide a total number of samples + +*/ +#ifndef RTSCUBESAMPLER_H +#define RTSCUBESAMPLER_H + +#include +#include "rtsMath.h" + +using namespace std; + +//definitions for sample types +#define RTS_RANDOM_UNIFORM 0x00001001 +#define RTS_RANDOM_GAUSSIAN 0x00001002 +#define RTS_REGULAR 0x00001003 + +class rtsCubeSampler +{ +public: + + unsigned int m_sample_type; + unsigned int m_squared_samples_per_side; + double max_angle; + vector3D m_main_vector; + + vector Evaluate(); +}; + +#endif \ No newline at end of file diff --git a/rtsDTGrid1D.h b/rtsDTGrid1D.h new file mode 100755 index 0000000..8ec59b8 --- /dev/null +++ b/rtsDTGrid1D.h @@ -0,0 +1,624 @@ +#ifndef _RTS_DTGRID1D_H +#define _RTS_DTGRID1D_H + +#include +#include +using namespace std; + +struct ConnectedComponent +{ + int toValue; + int coordMin; + int coordMax; +}; + + + + +template +class rtsDTGrid1D +{ + +private: + //main arrays + vector value; + vector conn; + + //variables to keep track of insertion + int max_coord; + bool insertion_started; + bool randomIndex(int &v, int &c, int x1); + + +public: + T background; + rtsDTGrid1D() + { + insertion_started = false; + max_coord = 0; + } + int getMaxX1(){return max_coord;} + + T random(int x1); + T& back(); + bool push(int x1, T value); + void insert(rtsDTGrid1D toInsert); + void getBounds(int &min_x1, int &max_x1); + void dilate(int H); + template rtsDTGrid1D

getStorage() + { + //create the resulting grid + rtsDTGrid1D

result; + //create an iterator to run over the existing grid + P* new_value = (P*)calloc(1, sizeof(P)); + for(iterator i = begin(); i!=end(); i.increment()) + { + result.push(i.X1(), *new_value); + } + return result; + + } + void operator=(T rhs); + void print(); + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + iterator randomIterator(int x1); + iterator begin(); + iterator end(); + iterator before(); + iterator after(); + +}; + +/***************ITERATOR*************************/ +template +class rtsDTGrid1D::iterator +{ + friend class rtsDTGrid1D; + + +protected: + rtsDTGrid1D* parent; + int iv; + int ic; + int x1; + +public: + T Value(){return parent->value[iv];} + int X1(){return x1;} + void SetValue(T val){parent->value[iv] = val;} + + iterator(){parent = NULL;} + + void p() + { + //increment the current coordinate and value + x1++; + iv++; + //if we are outside of the current connected component + if(x1 > parent->conn[ic].coordMax) + { + //if this is the last connected component, set the iterator to END and return + if(ic == parent->conn.size() - 1) + { + (*this) = parent->after(); + return; + } + //otherwise move to the next connected component and update the coordinate + ic++; + x1 = parent->conn[ic].coordMin; + } + } + void n() + { + //increment the current coordinate and value + x1--; + iv--; + //if we are outside of the current connected component + if(x1 < parent->conn[ic].coordMin) + { + //if this is the last connected component, set the iterator to END and return + if(ic <= 0) + { + (*this) = parent->before(); + return; + } + //otherwise move to the next connected component and update the coordinate + ic--; + x1 = parent->conn[ic].coordMax; + } + + + } + //boolean operators for comparing iterators + bool operator==(iterator &rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + //if(x1 == rhs.x1) + // return true; + return false; + } + bool operator!=(iterator &rhs){return !((*this) == rhs);} + bool operator<(iterator &rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + //if the parents are the same, test value indices + //if(parent == rhs.parent && iv < rhs.iv) + // return true; + //otherwise test coordinates + //if(parent != rhs.parent && x1 < rhs.x1) + // return true; + return false; + } + bool operator<=(iterator &rhs) + { + if(parent == rhs.parent && iv <= rhs.iv) + return true; + //if(x1 <= rhs.x1) + // return true; + return false; + } + void operator++(){p();} + void operator--(){n();} + + void increment_until(int pos) + { + while(x1 < pos && (*this) != parent->after()) + { + p(); + } + } +}; + + +/************STENCIL ITERATOR********************/ +template +class rtsDTGrid1D::stencil_iterator : public iterator +{ +private: + //list of iterators that make up the template + vector iterator_list; + //iterator positions (relative to the position of the stencil iterator) + vector position_list; + //list containing the values for each position in the stencil + vector value_list; + + void refresh_iterators(); + void set_values(); + void increment_all(); + +public: + typename rtsDTGrid1D::stencil_iterator operator=(const iterator rhs); + void addPosition(int p); + void operator++(){p();} + void p(); + T getValue(int id){return value_list[id];} + bool exists(int id); + +}; + +template +void rtsDTGrid1D::stencil_iterator::increment_all() +{ + //run through each iterator and increment to the correct position + int i; + int dest; + for(i=0; i +void rtsDTGrid1D::stencil_iterator::p() +{ + //increment the current position + rtsDTGrid1D::iterator::p(); + + increment_all(); +} + +template +void rtsDTGrid1D::stencil_iterator::refresh_iterators() +{ + //make sure that the iterator position has been set + if(parent == NULL) + { + cout<<"Iterator location not set."<begin(); + } + increment_all(); + //set the values for all of the iterators + set_values(); +} + +template +void rtsDTGrid1D::stencil_iterator::set_values() +{ + int i; + int dest; + for(i=0; ibackground; + } + + +} + +template +typename rtsDTGrid1D::stencil_iterator rtsDTGrid1D::stencil_iterator::operator=(const iterator rhs) +{ + parent = rhs.parent; + iv = rhs.iv; + ic = rhs.ic; + x1 = rhs.x1; + + refresh_iterators(); + + return (*this); +} + +template +void rtsDTGrid1D::stencil_iterator::addPosition(int p) +{ + position_list.push_back(p); + rtsDTGrid1D::iterator new_iter; + /*If the parent variable is valid (the current iterator is assigned to + a grid), assign the position just added to the same grid. + If the parent isn't set, all iterators are assigned to the appropriate grid + later on when the operator= is used to assign the grid to the stencil. + */ + if(parent != NULL) + { + new_iter = parent->begin(); + refresh_iterators(); + } + + iterator_list.push_back(new_iter); + value_list.resize(value_list.size() + 1); +} + +template +bool rtsDTGrid1D::stencil_iterator::exists(int id) +{ + //returns true if the iterator defined by id points to an actual grid node + + //determine the appropriate position for the iterator + int dest = x1 + position_list[id]; + + if(iterator_list[id].X1() == dest) + return true; + else + return false; + +} + + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::begin() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x1 = conn[0].coordMin; + return result; +} +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::before() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x1 = conn[0].coordMin; + return result; +} + +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x1 = conn[result.ic].coordMax; + return result; +} +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x1 = conn[result.ic].coordMax; + return result; +} + + + + +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::randomIterator(int x1) +{ + //if the grid is empty return a "after" iterator + if(value.size() == 0) + return after(); + + rtsDTGrid1D::iterator result; + result.parent = this; + int v_i, c_i; + + //if the value exists in the grid, create the iterator and return + if(randomIndex(v_i, c_i, x1)) + { + result.iv = v_i; + result.ic = c_i; + int offset = v_i - conn[c_i].toValue; + result.x1 = conn[c_i].coordMin + offset; + } + //if the value doesn't exist + else + { + //if the value lies before the current column + if(x1 < conn[c_i].coordMin) + { + result.ic = c_i; + + } + else + { + //if this is the last connected component + if(c_i >= conn.size() - 1) + return after(); + else + { + c_i++; + result.ic = c_i; + } + } + result.iv = conn[c_i].toValue; + result.x1 = conn[c_i].coordMin; + } + return result; + +} +template +void rtsDTGrid1D::print() +{ + rtsDTGrid1D::iterator i; + i = begin(); + while(i != after()) + { + cout< +bool rtsDTGrid1D::push(int x1, T v) +{ + //test to make sure the insertion is happening in the right order + if(insertion_started && x1 <= max_coord) + { + cout<<"Out-of-order insertion in D = 1: X1 = "< (max_coord + 1)) + { + //start a new connected component + ConnectedComponent new_conn; + new_conn.toValue = value.size(); + new_conn.coordMin = x1; + new_conn.coordMax = x1; + conn.push_back(new_conn); + insertion_started = true; + } + + //insert the value into the grid: + //(a) Insert the value at the end of the coord array + //(b) Increment the coordMax value of the current connected component + //(c) Change the maximum inserted coordinate to the new value + value.push_back(v); + conn[conn.size() - 1].coordMax = x1; + //change max_coord to the new coordinate + max_coord = x1; + return true; +} + +template +void rtsDTGrid1D::insert(rtsDTGrid1D toInsert) +{ + //create source and destination iterators + rtsDTGrid1D::iterator source = toInsert.begin(); + rtsDTGrid1D::iterator dest = begin(); + + while(source != toInsert.after()) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1()); + //if the position exists in dest + if(dest.X1() == source.X1()) + dest.SetValue(source.Value()); + source++; + } + +} + +template +void rtsDTGrid1D::getBounds(int &min_x1, int &max_x1) +{ + //return an empty bounding volume if the grid is empty + if(value.size() == 0) + { + min_x1 = 0; + max_x1 = 0; + return; + } + + //get the minimum and maximum coordinates + min_x1 = conn[0].coordMin; + max_x1 = conn.back().coordMax; +} +template +void rtsDTGrid1D::dilate(int H) +{ + //this function creates a new DT grid dilated by H and copies + //the original grid into the new grid + + //create a new grid + rtsDTGrid1D new_grid; + + //determine the dilated values for the first connected component + int numValues = 0; + int start = conn[0].coordMin - H; + int end = conn[0].coordMax + H; + + //run through each remaining connected component + for(int i=1; i +bool rtsDTGrid1D::randomIndex(int &v, int &c, int x1) +{ + //if the grid is empty return false + if(value.size() == 0) + return false; + + int low = 0; + int high = conn.size()-1; + int mid; + do + { + mid = low + (high - low)/2; + if(x1 > conn[mid].coordMax) + low = mid + 1; + //else if(x1 < conn[mid].coordMin) + else if(x1 < conn[mid].coordMin) + high = mid - 1; + else break; + } + while(low <= high); + + //at this point, mid is either at the appropriate connected component, + //or x1 is not in the grid + int offset = x1 - conn[mid].coordMin; + v = conn[mid].toValue + offset; + c = mid; + if(x1 >= conn[mid].coordMin && x1 <= conn[mid].coordMax) + { + return true; + } + else + { + return false; + } +} + +template +void rtsDTGrid1D::operator=(T rhs) +{ + for(int i=0; i +T& rtsDTGrid1D::back() +{ + return value[value.size()-1]; +} + +template +T rtsDTGrid1D::random(int x1) +{ + int v_i, c_i; + + if(randomIndex(v_i, c_i, x1)) + return value[v_i]; + else + return background; +} + + +#endif diff --git a/rtsDTGrid1D_v1.h b/rtsDTGrid1D_v1.h new file mode 100755 index 0000000..ab5b9bb --- /dev/null +++ b/rtsDTGrid1D_v1.h @@ -0,0 +1,594 @@ + +#include +#include +using namespace std; + +#ifndef _RTS_DTGRID1D_H +#define _RTS_DTGRID1D_H + +struct ConnectedComponent +{ + int toValue; + int coordMin; + int coordMax; +}; + + + + +template +class rtsDTGrid1D +{ + +private: + //main arrays + vector value; + vector conn; + + //variables to keep track of insertion + int max_coord; + bool insertion_started; + bool randomIndex(int &v, int &c, int x1); + + +public: + T background; + rtsDTGrid1D() + { + insertion_started = false; + max_coord = 0; + } + int getMaxX1(){return max_coord;} + + T random(int x1); + T& back(); + bool push(int x1, T value); + void insert(rtsDTGrid1D toInsert); + void getBounds(int &min_x1, int &max_x1); + void dilate(int H); + template rtsDTGrid1D

getStorage() + { + //create the resulting grid + rtsDTGrid1D

result; + //create an iterator to run over the existing grid + P* new_value = (P*)calloc(1, sizeof(P)); + for(iterator i = begin(); i!=end(); i.increment()) + { + result.push(i.X1(), *new_value); + } + return result; + + } + void operator=(T rhs); + void print(); + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + iterator randomIterator(int x1); + iterator begin(); + iterator end(); + iterator before(); + iterator after(); + +}; + +/***************ITERATOR*************************/ +template +class rtsDTGrid1D::iterator +{ + friend class rtsDTGrid1D; + + +protected: + rtsDTGrid1D* parent; + int iv; + int ic; + int x1; + +public: + T Value(){return parent->value[iv];} + int X1(){return x1;} + void SetValue(T val){parent->value[iv] = val;} + + iterator(){parent = NULL;} + + void increment() + { + //increment the current coordinate and value + x1++; + iv++; + //if we are outside of the current connected component + if(x1 > parent->conn[ic].coordMax) + { + //if this is the last connected component, set the iterator to END and return + if(ic == parent->conn.size() - 1) + { + (*this) = parent->after(); + return; + } + //otherwise move to the next connected component and update the coordinate + ic++; + x1 = parent->conn[ic].coordMin; + } + } + + //boolean operators for comparing iterators + bool operator==(iterator rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + return false; + } + bool operator!=(iterator rhs){return !((*this) == rhs);} + friend bool operator<(iterator &left, iterator &right) + { + if(left.iv < right.iv) + return true; + return false; + } + friend bool operator<=(iterator &left, iterator &right) + { + if(left.iv <= right.iv) + return true; + return false; + } + void operator++(){increment();} + + void increment_until(int pos) + { + while(x1 < pos && (*this) != parent->after()) + { + p(); + } + } +}; + + +/************STENCIL ITERATOR********************/ +template +class rtsDTGrid1D::stencil_iterator : public iterator +{ +private: + //list of iterators that make up the template + vector iterator_list; + //iterator positions (relative to the position of the stencil iterator) + vector position_list; + //list containing the values for each position in the stencil + vector value_list; + + void refresh_iterators(); + void set_values(); + void increment_all(); + +public: + typename rtsDTGrid1D::stencil_iterator operator=(const iterator rhs); + void addPosition(int p); + void operator++(){p();} + void p(); + T getValue(int id){return value_list[id];} + bool exists(int id); + +}; + +template +void rtsDTGrid1D::stencil_iterator::increment_all() +{ + //run through each iterator and increment to the correct position + int i; + int dest; + for(i=0; i +void rtsDTGrid1D::stencil_iterator::increment() +{ + //increment the current position + rtsDTGrid1D::iterator::increment(); + + increment_all(); +} + +template +void rtsDTGrid1D::stencil_iterator::refresh_iterators() +{ + //make sure that the iterator position has been set + if(parent == NULL) + { + cout<<"Iterator location not set."<begin(); + } + increment_all(); + //set the values for all of the iterators + set_values(); +} + +template +void rtsDTGrid1D::stencil_iterator::set_values() +{ + int i; + int dest; + for(i=0; ibackground; + } + + +} + +template +typename rtsDTGrid1D::stencil_iterator rtsDTGrid1D::stencil_iterator::operator=(const iterator rhs) +{ + parent = rhs.parent; + iv = rhs.iv; + ic = rhs.ic; + x1 = rhs.x1; + + refresh_iterators(); + + return (*this); +} + +template +void rtsDTGrid1D::stencil_iterator::addPosition(int p) +{ + position_list.push_back(p); + rtsDTGrid1D::iterator new_iter; + /*If the parent variable is valid (the current iterator is assigned to + a grid), assign the position just added to the same grid. + If the parent isn't set, all iterators are assigned to the appropriate grid + later on when the operator= is used to assign the grid to the stencil. + */ + if(parent != NULL) + { + new_iter = parent->begin(); + refresh_iterators(); + } + + iterator_list.push_back(new_iter); + value_list.resize(value_list.size() + 1); +} + +template +bool rtsDTGrid1D::stencil_iterator::exists(int id) +{ + //returns true if the iterator defined by id points to an actual grid node + + //determine the appropriate position for the iterator + int dest = x1 + position_list[id]; + + if(iterator_list[id].X1() == dest) + return true; + else + return false; + +} + + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::begin() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x1 = conn[0].coordMin; + return result; +} +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::before() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x1 = conn[0].coordMin; + return result; +} + +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x1 = conn[result.ic].coordMax; + return result; +} +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x1 = conn[result.ic].coordMax; + return result; +} + + + + +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::randomIterator(int x1) +{ + //if the grid is empty return a "after" iterator + if(value.size() == 0) + return after(); + + rtsDTGrid1D::iterator result; + result.parent = this; + int v_i, c_i; + + //if the value exists in the grid, create the iterator and return + if(randomIndex(v_i, c_i, x1)) + { + result.iv = v_i; + result.ic = c_i; + int offset = v_i - conn[c_i].toValue; + result.x1 = conn[c_i].coordMin + offset; + } + //if the value doesn't exist + else + { + //if the value lies before the current column + if(x1 < conn[c_i].coordMin) + { + result.ic = c_i; + + } + else + { + //if this is the last connected component + if(c_i >= conn.size() - 1) + return after(); + else + { + c_i++; + result.ic = c_i; + } + } + result.iv = conn[c_i].toValue; + result.x1 = conn[c_i].coordMin; + } + return result; + +} +template +void rtsDTGrid1D::print() +{ + rtsDTGrid1D::iterator i; + i = begin(); + while(i != after()) + { + cout< +bool rtsDTGrid1D::push(int x1, T v) +{ + //test to make sure the insertion is happening in the right order + if(insertion_started && x1 <= max_coord) + { + cout<<"Out-of-order insertion in D = 1: X1 = "< (max_coord + 1)) + { + //start a new connected component + ConnectedComponent new_conn; + new_conn.toValue = value.size(); + new_conn.coordMin = x1; + new_conn.coordMax = x1; + conn.push_back(new_conn); + insertion_started = true; + } + + //insert the value into the grid: + //(a) Insert the value at the end of the coord array + //(b) Increment the coordMax value of the current connected component + //(c) Change the maximum inserted coordinate to the new value + value.push_back(v); + conn[conn.size() - 1].coordMax = x1; + //change max_coord to the new coordinate + max_coord = x1; + return true; +} + +template +void rtsDTGrid1D::insert(rtsDTGrid1D toInsert) +{ + //create source and destination iterators + rtsDTGrid1D::iterator source = toInsert.begin(); + rtsDTGrid1D::iterator dest = begin(); + + while(source != toInsert.after()) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1()); + //if the position exists in dest + if(dest.X1() == source.X1()) + dest.SetValue(source.Value()); + source++; + } + +} + +template +void rtsDTGrid1D::getBounds(int &min_x1, int &max_x1) +{ + //return an empty bounding volume if the grid is empty + if(value.size() == 0) + { + min_x1 = 0; + max_x1 = 0; + return; + } + + //get the minimum and maximum coordinates + min_x1 = conn[0].coordMin; + max_x1 = conn.back().coordMax; +} +template +void rtsDTGrid1D::dilate(int H) +{ + //this function creates a new DT grid dilated by H and copies + //the original grid into the new grid + + //create a new grid + rtsDTGrid1D new_grid; + + //determine the dilated values for the first connected component + int numValues = 0; + int start = conn[0].coordMin - H; + int end = conn[0].coordMax + H; + + //run through each remaining connected component + for(int i=1; i +bool rtsDTGrid1D::randomIndex(int &v, int &c, int x1) +{ + //if the grid is empty return false + if(value.size() == 0) + return false; + + int low = 0; + int high = conn.size()-1; + int mid; + do + { + mid = low + (high - low)/2; + if(x1 > conn[mid].coordMax) + low = mid + 1; + //else if(x1 < conn[mid].coordMin) + else if(x1 < conn[mid].coordMin) + high = mid - 1; + else break; + } + while(low <= high); + + //at this point, mid is either at the appropriate connected component, + //or x1 is not in the grid + int offset = x1 - conn[mid].coordMin; + v = conn[mid].toValue + offset; + c = mid; + if(x1 >= conn[mid].coordMin && x1 <= conn[mid].coordMax) + { + return true; + } + else + { + return false; + } +} + +template +void rtsDTGrid1D::operator=(T rhs) +{ + for(int i=0; i +T& rtsDTGrid1D::back() +{ + return value[value.size()-1]; +} + +template +T rtsDTGrid1D::random(int x1) +{ + int v_i, c_i; + + if(randomIndex(v_i, c_i, x1)) + return value[v_i]; + else + return background; +} + + +#endif diff --git a/rtsDTGrid2D.h b/rtsDTGrid2D.h new file mode 100755 index 0000000..568f6fc --- /dev/null +++ b/rtsDTGrid2D.h @@ -0,0 +1,1072 @@ + +#ifndef _RTS_DTGRID2D_H +#define _RTS_DTGRID2D_H + +#include +#include +using namespace std; + +#include "rtsDTGrid1D.h" + + + +struct IndexPair +{ + //int toValue; + int toConn; + int numConn; +}; + + +struct Coord2D +{ + int x1; + int x2; +}; + +#include +using namespace std; + +class ColumnUnion +{ +private: + list Q; + vector* toConn; + +public: + void InsertColumn(IndexPair col) + { + Q.push_back(col); + } + void RemoveColumn() + { + Q.pop_front(); + } + vector MergeColumns(vector *Pc, + vector *n, + int H) + { + int i_Pc = 0; + int i_n = 0; + int smallest_column; + ConnectedComponent smallest_cc; + vector result; + + //iterate while there are remaining connected components in each column + while(i_Pc < Pc->size() || i_n < n->size()) + { + //find the smallest coordMin value at the two index locations + + //if the index is at the end of the primary array + if(i_Pc == Pc->size()) + { + smallest_cc = n->at(i_n); + smallest_cc.coordMin -= H; + smallest_cc.coordMax += H; + i_n++; + } + //if n is at the end of the array + else if(i_n == n->size()) + { + smallest_cc = Pc->at(i_Pc); + i_Pc++; + } + else if(n->at(i_n).coordMin - H < Pc->at(i_Pc).coordMin) + { + smallest_cc = n->at(i_n); + smallest_cc.coordMin -= H; + smallest_cc.coordMax += H; + i_n++; + } + else + { + smallest_cc = Pc->at(i_Pc); + i_Pc++; + } + + //merge the connected component into result + //if the result array is empty or the last connected component doesn't overlap with smallest_cc + if(result.size() == 0 || result.back().coordMax + 1 < smallest_cc.coordMin) + result.push_back(smallest_cc); + else if(result.back().coordMax < smallest_cc.coordMax) + result.back().coordMax = smallest_cc.coordMax; + } + return result; + + } + + vector ComputeUnion(int H) + { + //create a vector to store the result + vector result; + + //for each column in the list, merge it with the result vector + list::iterator i; + vector::iterator start; + vector::iterator end; + for(i = Q.begin(); i != Q.end(); i++) + { + start = toConn->begin() + (*i).toConn; + end = start + (*i).numConn; + vector column(start, end); + result = MergeColumns(&result, &column, H); + } + + //output result + //for(int i=0; i *cc_list) + { + toConn = cc_list; + } +}; + + +/*vector ColumnUnion::MergeColumns(vector *Pc, vector *n, int H) +{ + int i_Pc = 0; + int i_n = 0; + int smallest_column; + ConnectedComponent smallest_cc; + vector result; + + //iterate while there are remaining connected components in each column + while(i_Pc < Pc->size() || i_n < n->size()) + { + //find the smallest coordMin value at the two index locations + + //if the index is at the end of the primary array + if(i_Pc == Pc->size()) + { + smallest_cc = n->at(i_n); + smallest_cc.coordMin -= H; + smallest_cc.coordMax += H; + i_n++; + } + //if n is at the end of the array + else if(i_n == n->size()) + { + smallest_cc = Pc->at(i_Pc); + i_Pc++; + } + else if(n->at(i_n).coordMin - H < Pc->at(i_Pc).coordMin) + { + smallest_cc = n->at(i_n); + smallest_cc.coordMin -= H; + smallest_cc.coordMax += H; + i_n++; + } + else + { + smallest_cc = Pc->at(i_Pc); + i_Pc++; + } + + //merge the connected component into result + //if the result array is empty or the last connected component doesn't overlap with smallest_cc + if(result.size() == 0 || result.back().coordMax + 1 < smallest_cc.coordMin) + result.push_back(smallest_cc); + else if(result.back().coordMax < smallest_cc.coordMax) + result.back().coordMax = smallest_cc.coordMax; + } + return result; +}*/ + +/*vector ColumnUnion::ComputeUnion(int H) +{ + + //create a vector to store the result + vector result; + + //for each column in the list, merge it with the result vector + list::iterator i; + vector::iterator start; + vector::iterator end; + for(i = Q.begin(); i != Q.end(); i++) + { + start = toConn->begin() + (*i).toConn; + end = start + (*i).numConn; + vector column(start, end); + result = MergeColumns(&result, &column, H); + } + + //output result + //for(int i=0; i +class rtsDTGrid2D +{ +private: + //main arrays + vector value; + vector conn; + rtsDTGrid1D proj1D; + bool randomIndex(rtsDTGrid1D::iterator &iter1D, int &v_i, int &c_i, int x1, int x2); + + + + //variables to keep track of insertion + int max_coord; + bool grid_insertion_started; + bool column_insertion_started; + + +public: + rtsDTGrid2D() + { + grid_insertion_started = false; + column_insertion_started = false; + proj1D.background.toConn = -1; + max_coord = 0; + } + + bool push(int x1, int x2, T v); + T random(int x1, int x2); + T& back(); + T background; + void print(); + + friend class ColumnUnion; + void dilate(int H); + void insert(rtsDTGrid2D toInsert); + void operator=(T rhs); + void getBounds(int &min_x1, int &min_x2, int &max_x1, int &max_x2); + + void dumpValue(); + void dumpConn(); + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + iterator randomIterator(int x1, int x2); + iterator begin(); + iterator before(); + iterator end(); + iterator after(); + + //other types of iteration + iterator begin_pn(); + iterator end_pn(); + iterator begin_np(); + iterator end_np(); +}; + +/**********ITERATOR***********************/ +template +class rtsDTGrid2D::iterator +{ + friend class rtsDTGrid2D; + rtsDTGrid2D* parent; + rtsDTGrid1D::iterator loc1D; + int iv; + int ic; + int x2; + +public: + + + T Value(){return parent->value[iv];} + int X1(){return loc1D.X1();} + int X2(){return x2;} + iterator(){parent = NULL;} + void SetValue(T value){parent->value[iv] = value;} + + + void pp() + { + //increment the value + iv++; + //if this exceeds the length of the value array, we are at the end of the grid + if(iv == parent->value.size()) + { + (*this) = parent->after(); + return; + } + + //increment the current coordinate + x2++; + //if we are outside of the current connected component + if(x2 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc1D.Value().toConn + loc1D.Value().numConn) + loc1D++; + //if there are no more connected components + if(ic == parent->conn.size()) + { + //we're at the end, return end + (*this) = parent->end(); + return; + } + x2 = parent->conn[ic].coordMin; + } + } + + void nn() + { + //decrement the value + iv--; + //if this is less than 0, we are at the beginning of the grid + if(iv < 0) + { + (*this) = parent->before(); + return; + } + + //decrement the current coordinate + x2--; + //if we are outside of the current connected component + if(x2 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is the first connected component in the column + if(ic < loc1D.Value().toConn) + loc1D--; + //if there are no more connected components + if(ic < 0) + { + //we're at the beginning, return begin + (*this) = parent->before(); + return; + } + x2 = parent->conn[ic].coordMax; + } + + } + + void pn() + { + //for the most part we will be going backwards through the array + //so first decrement iv + iv--; + x2--; + //if iv is less than the current connected component + if(iv < parent->conn[ic].toValue) + { + //go to the previous connected component + ic--; + //if we are before the first connected component in the column + if(ic < loc1D.Value().toConn) + { + //increment the 1D iterator + loc1D++; + //reset ic to the last component of the new column + ic = loc1D.Value().toConn + loc1D.Value().numConn - 1; + //find the new value identifier + iv = parent->conn[ic].toValue + (parent->conn[ic].coordMax - parent->conn[ic].coordMin); + } + //compute the currect coordinate + x2 = parent->conn[ic].coordMax; + } + } + + void np() + { + //for the most part we will be going forward through the grid + //increment iv + iv++; + x2++; + + //if we are outside of the current connected component + if(x2 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc1D.Value().toConn + loc1D.Value().numConn) + { + loc1D--; + ic = loc1D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x2 = parent->conn[ic].coordMin; + } + + } + + //boolean operators for comparing iterators + bool operator==(iterator &rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + //if(loc1D == rhs.loc1D && x2 == rhs.x2) + // return true; + return false; + } + bool operator!=(iterator &rhs){return !((*this) == rhs);} + + bool operator<(iterator &rhs) + { + if(parent == rhs.parent && iv < rhs.iv) + return true; + //if(loc1D < rhs.loc1D) + // return true; + //else if(loc1D == rhs.loc1D && x2 < rhs.x2) + // return true; + return false; + } + bool operator<=(iterator &rhs) + { + if(parent == rhs.parent && iv <= rhs.iv) + return true; + //if(loc1D <= rhs.loc1D) + // return true; + //else if(loc1D == rhs.loc1D && x2 <= rhs.x2) + // return true; + return false; + } + void operator++(){pp();} + void operator--(){nn();} + void increment_until(int p1, int p2) + { + while((*this) != parent->end()) + { + if(X1() > p1) + return; + else if(X1() == p1 && X2() >= p2) + return; + + pp(); + } + } +}; + +/********STENCIL ITERATOR*****************/ +template +class rtsDTGrid2D::stencil_iterator : public iterator +{ +private: + //list of iterators that make up the template + vector iterator_list; + //iterator positions (relative to the position of the stencil iterator) + vector position_list; + //list containing the values for each position in the stencil + vector value_list; + + void refresh_iterators(); + void set_values(); + void increment_all(); + +public: + typename rtsDTGrid2D::stencil_iterator operator=(const iterator rhs); + void addPosition(int p1, int p2); + void increment(); + void operator++() + { + increment(); + } + T getValue(int id){return value_list[id];} + bool exists(int id); + +}; + +template +void rtsDTGrid2D::stencil_iterator::increment_all() +{ + //run through each iterator and increment to the correct position + int i; + Coord2D dest; + for(i=0; i +void rtsDTGrid2D::stencil_iterator::increment() +{ + //increment the current position + rtsDTGrid2D::iterator::pp(); + + increment_all(); +} + +template +void rtsDTGrid2D::stencil_iterator::refresh_iterators() +{ + //make sure that the iterator position has been set + if(parent == NULL) + { + cout<<"Iterator location not set."<begin(); + iterator_list[i] = parent->randomIterator(X1() + position_list[i].x1, + X2() + position_list[i].x2); + } + //increment_all(); + //set the values for all of the iterators + set_values(); +} + +template +void rtsDTGrid2D::stencil_iterator::set_values() +{ + int i; + Coord2D dest; + for(i=0; ibackground; + } + + +} + +template +typename rtsDTGrid2D::stencil_iterator rtsDTGrid2D::stencil_iterator::operator=(const iterator rhs) +{ + parent = rhs.parent; + loc1D = rhs.loc1D; + iv = rhs.iv; + ic = rhs.ic; + x2 = rhs.x2; + + refresh_iterators(); + + return (*this); +} + +template +void rtsDTGrid2D::stencil_iterator::addPosition(int p1, int p2) +{ + //add a position to the position list and add a new iterator to the iterator list + Coord2D p; + p.x1 = p1; + p.x2 = p2; + position_list.push_back(p); + rtsDTGrid2D::iterator new_iter; + + + iterator_list.push_back(new_iter); + T empty; + value_list.push_back(empty); +} + +template +bool rtsDTGrid2D::stencil_iterator::exists(int id) +{ + int i; + Coord2D dest; + + //determine the appropriate position for the iterator + dest.x1 = X1() + position_list[id].x1; + dest.x2 = X2() + position_list[id].x2; + //now add the value to the value list + if(iterator_list[id].X1() == dest.x1 && iterator_list[id].X2() == dest.x2) + return true; + else + return false; + +} + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::begin() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x2 = conn[0].coordMin; + result.loc1D = proj1D.begin(); + + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::before() +{ + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x2 = conn[0].coordMin; + result.loc1D = proj1D.before(); + + return result; +} + +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x2 = conn[result.ic].coordMax; + result.loc1D = proj1D.end(); + return result; +} + +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::randomIterator(int x1, int x2) +{ + rtsDTGrid2D::iterator result; + result.parent = this; + + //perform the random search + int v_i, c_i; + rtsDTGrid1D::iterator iter1D; + + //if the value exists in the grid, create the iterator and return + if(randomIndex(iter1D, v_i, c_i, x1, x2)) + { + result.loc1D = iter1D; + result.iv = v_i; + result.ic = c_i; + int offset = v_i - conn[c_i].toValue; + result.x2 = conn[c_i].coordMin + offset; + } + //if the value doesn't exist + else + { + //if the 1D iterator is at the end of the grid, return after() + if(iter1D == proj1D.after()) + return after(); + + //if the value lies before the current column + if(x1 < iter1D.X1() || (x1 == iter1D.X1() && x2 < conn[c_i].coordMin) ) + { + result.ic = c_i; + } + //else if the value lies after the current column + else + { + //increment the 1D iterator + iter1D++; + //if this is the last connected component + if(c_i >= conn.size() - 1) + return after(); + else + { + c_i++; + result.ic = c_i; + } + } + + + result.loc1D = iter1D; + result.iv = conn[c_i].toValue; + result.x2 = conn[c_i].coordMin; + } + return result; + + +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x2 = conn[result.ic].coordMax; + result.loc1D = proj1D.after(); + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::begin_pn() +{ + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc1D = proj1D.begin(); + result.ic = result.loc1D.Value().toConn + result.loc1D.Value().numConn - 1; + result.iv = conn[result.ic].toValue + (conn[result.ic].coordMax - conn[result.ic].coordMin); + result.x2 = conn[result.ic].coordMax; + + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::begin_np() +{ + //this is the opposite corner of pn + return end_pn(); +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::end_pn() +{ + if(value.size() == 0) + return after(); + iterator result; + result.parent = this; + result.loc1D = proj1D.end(); + result.ic = result.loc1D.Value().toConn; + result.iv = conn[result.ic].toValue; + result.x2 = conn[result.ic].coordMin; + + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::end_np() +{ + //this is the opposite corner of pn + return begin_pn(); +} + +template +void rtsDTGrid2D::print() +{ + rtsDTGrid2D::iterator i; + i = begin(); + while(i!=end()) + { + cout< +bool rtsDTGrid2D::push(int x1, int x2, T v) +{ + //run this code if we have to start a new column in X1. This happens when: + //(a) we have just inserted the first value into the grid + //(b) the value of x1 is greater than the last value of x1 + if(grid_insertion_started == false || x1 != proj1D.getMaxX1()) + { + //assume that a new column is being created + //create the column in proj1D + IndexPair newPair; + newPair.toConn = conn.size(); + //newPair.toValue = value.size(); + newPair.numConn = 0; + + //if this insertion throws an error, the value was inserted incorrectly + //the error will get thrown by DTGrid1D, so just return + if(!proj1D.push(x1, newPair)) + { + cout<<"Out-of-order insertion in D = 2: X1 = "< result = CUqueue.ComputeUnion(H); + + //compute the new IndexPair representing the column + new_pair.toConn = new_grid.conn.size(); + new_pair.numConn = result.size(); + //store the index pair + iteratorNew.SetValue(new_pair); + + //insert each of the connected components + for(ccIterator = result.begin(); ccIterator!=result.end(); ccIterator++) + { + new_grid.conn.push_back(*ccIterator); + new_grid.conn.back().toValue = numValues; + numValues += (*ccIterator).coordMax - (*ccIterator).coordMin + 1; + } + + //if a column is leaving the stencil + if(iteratorDilate.getValue(0).numConn) + CUqueue.RemoveColumn(); + } + + //allocate space for the new value array + new_grid.value.resize(numValues, background); + + //copy the data from this grid into the new grid + new_grid.insert(*this); + + //replace this grid with the new grid + conn = new_grid.conn; + value = new_grid.value; + proj1D = new_grid.proj1D; + + +} + +template +void rtsDTGrid2D::insert(rtsDTGrid2D toInsert) +{ + //create source and destination iterators + rtsDTGrid2D::iterator source = toInsert.begin(); + rtsDTGrid2D::iterator dest = begin(); + + for(source = toInsert.begin(); source != toInsert.after(); source++) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1(), source.X2()); + //cout<<"source: "< +void rtsDTGrid2D::getBounds(int &min_x1, int &min_x2, int &max_x1, int &max_x2) +{ + //if the grid is empty, return an empty bounding volume + if(value.size() == 0) + { + min_x1 = min_x2 = max_x1 = max_x2 = 0; + return; + } + + //get the min and max values for the 1D grid (x1 coordinate) + proj1D.getBounds(min_x1, max_x1); + + //initialize the min and max values + min_x2 = conn[0].coordMin; + max_x2 = conn.back().coordMax; + + //iterate through all columns finding the smallest and largest coordinate values + rtsDTGrid1D::iterator i; + IndexPair col; + for(i=proj1D.begin(); i!=proj1D.after(); i++) + { + col = i.Value(); + if(conn[col.toConn].coordMin < min_x2) + min_x2 = conn[col.toConn].coordMin; + if(conn[col.toConn + col.numConn - 1].coordMax > max_x2) + max_x2 = conn[col.toConn + col.numConn - 1].coordMax; + } + + +} +template +void rtsDTGrid2D::operator =(T rhs) +{ + for(int i=0; i +void rtsDTGrid2D::dumpValue() +{ + for(int i=0; i +void rtsDTGrid2D::dumpConn() +{ + for(int i=0; i +#include +using namespace std; + +#include "rtsDTGrid1D.h" + +#ifndef _RTS_DTGRID2D_H +#define _RTS_DTGRID2D_H + +struct IndexPair +{ + //int toValue; + int toConn; + int numConn; +}; + +#include "ColumnUnion.h" + +struct Coord2D +{ + int x1; + int x2; +}; + + + +template +class rtsDTGrid2D +{ +private: + //main arrays + vector value; + vector conn; + rtsDTGrid1D proj1D; + bool randomIndex(rtsDTGrid1D::iterator &iter1D, int &v_i, int &c_i, int x1, int x2); + + + + //variables to keep track of insertion + int max_coord; + bool grid_insertion_started; + bool column_insertion_started; + + +public: + rtsDTGrid2D() + { + grid_insertion_started = false; + column_insertion_started = false; + proj1D.background.toConn = -1; + max_coord = 0; + } + + bool push(int x1, int x2, T v); + T random(int x1, int x2); + T& back(); + T background; + void print(); + + friend class ColumnUnion; + void dilate(int H); + void insert(rtsDTGrid2D toInsert); + void operator=(T rhs); + void getBounds(int &min_x1, int &min_x2, int &max_x1, int &max_x2); + + void dumpValue(); + void dumpConn(); + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + iterator randomIterator(int x1, int x2); + iterator begin(); + iterator before(); + iterator end(); + iterator after(); +}; + +/**********ITERATOR***********************/ +template +class rtsDTGrid2D::iterator +{ + friend class rtsDTGrid2D; + rtsDTGrid2D* parent; + rtsDTGrid1D::iterator loc1D; + int iv; + int ic; + int x2; + +public: + + + T Value(){return parent->value[iv];} + int X1(){return loc1D.X1();} + int X2(){return x2;} + iterator(){parent = NULL;} + void SetValue(T value){parent->value[iv] = value;} + + + void increment() + { + //increment the value + iv++; + //if this exceeds the length of the value array, we are at the end of the grid + if(iv == parent->value.size()) + { + (*this) = parent->after(); + return; + } + + //increment the current coordinate + x2++; + //if we are outside of the current connected component + if(x2 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc1D.Value().toConn + loc1D.Value().numConn) + loc1D++; + //if there are no more connected components + if(ic == parent->conn.size()) + { + //we're at the end, return end + (*this) = parent->end(); + return; + } + x2 = parent->conn[ic].coordMin; + } + } + + + //boolean operators for comparing iterators + bool operator==(iterator rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + return false; + } + bool operator!=(iterator rhs){return !((*this) == rhs);} + + friend bool operator<(iterator &left, iterator &right) + { + if(left.iv < right.iv) + return true; + return false; + } + friend bool operator<=(iterator &left, iterator &right) + { + if(left.iv <= right.iv) + return true; + return false; + } + void operator++(){increment();} + void increment_until(int p1, int p2) + { + while((*this) != parent->end()) + { + if(X1() > p1) + return; + else if(X1() == p1 && X2() >= p2) + return; + + increment(); + } + } +}; + +/********STENCIL ITERATOR*****************/ +template +class rtsDTGrid2D::stencil_iterator : public iterator +{ +private: + //list of iterators that make up the template + vector iterator_list; + //iterator positions (relative to the position of the stencil iterator) + vector position_list; + //list containing the values for each position in the stencil + vector value_list; + + void refresh_iterators(); + void set_values(); + void increment_all(); + +public: + typename rtsDTGrid2D::stencil_iterator operator=(const iterator rhs); + void addPosition(int p1, int p2); + void increment(); + void operator++() + { + increment(); + } + T getValue(int id){return value_list[id];} + bool exists(int id); + +}; + +template +void rtsDTGrid2D::stencil_iterator::increment_all() +{ + //run through each iterator and increment to the correct position + int i; + Coord2D dest; + for(i=0; i +void rtsDTGrid2D::stencil_iterator::increment() +{ + //increment the current position + rtsDTGrid2D::iterator::increment(); + + increment_all(); +} + +template +void rtsDTGrid2D::stencil_iterator::refresh_iterators() +{ + //make sure that the iterator position has been set + if(parent == NULL) + { + cout<<"Iterator location not set."<begin(); + iterator_list[i] = parent->randomIterator(X1() + position_list[i].x1, + X2() + position_list[i].x2); + } + //increment_all(); + //set the values for all of the iterators + set_values(); +} + +template +void rtsDTGrid2D::stencil_iterator::set_values() +{ + int i; + Coord2D dest; + for(i=0; ibackground; + } + + +} + +template +typename rtsDTGrid2D::stencil_iterator rtsDTGrid2D::stencil_iterator::operator=(const iterator rhs) +{ + parent = rhs.parent; + loc1D = rhs.loc1D; + iv = rhs.iv; + ic = rhs.ic; + x2 = rhs.x2; + + refresh_iterators(); + + return (*this); +} + +template +void rtsDTGrid2D::stencil_iterator::addPosition(int p1, int p2) +{ + //add a position to the position list and add a new iterator to the iterator list + Coord2D p; + p.x1 = p1; + p.x2 = p2; + position_list.push_back(p); + rtsDTGrid2D::iterator new_iter; + + + iterator_list.push_back(new_iter); + T empty; + value_list.push_back(empty); +} + +template +bool rtsDTGrid2D::stencil_iterator::exists(int id) +{ + int i; + Coord2D dest; + + //determine the appropriate position for the iterator + dest.x1 = X1() + position_list[id].x1; + dest.x2 = X2() + position_list[id].x2; + //now add the value to the value list + if(iterator_list[id].X1() == dest.x1 && iterator_list[id].X2() == dest.x2) + return true; + else + return false; + +} + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::begin() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x2 = conn[0].coordMin; + result.loc1D = proj1D.begin(); + + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::before() +{ + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x2 = conn[0].coordMin; + result.loc1D = proj1D.before(); + + return result; +} + +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x2 = conn[result.ic].coordMax; + result.loc1D = proj1D.end(); + return result; +} + +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::randomIterator(int x1, int x2) +{ + rtsDTGrid2D::iterator result; + result.parent = this; + + //perform the random search + int v_i, c_i; + rtsDTGrid1D::iterator iter1D; + + //if the value exists in the grid, create the iterator and return + if(randomIndex(iter1D, v_i, c_i, x1, x2)) + { + result.loc1D = iter1D; + result.iv = v_i; + result.ic = c_i; + int offset = v_i - conn[c_i].toValue; + result.x2 = conn[c_i].coordMin + offset; + } + //if the value doesn't exist + else + { + //if the 1D iterator is at the end of the grid, return after() + if(iter1D == proj1D.after()) + return after(); + + //if the value lies before the current column + if(x1 < iter1D.X1() || (x1 == iter1D.X1() && x2 < conn[c_i].coordMin) ) + { + result.ic = c_i; + } + //else if the value lies after the current column + else + { + //increment the 1D iterator + iter1D++; + //if this is the last connected component + if(c_i >= conn.size() - 1) + return after(); + else + { + c_i++; + result.ic = c_i; + } + } + + + result.loc1D = iter1D; + result.iv = conn[c_i].toValue; + result.x2 = conn[c_i].coordMin; + } + return result; + + +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x2 = conn[result.ic].coordMax; + result.loc1D = proj1D.after(); + return result; +} + +/**************DT GRID**************************/ +template +bool rtsDTGrid2D::push(int x1, int x2, T v) +{ + //run this code if we have to start a new column in X1. This happens when: + //(a) we have just inserted the first value into the grid + //(b) the value of x1 is greater than the last value of x1 + if(grid_insertion_started == false || x1 != proj1D.getMaxX1()) + { + //assume that a new column is being created + //create the column in proj1D + IndexPair newPair; + newPair.toConn = conn.size(); + //newPair.toValue = value.size(); + newPair.numConn = 0; + + //if this insertion throws an error, the value was inserted incorrectly + //the error will get thrown by DTGrid1D, so just return + if(!proj1D.push(x1, newPair)) + { + cout<<"Out-of-order insertion in D = 2: X1 = "< result = CUqueue.ComputeUnion(H); + + //compute the new IndexPair representing the column + new_pair.toConn = new_grid.conn.size(); + new_pair.numConn = result.size(); + //store the index pair + iteratorNew.SetValue(new_pair); + + //insert each of the connected components + for(ccIterator = result.begin(); ccIterator!=result.end(); ccIterator++) + { + new_grid.conn.push_back(*ccIterator); + new_grid.conn.back().toValue = numValues; + numValues += (*ccIterator).coordMax - (*ccIterator).coordMin + 1; + } + + //if a column is leaving the stencil + if(iteratorDilate.getValue(0).numConn) + CUqueue.RemoveColumn(); + } + + //allocate space for the new value array + new_grid.value.resize(numValues, background); + + //copy the data from this grid into the new grid + new_grid.insert(*this); + + //replace this grid with the new grid + conn = new_grid.conn; + value = new_grid.value; + proj1D = new_grid.proj1D; + + +} + +template +void rtsDTGrid2D::insert(rtsDTGrid2D toInsert) +{ + //create source and destination iterators + rtsDTGrid2D::iterator source = toInsert.begin(); + rtsDTGrid2D::iterator dest = begin(); + + for(source = toInsert.begin(); source != toInsert.after(); source++) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1(), source.X2()); + //cout<<"source: "< +void rtsDTGrid2D::getBounds(int &min_x1, int &min_x2, int &max_x1, int &max_x2) +{ + //if the grid is empty, return an empty bounding volume + if(value.size() == 0) + { + min_x1 = min_x2 = max_x1 = max_x2 = 0; + return; + } + + //get the min and max values for the 1D grid (x1 coordinate) + proj1D.getBounds(min_x1, max_x1); + + //initialize the min and max values + min_x2 = conn[0].coordMin; + max_x2 = conn.back().coordMax; + + //iterate through all columns finding the smallest and largest coordinate values + rtsDTGrid1D::iterator i; + IndexPair col; + for(i=proj1D.begin(); i!=proj1D.after(); i++) + { + col = i.Value(); + if(conn[col.toConn].coordMin < min_x2) + min_x2 = conn[col.toConn].coordMin; + if(conn[col.toConn + col.numConn - 1].coordMax > max_x2) + max_x2 = conn[col.toConn + col.numConn - 1].coordMax; + } + + +} +template +void rtsDTGrid2D::operator =(T rhs) +{ + for(int i=0; i +void rtsDTGrid2D::dumpValue() +{ + for(int i=0; i +void rtsDTGrid2D::dumpConn() +{ + for(int i=0; i +#include +using namespace std; + +#include "rtsDTGrid2D.h" + +struct Coord3D +{ + int x1; + int x2; + int x3; + + bool operator==(Coord3D &rhs) + { + if( (x1 == rhs.x1) && (x2 == rhs.x2) && (x3 == rhs.x3) ) + return true; + return false; + } + + bool operator<(Coord3D &rhs) + { + if(x1 < rhs.x1) + return true; + else if( (x1 == rhs.x1) && (x2 < rhs.x2) ) + return true; + else if( (x1 == rhs.x1) && (x2 == rhs.x2) && (x3 < rhs.x3) ) + return true; + return false; + + } + +}; + + + + +/**************DT GRID**************************/ +template +class rtsDTGrid3D +{ +private: + //main arrays + vector value; + vector conn; + rtsDTGrid2D proj2D; + Coord2D current_column; + bool randomIndex(rtsDTGrid2D::iterator &iter2D, int &v_i, int &c_i, int x1, int x2, int x3); + + + + //variables to keep track of insertion + int max_coord; + bool grid_insertion_started; + bool column_insertion_started; + + +public: + rtsDTGrid3D() + { + grid_insertion_started = false; + column_insertion_started = false; + proj2D.background.toConn = -1; + max_coord = 0; + } + + bool push(int x1, int x2, int x3, T v); + T random(int x1, int x2, int x3); + T background; + + + T& back(); + + void print(); + void operator=(T rhs); + void getBounds(int &min_x1, int &min_x2, int &min_x3, int &max_x1, int &max_x2, int &max_x3); + int getNumNodes(){return value.size();} + void insert(rtsDTGrid3D toInsert); + + //arithmetic + rtsDTGrid3D operator+(rtsDTGrid3D &rhs); + rtsDTGrid3D operator-(rtsDTGrid3D &rhs); + + + //dilation + friend class ColumnUnion; + void dilate(int H); + + /* + + + + + + //other types of iteration + iterator begin_pn(); + iterator end_pn(); + iterator begin_np(); + iterator end_np(); + */ + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + //iterator randomIterator(int x1, int x2); + iterator begin(); + iterator before(); + iterator end(); + iterator after(); + + //other types of iteration + iterator begin_ppn(); + iterator begin_nnp(); + iterator begin_pnp(); + iterator begin_npn(); + iterator begin_pnn(); + iterator begin_npp(); + + + iterator end_ppn(){return begin_nnp();} + iterator end_nnp(){return begin_ppn();} + iterator end_pnp(){return begin_npn();} + iterator end_npn(){return begin_pnp();} + iterator end_pnn(){return begin_npp();} + iterator end_npp(){return begin_pnn();} +}; + + +/**********ITERATOR***********************/ +template +class rtsDTGrid3D::iterator +{ + friend class rtsDTGrid3D; + rtsDTGrid3D* parent; + rtsDTGrid2D::iterator loc2D; + int iv; + int ic; + int x3; + +public: + + + T Value(){return parent->value[iv];} + int X1(){return loc2D.X1();} + int X2(){return loc2D.X2();} + int X3(){return x3;} + Coord3D Coord() + { + Coord3D result; + result.x1 = X1(); + result.x2 = X2(); + result.x3 = X3(); + return result; + } + iterator(){parent = NULL;} + void SetValue(T value){parent->value[iv] = value;} + + + void ppp() + { + //increment the value + iv++; + //if this exceeds the length of the value array, we are at the end of the grid + if(iv == parent->value.size()) + { + (*this) = parent->after(); + return; + } + + //increment the current coordinate + x3++; + //if we are outside of the current connected component + if(x3 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc2D.Value().toConn + loc2D.Value().numConn) + loc2D++; + //if there are no more connected components + if(ic == parent->conn.size()) + { + //we're at the end, return end + (*this) = parent->end(); + return; + } + x3 = parent->conn[ic].coordMin; + } + } + void ppn() + { + //decrement the value + iv--; + + //decrement the current coordinate + x3--; + //if we are outside of the current connected component + if(x3 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is before the first connected component in the column + if(ic < loc2D.Value().toConn) + { + //increment to the next column + loc2D++; + //set the connected component to the last one in the column + ic = loc2D.Value().toConn + loc2D.Value().numConn - 1; + int num_values = parent->conn[ic].coordMax - parent->conn[ic].coordMin + 1; + iv = parent->conn[ic].toValue + num_values - 1; + } + + x3 = parent->conn[ic].coordMax; + } + + + } + + void nnp() + { + //increment the value + iv++; + + //increment the current coordinate + x3++; + //if we are outside of the current connected component + if(x3 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is after the last connected component in the column + if(ic == loc2D.Value().toConn + loc2D.Value().numConn) + { + //decrement to the previous column + loc2D--; + //set the connected component to the first one in the column + ic = loc2D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x3 = parent->conn[ic].coordMin; + } + + + } + + + void nnn() + { + //decrement the value + iv--; + //if this is less than 0, we are at the beginning of the grid + if(iv < 0) + { + (*this) = parent->before(); + return; + } + + //decrement the current coordinate + x3--; + //if we are outside of the current connected component + if(x3 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is the first connected component in the column + if(ic < loc2D.Value().toConn) + loc2D--; + //if there are no more connected components + if(ic < 0) + { + //we're at the beginning, return begin + (*this) = parent->before(); + return; + } + x3 = parent->conn[ic].coordMax; + } + + } + + void pnp() + { + //increment the value + iv++; + + //increment the current coordinate + x3++; + //if we are outside of the current connected component + if(x3 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is after the last connected component in the column + if(ic == loc2D.Value().toConn + loc2D.Value().numConn) + { + //decrement to the previous column + loc2D.pn(); + //set the connected component to the first one in the column + ic = loc2D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x3 = parent->conn[ic].coordMin; + } + + + } + void npn() + { + //decrement the value + iv--; + + //decrement the current coordinate + x3--; + //if we are outside of the current connected component + if(x3 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is before the first connected component in the column + if(ic < loc2D.Value().toConn) + { + //increment to the next column + loc2D.np(); + //set the connected component to the last one in the column + ic = loc2D.Value().toConn + loc2D.Value().numConn - 1; + int num_values = parent->conn[ic].coordMax - parent->conn[ic].coordMin + 1; + iv = parent->conn[ic].toValue + num_values - 1; + } + + x3 = parent->conn[ic].coordMax; + } + + + } + void pnn() + { + //decrement the value + iv--; + + //decrement the current coordinate + x3--; + //if we are outside of the current connected component + if(x3 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is before the first connected component in the column + if(ic < loc2D.Value().toConn) + { + //increment to the next column + loc2D.pn(); + //set the connected component to the last one in the column + ic = loc2D.Value().toConn + loc2D.Value().numConn - 1; + int num_values = parent->conn[ic].coordMax - parent->conn[ic].coordMin + 1; + iv = parent->conn[ic].toValue + num_values - 1; + } + + x3 = parent->conn[ic].coordMax; + } + + + } + void npp() + { + //increment the value + iv++; + + //increment the current coordinate + x3++; + //if we are outside of the current connected component + if(x3 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is after the last connected component in the column + if(ic == loc2D.Value().toConn + loc2D.Value().numConn) + { + //decrement to the previous column + loc2D.np(); + //set the connected component to the first one in the column + ic = loc2D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x3 = parent->conn[ic].coordMin; + } + + + } + + /* + void pn() + { + //for the most part we will be going backwards through the array + //so first decrement iv + iv--; + x2--; + //if iv is less than the current connected component + if(iv < parent->conn[ic].toValue) + { + //go to the previous connected component + ic--; + //if we are before the first connected component in the column + if(ic < loc1D.Value().toConn) + { + //increment the 1D iterator + loc1D++; + //reset ic to the last component of the new column + ic = loc1D.Value().toConn + loc1D.Value().numConn - 1; + //find the new value identifier + iv = parent->conn[ic].toValue + (parent->conn[ic].coordMax - parent->conn[ic].coordMin); + } + //compute the currect coordinate + x2 = parent->conn[ic].coordMax; + } + } + + void np() + { + //for the most part we will be going forward through the grid + //increment iv + iv++; + x2++; + + //if we are outside of the current connected component + if(x2 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc1D.Value().toConn + loc1D.Value().numConn) + { + loc1D--; + ic = loc1D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x2 = parent->conn[ic].coordMin; + } + + } + + + + + friend bool operator<(iterator &left, iterator &right) + { + if(left.iv < right.iv) + return true; + return false; + } + friend bool operator<=(iterator &left, iterator &right) + { + if(left.iv <= right.iv) + return true; + return false; + } + + */ + + void increment_until(int p1, int p2, int p3) + { + while((*this) != parent->end()) + { + if(X1() > p1) + return; + if(X1() == p1 && X2() > p2) + return; + else if(X1() == p1 && X2() == p2 && X3() >= p3) + return; + + ppp(); + } + } + void operator++(){ppp();} + void operator--(){nnn();} + + //boolean operators for comparing iterators + bool operator==(iterator &rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + + //if(loc2D == rhs.loc2D && x3 == rhs.x3) + // return true; + return false; + } + bool operator!=(iterator &rhs){return !((*this) == rhs);} + bool operator<(iterator rhs) + { + if(parent == rhs.parent && iv < rhs.iv) + return true; + //if(loc2D < rhs.loc2D && x3 < rhs.x3) + // return true; + return false; + + } +}; + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x3 = conn[0].coordMin; + result.loc2D = proj2D.begin(); + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x3 = conn[result.ic].coordMax; + result.loc2D = proj2D.end(); + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x2 = conn[result.ic].coordMax; + result.loc2D = proj2D.after(); + return result; +} + + +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::before() +{ + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x2 = conn[0].coordMin; + result.loc2D = proj2D.before(); + + return result; +} + +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_ppn() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin(); + //find the index of the last connected component in the first column + int last_conn = result.loc2D.Value().toConn + result.loc2D.Value().numConn - 1; + result.ic = last_conn; + result.iv = conn[last_conn].toValue + conn[last_conn].coordMax - conn[last_conn].coordMin; + result.x3 = conn[last_conn].coordMax; + + + return result; +} + +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_nnp() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.end(); + //find the index of the first connected component in the last column + int first_conn = result.loc2D.Value().toConn; + result.ic = first_conn; + result.iv = conn[first_conn].toValue; + result.x3 = conn[first_conn].coordMin; + + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_pnp() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin_pn(); + //find the index of the first connected component in the column + int first_conn = result.loc2D.Value().toConn; + result.ic = first_conn; + result.iv = conn[first_conn].toValue; + result.x3 = conn[first_conn].coordMin; + + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_npn() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin_np(); + //find the index of the last connected component in the column + int last_conn = result.loc2D.Value().toConn + result.loc2D.Value().numConn - 1; + result.ic = last_conn; + result.iv = conn[last_conn].toValue + conn[last_conn].coordMax - conn[last_conn].coordMin; + result.x3 = conn[last_conn].coordMax; + + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_pnn() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin_pn(); + //find the index of the last connected component in the column + int last_conn = result.loc2D.Value().toConn + result.loc2D.Value().numConn - 1; + result.ic = last_conn; + result.iv = conn[last_conn].toValue + conn[last_conn].coordMax - conn[last_conn].coordMin; + result.x3 = conn[last_conn].coordMax; + + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_npp() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin_np(); + //find the index of the first connected component in the column + int first_conn = result.loc2D.Value().toConn; + result.ic = first_conn; + result.iv = conn[first_conn].toValue; + result.x3 = conn[first_conn].coordMin; + + + return result; +} +/**************DT GRID METHODS**************************/ +template +bool rtsDTGrid3D::push(int x1, int x2, int x3, T v) +{ + //run this code if we have to start a new column. This happens when: + //(a) we have just inserted the first value into the grid + //(b) the insertion takes place in a different column + if(grid_insertion_started == false || x1 != current_column.x1 || x2 != current_column.x2) + { + //assume that a new column is being created + //create the column in proj1D + IndexPair newPair; + newPair.toConn = conn.size(); + //newPair.toValue = value.size(); + newPair.numConn = 0; + + //if this insertion throws an error, the value was inserted incorrectly + //the error will get thrown by DTGrid2D, so just return + if(!proj2D.push(x1, x2, newPair)) + { + cout<<"Out-of-order insertion in D = 3: X1 = "< +void rtsDTGrid3D::operator =(T rhs) +{ + for(int i=0; i +void rtsDTGrid3D::getBounds(int &min_x1, int &min_x2, int &min_x3, int &max_x1, int &max_x2, int &max_x3) +{ + //if the grid is empty, return an empty bounding volume + if(value.size() == 0) + { + min_x1 = min_x2 = min_x3 = max_x1 = max_x2 = max_x3 = 0; + return; + } + + //get the min and max values for the 1D grid (x1 coordinate) + proj2D.getBounds(min_x1, min_x2, max_x1, max_x2); + + //initialize the min and max values + min_x3 = conn[0].coordMin; + max_x3 = conn.back().coordMax; + + //iterate through all columns finding the smallest and largest coordinate values + rtsDTGrid2D::iterator i; + IndexPair col; + for(i=proj2D.begin(); i!=proj2D.after(); i++) + { + col = i.Value(); + if(conn[col.toConn].coordMin < min_x3) + min_x3 = conn[col.toConn].coordMin; + if(conn[col.toConn + col.numConn - 1].coordMax > max_x3) + max_x3 = conn[col.toConn + col.numConn - 1].coordMax; + } + + +} +template +void rtsDTGrid3D::insert(rtsDTGrid3D toInsert) +{ + //create source and destination iterators + rtsDTGrid3D::iterator source = toInsert.begin(); + rtsDTGrid3D::iterator dest = begin(); + + for(source = toInsert.begin(); source != toInsert.after(); source++) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1(), source.X2(), source.X3()); + //cout<<"source: "< +void rtsDTGrid3D::dilate(int H) +{ + //if the grid is empty, return unchanged + if(value.size() == 0) + return; + + ColumnUnion CUqueue; + CUqueue.ConnectToGrid(&conn); + + + //dilate the N-1 DT-Grid constituent + rtsDTGrid2D dilated_proj2D = proj2D; + + //an empty pair has a number of connected components equal to zero + //this should not happen in reality and can therefore be used to check for new columns + IndexPair empty_pair; + empty_pair.numConn = 0; + + //set the background node to the empty node and dilate the 2D projection + dilated_proj2D.background = empty_pair; + dilated_proj2D.dilate(H); + + //create a new DT Grid that will replace this one + rtsDTGrid3D new_grid; + new_grid.proj2D = dilated_proj2D; + new_grid.proj2D.background.toConn = -1; + + //create iteratorDilate that iterates along the dilated N-1 grid + rtsDTGrid2D::stencil_iterator iteratorDilate; + + //create the template entrance nodes + int n; + for(n=-H; n<=H; n++) + iteratorDilate.addPosition(n, H); + //create the template exit nodes + for(n=-H; n<=H; n++) + iteratorDilate.addPosition(n, -H); + + //create an iterator to set the new proj2D values + rtsDTGrid2D::iterator iteratorNew; + + + //variables for each iteration + IndexPair new_pair; + vector::iterator ccIterator; + unsigned int numValues = 0; + for(iteratorNew = new_grid.proj2D.begin(), + iteratorDilate = dilated_proj2D.begin(); + iteratorDilate != dilated_proj2D.after(); + iteratorNew++, + iteratorDilate++) + { + //if a column is entering the stencil + for(n=0; n<=(2*H); n++) + if(iteratorDilate.getValue(n).numConn) + CUqueue.InsertColumn(iteratorDilate.getValue(n)); + + //compute the union of all columns in the queue + vector result = CUqueue.ComputeUnion(H); + + //compute the new IndexPair representing the column + new_pair.toConn = new_grid.conn.size(); + new_pair.numConn = result.size(); + //store the index pair + iteratorNew.SetValue(new_pair); + + //insert each of the connected components + for(ccIterator = result.begin(); ccIterator!=result.end(); ccIterator++) + { + new_grid.conn.push_back(*ccIterator); + new_grid.conn.back().toValue = numValues; + numValues += (*ccIterator).coordMax - (*ccIterator).coordMin + 1; + } + + //if a column is leaving the stencil + for(n=(2*H + 1); n<=(4*H + 1); n++) + if(iteratorDilate.getValue(n).numConn) + CUqueue.RemoveColumn(); + } + + //allocate space for the new value array + new_grid.value.resize(numValues, background); + + //copy the data from this grid into the new grid + new_grid.insert(*this); + + //replace this grid with the new grid + conn = new_grid.conn; + value = new_grid.value; + proj2D = new_grid.proj2D; + + +} + + + +/***************ARITHMETIC********************************/ +template +rtsDTGrid3D rtsDTGrid3D::operator+(rtsDTGrid3D &rhs) +{ + rtsDTGrid3D result; + + //create an iterator for each DT Grid + rtsDTGrid3D::iterator left = begin(); + rtsDTGrid3D::iterator right = rhs.begin(); + + //iterate both until one iterator has hit after() + while(left != after() && right != rhs.after()) + { + //if the iterators are at the same coordinate + if(left.Coord() == right.Coord()) + { + //insert their sum into the new grid + result.push(left.X1(), left.X2(), left.X3(), left.Value() + right.Value()); + //increment both + left++; right++; + } + //add the lowest (lexicographically) value to the background, insert the result, and increment + else if( (left.Coord() < right.Coord()) ) + { + result.push(left.X1(), left.X2(), left.X3(), left.Value() + rhs.background); + left++; + } + else if( (right.Coord() < left.Coord()) ) + { + result.push(right.X1(), right.X2(), right.X3(), right.Value() + background); + right++; + } + } + + //if the left iterator hasn't finished, iterate to finish it off + while(left != after()) + { + result.push(left.X1(), left.X2(), left.X3(), left.Value() + rhs.background); + left++; + } + + while(right != rhs.after()) + { + result.push(right.X1(), right.X2(), right.X3(), right.Value() + rhs.background); + right++; + } + + + return result; + + +} + +template +rtsDTGrid3D rtsDTGrid3D::operator-(rtsDTGrid3D &rhs) +{ + rtsDTGrid3D result; + + //create an iterator for each DT Grid + rtsDTGrid3D::iterator left = begin(); + rtsDTGrid3D::iterator right = rhs.begin(); + + //iterate both until one iterator has hit after() + while(left != after() && right != rhs.after()) + { + //if the iterators are at the same coordinate + if(left.Coord() == right.Coord()) + { + //insert their sum into the new grid + result.push(left.X1(), left.X2(), left.X3(), left.Value() - right.Value()); + //increment both + left++; right++; + } + //add the lowest (lexicographically) value to the background, insert the result, and increment + else if( (left.Coord() < right.Coord()) ) + { + result.push(left.X1(), left.X2(), left.X3(), left.Value() - rhs.background); + left++; + } + else if( (right.Coord() < left.Coord()) ) + { + result.push(right.X1(), right.X2(), right.X3(), background - right.Value()); + right++; + } + } + + //if the left iterator hasn't finished, iterate to finish it off + while(left != after()) + { + result.push(left.X1(), left.X2(), left.X3(), left.Value() - rhs.background); + left++; + } + + while(right != rhs.after()) + { + result.push(right.X1(), right.X2(), right.X3(), background - right.Value()); + right++; + } + + + return result; + + +} +#endif diff --git a/rtsFilamentNetwork.cpp b/rtsFilamentNetwork.cpp new file mode 100755 index 0000000..0806f8e --- /dev/null +++ b/rtsFilamentNetwork.cpp @@ -0,0 +1,92 @@ +#include "rtsFilamentNetwork.h" + +int rtsFilamentNetwork::LoadFIB(const char* filename) +{ + return fib_load(filename); +} + +int rtsFilamentNetwork::fib_load(const char* filename) +{ + //open the input file + ifstream infile; + infile.open(filename); + if(!infile) return 0; + + //temporary vector storing points + vector> vertices; + vector radii; + point3D input; + point3D max(0.0, 0.0, 0.0); //maximum extents of the points in the file + + float r; + + int i,j; + //get all of the nodes from the file + int num_nodes; + infile>>num_nodes; + int id; + for(i=0; i>id; + infile>>input.x; infile>>input.y; infile>>input.z; infile>>r; + + //update the maximum + if(input.x > max.x) max.x = input.x; + if(input.y > max.y) max.y = input.y; + if(input.z > max.z) max.z = input.z; + + vertices.push_back(input); + radii.push_back(r); + } + + /*Scale the node values based on the maximum value. I do this so that + every node is between 0 - 1 rather than the original scale. In the long run, + it should make rendering easier. + */ + for(i=0; i>num_filaments; + + for(i=0; iobjBegin(OBJ_LINE_STRIP); //begin the filament + infile>>num_edges; + for(j = 1; j>id; id--; + network->objVertex3f(vertices[id].x, vertices[id].y, vertices[id].z); + //this final read is required because of redundancy in the input file + infile>>id; + } + infile>>id; //this final read is also required due to redundancy in the input file + id--; + network->objVertex3f(vertices[id].x, vertices[id].y, vertices[id].z); + infile>>id; + id--; + network->objVertex3f(vertices[id].x, vertices[id].y, vertices[id].z); + network->objEnd(); + } + return 1; +} + +void rtsFilamentNetwork::PrintProperties() +{ + + cout<<"Number of Filaments: "<getNumLines(); +} + +void rtsFilamentNetwork::PrintNetwork() +{ + +} \ No newline at end of file diff --git a/rtsFilamentNetwork.h b/rtsFilamentNetwork.h new file mode 100755 index 0000000..f9a3144 --- /dev/null +++ b/rtsFilamentNetwork.h @@ -0,0 +1,35 @@ +#ifndef RTSFILAMENTNETWORK_H +#define RTSFILAMENTNETWORK_H + +#include "rtsLinearAlgebra.h" +#include "objJedi.h" +#include +#include + +using namespace std; + + +class rtsFilamentNetwork +{ +protected: + rtsOBJ* network; + int fib_load(const char* filename); + +public: + rtsFilamentNetwork(){network = new rtsOBJ();} + + virtual int LoadFIB(const char* filename); + void PrintProperties(); + void PrintNetwork(); + +}; + + + +#endif + + + + + + \ No newline at end of file diff --git a/rtsFilename.h b/rtsFilename.h new file mode 100755 index 0000000..414bbca --- /dev/null +++ b/rtsFilename.h @@ -0,0 +1,67 @@ +#include + +using namespace std; + +#ifndef RTS_FILENAME_H +#define RTS_FILENAME_H + +class rtsFilename +{ +private: + string filename; + +public: + string getFilename() + { + int pos = filename.find_last_of("/\\"); + string name = filename.substr(pos+1, filename.size()); + return name; + } + + rtsFilename& operator=(const string str) + { + filename = str; + return *this; + } + rtsFilename(const string str){filename = str;} + rtsFilename(){filename = "";} + + string getExtension() + { + int pos = filename.find_last_of("."); + string ext = filename.substr(pos+1, filename.size() - pos); + return ext; + } + + string getDirectory() + { + int pos = filename.find_last_of("/\\"); + string directory; + if(pos != -1) + directory = filename.substr(0, pos); + else + directory = ""; + return directory; + } + + string getPrefix() + { + int slash = filename.find_last_of("/\\"); + int dot = filename.find_last_of("."); + + string prefix; + prefix = filename.substr(slash+1, dot - slash - 1); + return prefix; + + } + + string getString() + { + return filename; + } + + + +}; + +#endif \ No newline at end of file diff --git a/rtsFunction3D.h b/rtsFunction3D.h new file mode 100755 index 0000000..3711979 --- /dev/null +++ b/rtsFunction3D.h @@ -0,0 +1,913 @@ +#ifndef RTSFUNCTION3D_H +#define RTSFUNCTION3D_H + +#define DIST_MAX 255 + +#include "rtsLinearAlgebra.h" +//#include "rtsDTGrid3D.h" +#include +//#include +//#include +//#include +//#include +using namespace std; + +typedef int indextype; + +///This class represents a 3D implicit function as a grid. It provides methods for accessing values, interpolation, and several utilities. + +template class rtsFunction3D +{ +private: + //pointer to store the data + T* m_data; + //resolution of the data (x, y, z) dimensional extents + vector3D m_resolution; + T m_boundary; //boundary condition + point3D m_domain_min; //min and max range values (used for parametric access) + point3D m_domain_max; + vector3D m_voxel_size; + + //bit-blit function copies 3D data quickly from source to dest + void blit3D(const T* source, + indextype s_px, indextype s_py, indextype s_pz, + indextype s_sx, indextype s_sy, indextype s_sz, + T* dest, + indextype d_px, indextype d_py, indextype d_pz, + indextype d_sx, indextype d_sy, indextype d_sz, + indextype blit_size_x, indextype blit_size_y, indextype blit_size_z); + + void shallow_copy(const rtsFunction3D source, rtsFunction3D &dest); + inline point3D getParameter(indextype i); + void initialize_empty(indextype res_x, indextype res_y, indextype res_z); + +public: + //construct an implicit function with a size of 1 + rtsFunction3D(); /// resolution, T boundary, point3D min_domain, point3D max_domain); + //full copy constructor, defines all variables + rtsFunction3D(T* data, vector3D resolution, T boundary, point3D min_domain, point3D max_domain); + rtsFunction3D(const rtsFunction3D &original); //copy constructor + ~rtsFunction3D(); //destructor + void Init(indextype res_x, indextype res_y, indextype res_z); + + //overloaded operators + rtsFunction3D& operator=(const rtsFunction3D& original); ///& operator=(const T constant); ///& operator*=(const T constant); ///& operator+=(const T constant); ///& operator-=(const T constant); ///& operator/=(const T constant); /// operator+(const T constant); /// operator-(const T constant); /// operator*(const T constant); /// operator/(const T constant); /// friend class rtsFunction3D; + template operator rtsFunction3D(); /// operator*(const T lhs, rtsFunction3D rhs){return rhs*lhs;} /// operator+(const T lhs, rtsFunction3D rhs){return rhs+lhs;} /// operator-(const T lhs, rtsFunction3D rhs) /// result; + rhs.shallow_copy(rhs, result); //make a copy of all of the shallow variables and allocate memory + indextype size = rhs.m_resolution.x * rhs.m_resolution.y * rhs.m_resolution.z; + //iterate and subtract + for(indextype i=0; i operator/(const T lhs, rtsFunction3D rhs); + + //loading/saving data to disk + void LoadRAW(indextype header_size, indextype data_x, indextype data_y, indextype data_z, const char* filename); /// Project2D(); // getParameter(indextype x, indextype y, indextype z); + inline point3D getNearestIndex(double i, double j, double k); + inline point3D getFractionalIndex(double i, double j, double k); + inline point3D getNearestIndex(indextype i); + point3D getMinDomain(){return m_domain_min;} + point3D getMaxDomain(){return m_domain_max;} + + //data input methods + void Insert(rtsFunction3D* source, indextype x, indextype y, indextype z); + + //data massaging + + void Scale(T min, T max); + void Crop(indextype x, indextype y, indextype z, indextype size_x, indextype size_y, indextype size_z); + void Binary(T threshold, T true_value); ///* Resample(indextype newres_x, indextype newres_y, indextype newres_z); + + //output functions + void toConsole(); + +}; + +template +void rtsFunction3D::blit3D(const T* source, + indextype s_px, indextype s_py, indextype s_pz, + indextype s_sx, indextype s_sy, indextype s_sz, + T* dest, + indextype d_px, indextype d_py, indextype d_pz, + indextype d_sx, indextype d_sy, indextype d_sz, + indextype blit_size_x, indextype blit_size_y, indextype blit_size_z) +{ + indextype ps, pd; //stores the mapping for the source point to the dest point + //find the maximum points that can be blit to (in case source overlaps the edges of dest) + blit_size_x = min(blit_size_x, min(s_sx - s_px, d_sx - d_px)); + blit_size_y = min(blit_size_y, min(s_sy - s_py, d_sy - d_py)); + blit_size_z = min(blit_size_z, min(s_sz - s_pz, d_sz - d_pz)); + + indextype source_z_offset = s_sx * s_sy; + indextype dest_z_offset = d_sx * d_sy; + + indextype z,y; + for(z=0; z +void rtsFunction3D::shallow_copy(const rtsFunction3D source, rtsFunction3D &dest) +{ + dest = rtsFunction3D(source.m_resolution.x, source.m_resolution.y, source.m_resolution.z); + dest.m_boundary = source.m_boundary; + dest.m_domain_max = source.m_domain_max; + dest.m_domain_min = source.m_domain_max; + dest.m_voxel_size = source.m_voxel_size; +} + +template +rtsFunction3D::rtsFunction3D(vector3D resolution, T boundary, point3D domain_min, point3D domain_max) +{ + //This function creates an implicit function based on all of the shallow variables + m_resolution = resolution; + m_boundary = boundary; + m_domain_min = domain_min; + m_domain_max = domain_max; + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; + + //allocate the data + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; +} + +template +rtsFunction3D::rtsFunction3D(T* data, vector3D resolution, T boundary, point3D domain_min, point3D domain_max) +{ + //This function creates an implicit function based on ALL of the variables + m_resolution = resolution; + m_boundary = boundary; + m_domain_min = domain_min; + m_domain_max = domain_max; + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; + + //allocate the data + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + m_data = new T[size]; + memcpy(m_data, data, sizeof(T)*size); + //for(int i=0; i +rtsFunction3D::rtsFunction3D() +{ + m_resolution.x = 1; + m_resolution.y = 1; + m_resolution.z = 1; + m_data = new T[1]; + memset(&m_boundary, 0, sizeof(T)); //initialize boundary condition + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + m_voxel_size = vector3D(1.0, 1.0, 1.0); +} + +template +void rtsFunction3D::initialize_empty(indextype res_x, indextype res_y, indextype res_z) +{ + m_resolution.x = res_x; //set resolution vector + m_resolution.y = res_y; + m_resolution.z = res_z; + m_data = (T*)calloc(res_x*res_y*res_z, sizeof(T)); //allocate data +} + +template +rtsFunction3D::rtsFunction3D(indextype res_x, indextype res_y, indextype res_z) +{ + initialize_empty(res_x, res_y, res_z); + memset(&m_boundary, 0, sizeof(T)); //initialize boundary condition + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +void rtsFunction3D::Init(indextype res_x, indextype res_y, indextype res_z) +{ + initialize_empty(res_x, res_y, res_z); + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + memset(&m_boundary, 0, sizeof(T)); //initialize boundary condition + + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +rtsFunction3D::rtsFunction3D(T* data, indextype res_x, indextype res_y, indextype res_z) +{ + m_resolution.x = res_x; //set resolution vector + m_resolution.y = res_y; + m_resolution.z = res_z; + m_data = new T[res_x*res_y*res_z]; //allocate data + //copy the sample data into the data array + indextype size = res_x*res_y*res_z; + for(indextype i=0; i(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +rtsFunction3D::rtsFunction3D(const rtsFunction3D& original) +{ + //copy the shallow variables + m_resolution = original.m_resolution; + m_boundary = original.m_boundary; + m_domain_min = original.m_domain_min; + m_domain_max = original.m_domain_max; + m_voxel_size = original.m_voxel_size; + + //allocate space for the data + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; + //copy the data + blit3D(original.m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_resolution.x, m_resolution.y, m_resolution.z); +} + +template +rtsFunction3D::~rtsFunction3D() +{ + delete m_data; +} + +template +typename rtsFunction3D& rtsFunction3D::operator=(const T rhs) +{ + indextype size = m_resolution.x*m_resolution.y*m_resolution.z; + for(int i=0; i +typename rtsFunction3D& rtsFunction3D::operator=(const rtsFunction3D& rhs) +{ + //check for self-assignment + if(this == &rhs) + return *this; + + //deallocate memory + if(m_data != NULL) + delete m_data; + + //copy the shallow variables + m_resolution = rhs.m_resolution; + m_boundary = rhs.m_boundary; + m_domain_min = rhs.m_domain_min; + m_domain_max = rhs.m_domain_max; + m_voxel_size = rhs.m_voxel_size; + + //allocate and copy memory + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; + //copy the data + blit3D(rhs.m_data, + 0,0,0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_resolution.x, m_resolution.y, m_resolution.z); + + //return the left hand side + return *this; +} + +template +inline T& rtsFunction3D::operator ()(indextype x, indextype y, indextype z) +{ + return xyz(x, y, z); +} + +template +inline T rtsFunction3D::operator()(double i, double j, double k) +{ + return ijk(i, j, k); +} + +template +rtsFunction3D& rtsFunction3D::operator *=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsFunction3D& rtsFunction3D::operator +=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsFunction3D& rtsFunction3D::operator -=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsFunction3D& rtsFunction3D::operator /=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +const rtsFunction3D rtsFunction3D::operator *(const T constant) +{ + rtsFunction3D result = (*this); + result *= constant; + + return result; +} + +template +const rtsFunction3D rtsFunction3D::operator +(const T constant) +{ + rtsFunction3D result = (*this); + result += constant; + + return result; +} + +template +const rtsFunction3D rtsFunction3D::operator -(const T constant) +{ + rtsFunction3D result = (*this); + result -= constant; + + return result; +} + +template +const rtsFunction3D rtsFunction3D::operator /(const T constant) +{ + rtsFunction3D result = (*this); + result /= constant; + + return result; +} + +template +template +rtsFunction3D::operator rtsFunction3D() +{ + //cast one type to another + //create the data pointer from the current function + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + U* new_data = new U[size]; + for(int i=0; i cast_result(new_data, m_resolution, m_boundary, m_domain_min, m_domain_max); + + return cast_result; +} + +template +inline T& rtsFunction3D::xyz(indextype x, indextype y, indextype z) +{ + if(x<0 || y<0 || z<0 || x>=m_resolution.x || y>=m_resolution.y || z>=m_resolution.z) + return m_boundary; + //return m_data[(z * m_resolution.x * m_resolution.y) + (y * m_resolution.x) + x]; + return m_data[x + m_resolution.x * (y + z * m_resolution.y)]; + +} + +template +inline point3D rtsFunction3D::getNearestIndex(indextype i) +{ + point3D result; + result.z = i/(m_resolution.x*m_resolution.y); + indextype mod = i%(m_resolution.x*m_resolution.y); + result.y = mod/m_resolution.x; + result.x = mod%m_resolution.x; + + return result; + +} + +template +void rtsFunction3D::LoadRAW(indextype header_size, indextype size_x, + indextype size_y, indextype size_z, const char *filename) +{ + //set the data size + m_resolution = vector3D(size_x, size_y, size_z); + //delete any previous data + if(m_data != NULL) + { + delete m_data; + m_data = NULL; + } + + ifstream infile(filename, ios::in | ios::binary); + + //load the header + unsigned char* header = new unsigned char[header_size]; + infile.read((char*)header, header_size); + + //load the actual data + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + //m_data = (T*)malloc(size*sizeof(T)); + initialize_empty(m_resolution.x, m_resolution.y, m_resolution.z); + infile.read((char*)m_data, size*sizeof(T)); + + //calculate min and maxes + infile.close(); +} + +template +void rtsFunction3D::LoadVOL(const char *filename) +{ + ifstream infile(filename, ios::in | ios::binary); //create the files stream + if(!infile) + return; + + indextype size_x, size_y, size_z; //create variables to store the size of the data set + //load the dimensions of the data set + infile.read((char*)&size_x, sizeof(int)); //load the file header + infile.read((char*)&size_y, sizeof(int)); + infile.read((char*)&size_z, sizeof(int)); + + //close the file + infile.close(); + //load the raw data + LoadRAW(12, size_x, size_y, size_z, filename); +} + +template +void rtsFunction3D::SaveVOL(const char *filename) +{ + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume size to the file + vector3D vol_size = m_resolution; + outfile.write((char*)&vol_size.x, sizeof(int)); + outfile.write((char*)&vol_size.y, sizeof(int)); + outfile.write((char*)&vol_size.z, sizeof(int)); + + outfile.write((char*)m_data, sizeof(T)*vol_size.x*vol_size.y*vol_size.z); +} + +template +void rtsFunction3D::SaveRAW(const char *filename) +{ + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume data + outfile.write((char*)m_data, sizeof(T)*m_resolution.x*m_resolution.y*m_resolution.z); +} + +template +inline T rtsFunction3D::ijk(double i, double j, double k) +{ + /*This function determines the value at the specified parametric points + defined by the m_domain_min and m_domain_max parameter values.*/ + + //if the parameter is outside the range, return the boundary value + if(im_domain_max.x || j>m_domain_max.y || k>m_domain_max.z) + return m_boundary; + + point3D index = getFractionalIndex(i, j, k); + + //cout< +void rtsFunction3D::Parameterize(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) +{ + m_domain_min = point3D(x_min, y_min, z_min); + m_domain_max = point3D(x_max, y_max, z_max); + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +inline point3D rtsFunction3D::getParameter(indextype x, indextype y, indextype z) +{ + //get the value between 0 and 1 + point3D normalized((double)x / (double)(m_resolution.x) + (1.0/(m_resolution.x*2.0)), + (double)y / (double)(m_resolution.y) + (1.0/(m_resolution.y*2.0)), + (double)z/(double)(m_resolution.z) + (1.0/(m_resolution.z*2.0))); + + point3D result(normalized.x * (m_domain_max.x - m_domain_min.x) + m_domain_min.x, + normalized.y * (m_domain_max.y - m_domain_min.y) + m_domain_min.y, + normalized.z * (m_domain_max.z - m_domain_min.z) + m_domain_min.z); + + return result; +} + +template +inline point3D rtsFunction3D::getNearestIndex(double i, double j, double k) +{ + //this function returns the index of the voxel containing the specified parameter point + point3D normalized((i - m_domain_min.x)/(m_domain_max.x-m_domain_min.x), + (j - m_domain_min.y)/(m_domain_max.y-m_domain_min.y), + (k - m_domain_min.z)/(m_domain_max.z-m_domain_min.z)); + + point3D result((normalized.x - (1.0/(m_resolution.x*2.0)))*(double)m_resolution.x+0.5, + (normalized.y - (1.0/(m_resolution.y*2.0)))*(double)m_resolution.y+0.5, + (normalized.z - (1.0/(m_resolution.z*2.0)))*(double)m_resolution.z+0.5); + + return result; +} + +template +inline point3D rtsFunction3D::getFractionalIndex(double i, double j, double k) +{ + //this function returns the index of the voxel containing the specified parameter point + point3D normalized((i - m_domain_min.x)/(m_domain_max.x-m_domain_min.x), + (j - m_domain_min.y)/(m_domain_max.y-m_domain_min.y), + (k - m_domain_min.z)/(m_domain_max.z-m_domain_min.z)); + + point3D result((normalized.x - (1.0/(m_resolution.x*2.0)))*(double)m_resolution.x, + (normalized.y - (1.0/(m_resolution.y*2.0)))*(double)m_resolution.y, + (normalized.z - (1.0/(m_resolution.z*2.0)))*(double)m_resolution.z); + return result; +} + + +template +T* rtsFunction3D::GetBits() +{ + /*Returns bit data in lexocographical order (possibly for 3D texture mapping)*/ + return m_data; +} + +template +rtsFunction3D* rtsFunction3D::Resample(indextype newres_x, indextype newres_y, indextype newres_z) +{ + /*This function resamples the current function at the specified resolution. + No convolution is done for reducing he resolution. + */ + + rtsFunction3D* result = new rtsFunction3D(vector3D(newres_x, newres_y, newres_z), + m_boundary, m_domain_min, m_domain_max); + + //run through the entire resolution of the new function, sampling the current function + int x, y, z; + point3D parametric; + for(x = 0; xgetParameter(x, y, z); + (*result)(x, y, z) = ijk(parametric.x, parametric.y, parametric.z); + } + + return result; +} + +template +void rtsFunction3D::Scale(T new_min, T new_max) +{ + /*This function scales all values of the implicit function to within a specified range + */ + + //find the minimum and maximum values in this function + indextype data_size = m_resolution.x * m_resolution.y * m_resolution.z; + T min = m_data[0]; + T max = m_data[0]; + for(indextype i=0; i max) + max = m_data[i]; + } + + //scale all values to the specified range + T current_range = max - min; + T new_range = new_max - new_min; + for(indextype i=0; i +void rtsFunction3D::Crop(indextype x, indextype y, indextype z, + indextype size_x, indextype size_y, indextype size_z) +{ + /*This function crops the implicit function at the specified nodes + */ + //create a pointer for the new data + T* new_data = new T[size_x*size_y*size_z]; + + //blit from the old data to the new data + blit3D(m_data, + x, y, z, + m_resolution.x, m_resolution.y, m_resolution.z, + new_data, + 0, 0, 0, + size_x, size_y, size_z, + size_x, size_y, size_z); + + //change the shallow variables + vector3D new_resolution = vector3D(size_x, size_y, size_z); + vector3D voxel_size = getParameter(0,0,0) - getParameter(1,1,1); + point3D new_domain_min = getParameter(x, y, z) - 0.5*voxel_size; + point3D new_domain_max = getParameter(size_x-1, size_y - 1, size_z-1) + 0.5*voxel_size; + //copy new shallow variables + m_resolution = new_resolution; + m_domain_min = new_domain_min; + m_domain_max = new_domain_max; + + //copy data + delete m_data; + m_data = new_data; + +} + +template +void rtsFunction3D::Threshold(T min, T value) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min) + xyz(x, y, z) = value; + } +} + +template +void rtsFunction3D::Threshold(T min, T max, T value) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min && test_value <= max) + xyz(x, y, z) = value; + } +} + +template +void rtsFunction3D::Threshold(T min, T max, T inside, T outside) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min && test_value <= max) + xyz(x, y, z) = inside; + else + xyz(x, y, z) = outside; + } +} + +template +void rtsFunction3D::Insert(rtsFunction3D* source, indextype x, indextype y, indextype z) +{ + blit3D(source->m_data, 0, 0, 0, source->m_resolution.x, source->m_resolution.y, source->m_resolution.z, + m_data, x, y, z, m_resolution.x, m_resolution.y, m_resolution.z, + source->m_resolution.x, source->m_resolution.y, source->m_resolution.z); +} + + + + +template +void rtsFunction3D::Binary(T threshold, T true_value) +{ + /** + This function converts an implicit function into a binary or characteristic function describing the solid represented by the level + set at isovalue "threshold". All values below threshold are set to zero while all values above threshold are set to the specified + "true_value". In order to use this function, the data type T must be able to be set to 0. + **/ + int max_index = m_resolution.x * m_resolution.y * m_resolution.z; //find the size of the data array + int i; + for(i=0; i= threshold) + m_data[i] = true_value; + else + m_data[i] = 0; +} + + + +template +void rtsFunction3D::ClampMax(T max) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i max) + m_data[i] = max; +} + +template +void rtsFunction3D::ClampMin(T min) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i +T rtsFunction3D::getMin() +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + T current = m_data[0]; + for(i=1; i +T rtsFunction3D::getMax() +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + T current = m_data[0]; + for(i=1; i current) + current = m_data[i]; + return current; +} + + +template +void rtsFunction3D::toConsole() +{ + cout< +rtsFunction3D rtsFunction3D::Project2D() +{ + /** + This function projects the entire 3D function onto a 2D function along the z-axis. + **/ + rtsFunction3D result(m_resolution.x, m_resolution.y, 1); + result = 0; + + indextype x, y, z; + for(x = 0; x +#include +#include +#include +#include +#include + +#ifndef _USE_OLD_IOSTREAMS + +using namespace std; +#endif + +// maximum mumber of lines the output console should have + +static const WORD MAX_CONSOLE_LINES = 500; +//#ifdef _DEBUG + +void RedirectIOToConsole(int Xpos = 0, int Ypos = 0, int Width = 700, int Height = 400) +{ + int hConHandle; + long lStdHandle; + CONSOLE_SCREEN_BUFFER_INFO coninfo; + FILE *fp; + // allocate a console for this app + AllocConsole(); + // set the screen buffer to be big enough to let us scroll text + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); + coninfo.dwSize.Y = MAX_CONSOLE_LINES; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), + coninfo.dwSize); + // redirect unbuffered STDOUT to the console + lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stdout = *fp; + setvbuf( stdout, NULL, _IONBF, 0 ); + // redirect unbuffered STDIN to the console + lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "r" ); + *stdin = *fp; + setvbuf( stdin, NULL, _IONBF, 0 ); + + // redirect unbuffered STDERR to the console + lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stderr = *fp; + setvbuf( stderr, NULL, _IONBF, 0 ); + + // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog + // point to console as well + ios::sync_with_stdio(); + //position + MoveWindow(GetConsoleWindow(), Xpos, Ypos, Width, Height, true); +} + +#else +void RedirectIOToConsole(int Xpos = 0, int Ypos = 0, int Width = 700, int Height = 400) +{ +} +#endif + +#endif + +/* End of File */ \ No newline at end of file diff --git a/rtsGraph.h b/rtsGraph.h new file mode 100755 index 0000000..f18efea --- /dev/null +++ b/rtsGraph.h @@ -0,0 +1,142 @@ +#ifndef RTS_GRAPH_H +#define RTS_GRAPH_H + +#include +#include + +using namespace std; + +template +class rtsGraph +{ + unsigned int current_id; +public: + class rtsGraphNode; + typedef typename list::iterator rtsGraphNodePtr; + + class rtsGraphNode + { + public: + list ConnectionList; + unsigned int ID; + T Data; + }; + + list NodeList; + + rtsGraphNodePtr addNode(T data) + { + //Adds a node to the graph. This node is unconnected by default. + + //create the new node + rtsGraphNode new_node; + //set the data to the data provided + new_node.Data = data; + //set the id + new_node.ID = current_id++; + + //add the node to the node list + NodeList.push_back(new_node); + rtsGraphNodePtr result = NodeList.end(); + result--; + return result; + } + bool cmpPtr(const rtsGraphNodePtr a, const rtsGraphNodePtr b) + { + return (*a).ID < (*b).ID; + } + + void addConnection(rtsGraphNodePtr n0, rtsGraphNodePtr n1) + { + //adds a connection between two nodes + //connect n0 to n1 + (*n0).ConnectionList.push_back(n1); + (*n1).ConnectionList.push_back(n0); + + } + + void removeNode(rtsGraphNodePtr n) + { + + typename list::iterator i; + typename list::iterator j; + typename list::iterator temp; + rtsGraphNodePtr m; + rtsGraphNodePtr k; + /*Remove all of the connections TO n*/ + + //for each node m connected to n + for(i = (*n).ConnectionList.begin(); i != (*n).ConnectionList.end(); i++) + { + m = (*i); + //for each node k connected to m + j = (*m).ConnectionList.begin(); + while(j != (*m).ConnectionList.end()) + { + k = (*j); + //if k is the same as n, remove it + if(k == n) + { + temp = j; + j++; + (*m).ConnectionList.erase(temp); + } + else + j++; + + } + } + + /*Add all connections to neighboring nodes*/ + + //for each node m connected to n + for(i = (*n).ConnectionList.begin(); i != (*n).ConnectionList.end(); i++) + { + m = (*i); + //for each node k connected to n + for(j = (*n).ConnectionList.begin(); j != (*n).ConnectionList.end(); j++) + { + k = (*j); + if(k != m) + (*m).ConnectionList.push_back(k); + + } + //(*m).ConnectionList.sort(&rtsGraph::cmpPtr); + //sort((*m).ConnectionList.begin(), (*m).ConnectionList.end(), rtsGraph::cmpPtr); + (*m).ConnectionList.unique(); + } + + + + + + + + } + + + void PrintGraph() + { + rtsGraphNodePtr i; + typename list::iterator c; + for(i = NodeList.begin(); i != NodeList.end(); i++) + { + cout<<(*i).Data<<": "; + for(c = (*i).ConnectionList.begin(); c != (*i).ConnectionList.end(); c++) + { + if(c != (*i).ConnectionList.begin()) + cout<<"--"; + cout<<(*(*c)).Data; + } + cout< +#include +#include + +using namespace std; +using namespace cimg_library; + + +///This file contains a series of functions useful for loading images into other structures. These function use the CImg header file. + +void rts_cimgLoadImage(rtsFunction3D& result, const char* filename) /// image(filename), visu(500,400,1,3,0); + + result = rtsFunction3D(image.width, image.height, 1); + unsigned int x, y; + for(x=0; x& result, int z, const char* filename) +{ + CImg image(result.DimX(), result.DimY()); + unsigned int x, y; + for(x=0; x& result, const char* filename, unsigned int min, unsigned int max, unsigned int color = 0) +{ + /** + This function loads a sequence of images into a 3D implicit function. The filename is passed using the '?' wild + card. The wild cards are then replaced with the given min through max values in order to construct the names + for the image files to be loaded. The files are then loaded and placed in sequential order along the z-axis + of the implicit function. + **/ + string sequence_name = filename; //turn the filename into a string + unsigned int wild_card_begin = sequence_name.find_first_of('?'); //find the start and end indices of the wild card + unsigned int wild_card_end = sequence_name.find_last_of('?'); + + unsigned int max_number_length = wild_card_end - wild_card_begin + 1; //find the maximum number of characters in the image number + unsigned int max_number = (unsigned int)pow((double)10, (double)max_number_length) - 1; //find the maximum possible number + + //make sure that the data is given correctly + if(max < min) return; + if(max > max_number) max = max_number; + + //create an array of file names + int num_images = max - min + 1; //compute the number of images + bool implicit_created = false; + for(int i=0; i image(file_name.c_str()); //load the frame + if(implicit_created == false) //create the implicit function for the first frame + { + result = rtsFunction3D(image.width, image.height, num_images); + implicit_created = true; + } + + //place the frame in the implicit function + unsigned int x, y; + for(x=0; x& result, const char* filename) +{ + string sequence_name = filename; //turn the filename into a string + unsigned int wild_card_begin = sequence_name.find_first_of('?'); //find the start and end indices of the wild card + unsigned int wild_card_end = sequence_name.find_last_of('?'); + + unsigned int max_number_length = wild_card_end - wild_card_begin + 1; //find the maximum number of characters in the image number + unsigned int max_number = (unsigned int)pow((double)10, (double)max_number_length) - 1; //find the maximum possible number + + //make sure that the data is given correctly + unsigned int max = result.DimZ(); + if(max > max_number) max = max_number; + + //save each individual file + int num_images = max; //compute the number of images + CImg image(result.DimX(), result.DimY()); //create an image for saving + for(int i=0; i source, unsigned int z) +{ + CImg image(source.DimX(), source.DimY()); + + int x, y; + for(x=0; x +#include +#include +#include +#include +using namespace std; + +typedef int indextype; + +///This class represents a 3D implicit function as a grid. It provides methods for accessing values, interpolation, and several utilities. + +template class rtsImplicit3D +{ +private: + //pointer to store the data + T* m_data; + //resolution of the data (x, y, z) dimensional extents + vector3D m_resolution; + T m_boundary; //boundary condition + point3D m_domain_min; //min and max range values (used for parametric access) + point3D m_domain_max; + vector3D m_voxel_size; + + //bit-blit function copies 3D data quickly from source to dest + void blit3D(const T* source, + indextype s_px, indextype s_py, indextype s_pz, + indextype s_sx, indextype s_sy, indextype s_sz, + T* dest, + indextype d_px, indextype d_py, indextype d_pz, + indextype d_sx, indextype d_sy, indextype d_sz, + indextype blit_size_x, indextype blit_size_y, indextype blit_size_z); + + void shallow_copy(const rtsImplicit3D source, rtsImplicit3D &dest); + inline point3D getParameter(indextype i); + + inline float isosurface_distance(point3D p0, point3D p1, T isovalue); + inline float manhattan_distance(rtsImplicit3D* function, point3D p, bool sdf = false); + void compute_distance_function_boundary(T isovalue, rtsImplicit3D* &result, rtsImplicit3D* &mask, bool sdf = false); + + +public: + //construct an implicit function with a size of 1 + rtsImplicit3D(); /// resolution, T boundary, point3D min_domain, point3D max_domain); + //full copy constructor, defines all variables + rtsImplicit3D(T* data, vector3D resolution, T boundary, point3D min_domain, point3D max_domain); + rtsImplicit3D(const rtsImplicit3D &original); //copy constructor + ~rtsImplicit3D(); //destructor + + //overloaded operators + rtsImplicit3D& operator=(const rtsImplicit3D& original); ///& operator=(const T constant); ///& operator*=(const T constant); ///& operator+=(const T constant); ///& operator-=(const T constant); ///& operator/=(const T constant); /// operator+(const T constant); /// operator-(const T constant); /// operator*(const T constant); /// operator/(const T constant); /// friend class rtsImplicit3D; + template operator rtsImplicit3D(); /// operator*(const T lhs, rtsImplicit3D rhs){return rhs*lhs;} /// operator+(const T lhs, rtsImplicit3D rhs){return rhs+lhs;} /// operator-(const T lhs, rtsImplicit3D rhs) /// result; + rhs.shallow_copy(rhs, result); //make a copy of all of the shallow variables and allocate memory + indextype size = rhs.m_resolution.x * rhs.m_resolution.y * rhs.m_resolution.z; + //iterate and subtract + for(indextype i=0; i operator/(const T lhs, rtsImplicit3D rhs); + + //loading/saving data to disk + void LoadRAW(indextype header_size, indextype data_x, indextype data_y, indextype data_z, const char* filename); /// getParameter(indextype x, indextype y, indextype z); + inline point3D getNearestIndex(double i, double j, double k); + inline point3D getFractionalIndex(double i, double j, double k); + inline point3D getNearestIndex(indextype i); + point3D getMinDomain(){return m_domain_min;} + point3D getMaxDomain(){return m_domain_max;} + vector> getEdgeNodes(T isovalue, bool protrusions = true); /// Project2D(); //* dt_grid, double factor, indextype x, indextype y, indextype z); + void Insert(rtsImplicit3D* source, indextype x, indextype y, indextype z); + + //data massaging + + void Scale(T min, T max); + void Crop(indextype x, indextype y, indextype z, indextype size_x, indextype size_y, indextype size_z); + void Binary(T threshold, T true_value); ///* Resample(indextype newres_x, indextype newres_y, indextype newres_z); + rtsImplicit3D* Isodistance_Manhattan(T isovalue, bool sdf = false); + rtsImplicit3D>* Gradient(); + rtsImplicit3D* EstimateAmbient(T threshold); + rtsImplicit3D* EstimateAttenuatedAmbient(T surface, T transparent, float attenuation); + + //implicit shapes + //(these functions create some basic implicit shapes just for fun) + void Sphere(double center_i, double center_j, double center_k, double radius, T in_value); + + //output functions + void toConsole(); + +}; + +template +void rtsImplicit3D::blit3D(const T* source, + indextype s_px, indextype s_py, indextype s_pz, + indextype s_sx, indextype s_sy, indextype s_sz, + T* dest, + indextype d_px, indextype d_py, indextype d_pz, + indextype d_sx, indextype d_sy, indextype d_sz, + indextype blit_size_x, indextype blit_size_y, indextype blit_size_z) +{ + indextype ps, pd; //stores the mapping for the source point to the dest point + //find the maximum points that can be blit to (in case source overlaps the edges of dest) + blit_size_x = min(blit_size_x, min(s_sx - s_px, d_sx - d_px)); + blit_size_y = min(blit_size_y, min(s_sy - s_py, d_sy - d_py)); + blit_size_z = min(blit_size_z, min(s_sz - s_pz, d_sz - d_pz)); + + indextype source_z_offset = s_sx * s_sy; + indextype dest_z_offset = d_sx * d_sy; + + indextype z,y; + for(z=0; z +void rtsImplicit3D::shallow_copy(const rtsImplicit3D source, rtsImplicit3D &dest) +{ + dest = rtsImplicit3D(source.m_resolution.x, source.m_resolution.y, source.m_resolution.z); + dest.m_boundary = source.m_boundary; + dest.m_domain_max = source.m_domain_max; + dest.m_domain_min = source.m_domain_max; + dest.m_voxel_size = source.m_voxel_size; +} + +template +rtsImplicit3D::rtsImplicit3D(vector3D resolution, T boundary, point3D domain_min, point3D domain_max) +{ + //This function creates an implicit function based on all of the shallow variables + m_resolution = resolution; + m_boundary = boundary; + m_domain_min = domain_min; + m_domain_max = domain_max; + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; + + //allocate the data + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; +} + +template +rtsImplicit3D::rtsImplicit3D(T* data, vector3D resolution, T boundary, point3D domain_min, point3D domain_max) +{ + //This function creates an implicit function based on ALL of the variables + m_resolution = resolution; + m_boundary = boundary; + m_domain_min = domain_min; + m_domain_max = domain_max; + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; + + //allocate the data + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + m_data = new T[size]; + memcpy(m_data, data, sizeof(T)*size); + //for(int i=0; i +rtsImplicit3D::rtsImplicit3D() +{ + m_resolution.x = 1; + m_resolution.y = 1; + m_resolution.z = 1; + m_data = new T[1]; + //m_boundary = 0; //initialize boundary condition + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + m_voxel_size = vector3D(1.0, 1.0, 1.0); +} + +template +rtsImplicit3D::rtsImplicit3D(indextype res_x, indextype res_y, indextype res_z) +{ + m_resolution.x = res_x; //set resolution vector + m_resolution.y = res_y; + m_resolution.z = res_z; + m_data = new T[res_x*res_y*res_z]; //allocate data + memset(&m_boundary, 0, sizeof(T)); //initialize boundary condition + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +rtsImplicit3D::rtsImplicit3D(T* data, indextype res_x, indextype res_y, indextype res_z) +{ + m_resolution.x = res_x; //set resolution vector + m_resolution.y = res_y; + m_resolution.z = res_z; + m_data = new T[res_x*res_y*res_z]; //allocate data + //copy the sample data into the data array + indextype size = res_x*res_y*res_z; + for(indextype i=0; i(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +rtsImplicit3D::rtsImplicit3D(const rtsImplicit3D& original) +{ + //copy the shallow variables + m_resolution = original.m_resolution; + m_boundary = original.m_boundary; + m_domain_min = original.m_domain_min; + m_domain_max = original.m_domain_max; + m_voxel_size = original.m_voxel_size; + + //allocate space for the data + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; + //copy the data + blit3D(original.m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_resolution.x, m_resolution.y, m_resolution.z); +} + +template +rtsImplicit3D::~rtsImplicit3D() +{ + delete m_data; +} + +template +typename rtsImplicit3D& rtsImplicit3D::operator=(const T rhs) +{ + indextype size = m_resolution.x*m_resolution.y*m_resolution.z; + for(int i=0; i +typename rtsImplicit3D& rtsImplicit3D::operator=(const rtsImplicit3D& rhs) +{ + //check for self-assignment + if(this == &rhs) + return *this; + + //deallocate memory + if(m_data != NULL) + delete m_data; + + //copy the shallow variables + m_resolution = rhs.m_resolution; + m_boundary = rhs.m_boundary; + m_domain_min = rhs.m_domain_min; + m_domain_max = rhs.m_domain_max; + m_voxel_size = rhs.m_voxel_size; + + //allocate and copy memory + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; + //copy the data + blit3D(rhs.m_data, + 0,0,0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_resolution.x, m_resolution.y, m_resolution.z); + + //return the left hand side + return *this; +} + +template +inline T& rtsImplicit3D::operator ()(indextype x, indextype y, indextype z) +{ + return xyz(x, y, z); +} + +template +inline T rtsImplicit3D::operator()(double i, double j, double k) +{ + return ijk(i, j, k); +} + +template +rtsImplicit3D& rtsImplicit3D::operator *=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsImplicit3D& rtsImplicit3D::operator +=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsImplicit3D& rtsImplicit3D::operator -=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsImplicit3D& rtsImplicit3D::operator /=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +const rtsImplicit3D rtsImplicit3D::operator *(const T constant) +{ + rtsImplicit3D result = (*this); + result *= constant; + + return result; +} + +template +const rtsImplicit3D rtsImplicit3D::operator +(const T constant) +{ + rtsImplicit3D result = (*this); + result += constant; + + return result; +} + +template +const rtsImplicit3D rtsImplicit3D::operator -(const T constant) +{ + rtsImplicit3D result = (*this); + result -= constant; + + return result; +} + +template +const rtsImplicit3D rtsImplicit3D::operator /(const T constant) +{ + rtsImplicit3D result = (*this); + result /= constant; + + return result; +} + +template +template +rtsImplicit3D::operator rtsImplicit3D() +{ + //cast one type to another + //create the data pointer from the current function + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + U* new_data = new U[size]; + for(int i=0; i cast_result(new_data, m_resolution, m_boundary, m_domain_min, m_domain_max); + + return cast_result; +} + +template +inline T& rtsImplicit3D::xyz(indextype x, indextype y, indextype z) +{ + if(x<0 || y<0 || z<0 || x>=m_resolution.x || y>=m_resolution.y || z>=m_resolution.z) + return m_boundary; + //return m_data[(z * m_resolution.x * m_resolution.y) + (y * m_resolution.x) + x]; + return m_data[x + m_resolution.x * (y + z * m_resolution.y)]; + +} + +template +inline point3D rtsImplicit3D::getNearestIndex(indextype i) +{ + point3D result; + result.z = i/(m_resolution.x*m_resolution.y); + indextype mod = i%(m_resolution.x*m_resolution.y); + result.y = mod/m_resolution.x; + result.x = mod%m_resolution.x; + + return result; + +} + +template +void rtsImplicit3D::LoadRAW(indextype header_size, indextype size_x, + indextype size_y, indextype size_z, const char *filename) +{ + //set the data size + m_resolution = vector3D(size_x, size_y, size_z); + //delete any previous data + if(m_data != NULL) + delete m_data; + + ifstream infile(filename, ios::in | ios::binary); + + //load the header + unsigned char* header = new unsigned char[header_size]; + infile.read((char*)header, header_size); + + //load the actual data + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + m_data = new T[size]; + infile.read((char*)m_data, size*sizeof(T)); + + //calculate min and maxes + infile.close(); +} + +template +void rtsImplicit3D::LoadVOL(const char *filename) +{ + ifstream infile(filename, ios::in | ios::binary); //create the files stream + if(!infile) + return; + + indextype size_x, size_y, size_z; //create variables to store the size of the data set + //load the dimensions of the data set + infile.read((char*)&size_x, sizeof(int)); //load the file header + infile.read((char*)&size_y, sizeof(int)); + infile.read((char*)&size_z, sizeof(int)); + + //close the file + infile.close(); + //load the raw data + LoadRAW(12, size_x, size_y, size_z, filename); +} + +template +void rtsImplicit3D::SaveVOL(const char *filename) +{ + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume size to the file + vector3D vol_size = m_resolution; + outfile.write((char*)&vol_size.x, sizeof(int)); + outfile.write((char*)&vol_size.y, sizeof(int)); + outfile.write((char*)&vol_size.z, sizeof(int)); + + outfile.write((char*)m_data, sizeof(char)*vol_size.x*vol_size.y*vol_size.z); +} + +template +void rtsImplicit3D::SaveRAW(const char *filename) +{ + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume data + outfile.write((char*)m_data, sizeof(T)*m_resolution.x*m_resolution.y*m_resolution.z); +} + +template +inline T rtsImplicit3D::ijk(double i, double j, double k) +{ + /*This function determines the value at the specified parametric points + defined by the m_domain_min and m_domain_max parameter values.*/ + + //if the parameter is outside the range, return the boundary value + if(im_domain_max.x || j>m_domain_max.y || k>m_domain_max.z) + return m_boundary; + + point3D index = getFractionalIndex(i, j, k); + + //cout< +void rtsImplicit3D::Parameterize(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) +{ + m_domain_min = point3D(x_min, y_min, z_min); + m_domain_max = point3D(x_max, y_max, z_max); + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +inline point3D rtsImplicit3D::getParameter(indextype x, indextype y, indextype z) +{ + //get the value between 0 and 1 + point3D normalized((double)x / (double)(m_resolution.x) + (1.0/(m_resolution.x*2.0)), + (double)y / (double)(m_resolution.y) + (1.0/(m_resolution.y*2.0)), + (double)z/(double)(m_resolution.z) + (1.0/(m_resolution.z*2.0))); + + point3D result(normalized.x * (m_domain_max.x - m_domain_min.x) + m_domain_min.x, + normalized.y * (m_domain_max.y - m_domain_min.y) + m_domain_min.y, + normalized.z * (m_domain_max.z - m_domain_min.z) + m_domain_min.z); + + return result; +} + +template +inline point3D rtsImplicit3D::getNearestIndex(double i, double j, double k) +{ + //this function returns the index of the voxel containing the specified parameter point + point3D normalized((i - m_domain_min.x)/(m_domain_max.x-m_domain_min.x), + (j - m_domain_min.y)/(m_domain_max.y-m_domain_min.y), + (k - m_domain_min.z)/(m_domain_max.z-m_domain_min.z)); + + point3D result((normalized.x - (1.0/(m_resolution.x*2.0)))*(double)m_resolution.x+0.5, + (normalized.y - (1.0/(m_resolution.y*2.0)))*(double)m_resolution.y+0.5, + (normalized.z - (1.0/(m_resolution.z*2.0)))*(double)m_resolution.z+0.5); + + return result; +} + +template +inline point3D rtsImplicit3D::getFractionalIndex(double i, double j, double k) +{ + //this function returns the index of the voxel containing the specified parameter point + point3D normalized((i - m_domain_min.x)/(m_domain_max.x-m_domain_min.x), + (j - m_domain_min.y)/(m_domain_max.y-m_domain_min.y), + (k - m_domain_min.z)/(m_domain_max.z-m_domain_min.z)); + + point3D result((normalized.x - (1.0/(m_resolution.x*2.0)))*(double)m_resolution.x, + (normalized.y - (1.0/(m_resolution.y*2.0)))*(double)m_resolution.y, + (normalized.z - (1.0/(m_resolution.z*2.0)))*(double)m_resolution.z); + return result; +} + + +template +T* rtsImplicit3D::GetBits() +{ + /*Returns bit data in lexocographical order (possibly for 3D texture mapping)*/ + return m_data; +} + +template +rtsImplicit3D* rtsImplicit3D::Resample(indextype newres_x, indextype newres_y, indextype newres_z) +{ + /*This function resamples the current function at the specified resolution. + No convolution is done for reducing he resolution. + */ + + rtsImplicit3D* result = new rtsImplicit3D(vector3D(newres_x, newres_y, newres_z), + m_boundary, m_domain_min, m_domain_max); + + //run through the entire resolution of the new function, sampling the current function + int x, y, z; + point3D parametric; + for(x = 0; xgetParameter(x, y, z); + (*result)(x, y, z) = ijk(parametric.x, parametric.y, parametric.z); + } + + return result; +} + +template +void rtsImplicit3D::Scale(T new_min, T new_max) +{ + /*This function scales all values of the implicit function to within a specified range + */ + + //find the minimum and maximum values in this function + indextype data_size = m_resolution.x * m_resolution.y * m_resolution.z; + T min = m_data[0]; + T max = m_data[0]; + for(indextype i=0; i max) + max = m_data[i]; + } + + //scale all values to the specified range + T current_range = max - min; + T new_range = new_max - new_min; + for(indextype i=0; i +void rtsImplicit3D::Crop(indextype x, indextype y, indextype z, + indextype size_x, indextype size_y, indextype size_z) +{ + /*This function crops the implicit function at the specified nodes + */ + //create a pointer for the new data + T* new_data = new T[size_x*size_y*size_z]; + + //blit from the old data to the new data + blit3D(m_data, + x, y, z, + m_resolution.x, m_resolution.y, m_resolution.z, + new_data, + 0, 0, 0, + size_x, size_y, size_z, + size_x, size_y, size_z); + + //change the shallow variables + vector3D new_resolution = vector3D(size_x, size_y, size_z); + vector3D voxel_size = getParameter(0,0,0) - getParameter(1,1,1); + point3D new_domain_min = getParameter(x, y, z) - 0.5*voxel_size; + point3D new_domain_max = getParameter(size_x-1, size_y - 1, size_z-1) + 0.5*voxel_size; + //copy new shallow variables + m_resolution = new_resolution; + m_domain_min = new_domain_min; + m_domain_max = new_domain_max; + + //copy data + delete m_data; + m_data = new_data; + +} + +template +void rtsImplicit3D::Threshold(T min, T value) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min) + xyz(x, y, z) = value; + } +} + +template +void rtsImplicit3D::Threshold(T min, T max, T value) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min && test_value <= max) + xyz(x, y, z) = value; + } +} + +template +void rtsImplicit3D::Threshold(T min, T max, T inside, T outside) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min && test_value <= max) + xyz(x, y, z) = inside; + else + xyz(x, y, z) = outside; + } +} + +template +void rtsImplicit3D::Insert(rtsDTGrid3D* dt_grid, double factor, indextype pos_x, indextype pos_y, indextype pos_z) +{ +/* This function copies a 3D DT-Grid into the implicit function at the specified position. +*/ + rtsDTGrid3D::iterator i; + indextype x, y, z; + for(i=dt_grid->begin(); i != dt_grid->end(); i.increment()) //for each node in the grid + { + x = pos_x + i.getX(); + y = pos_y + i.getY(); + z = pos_z + i.getZ(); + if(x >= 0 || x < m_resolution.x || + y >= 0 || y < m_resolution.y || + y >= 0 || y < m_resolution.z) + xyz(x, y, z) = max(i.value* factor, (double)xyz(x, y, z)); + } +} + +template +void rtsImplicit3D::Insert(rtsImplicit3D* source, indextype x, indextype y, indextype z) +{ + blit3D(source->m_data, 0, 0, 0, source->m_resolution.x, source->m_resolution.y, source->m_resolution.z, + m_data, x, y, z, m_resolution.x, m_resolution.y, m_resolution.z, + source->m_resolution.x, source->m_resolution.y, source->m_resolution.z); +} + + +template +inline float rtsImplicit3D::manhattan_distance(rtsImplicit3D* function, point3D point, bool sdf) +{ + /*This function updates the manhattan distance from a surface using the manhattan + distance of its neighboring points. + */ + indextype x, y, z; + x=point.x; y=point.y, z=point.z; + int sign = 1; + float result = DIST_MAX; + float near_value; //the value of the neighbor being considered + float possible_value; + if(x!=0) + { + near_value = (*function)(x-1, y, z); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.x); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.x); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + + } + if(x!=function->DimX()-1) + { + near_value = (*function)(x+1, y, z); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.x); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.x); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(y!=0) + { + near_value = (*function)(x, y-1, z); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.y); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.y); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(y!=function->DimY()-1) + { + near_value = (*function)(x, y+1, z); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.y); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.y); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(z!=0) + { + near_value = (*function)(x, y, z-1); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.z); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.z); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(z!=function->DimZ()-1) + { + near_value = (*function)(x, y, z+1); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.z); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.z); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + return result; +} + +template +inline float rtsImplicit3D::isosurface_distance(point3D p0, point3D p1, T isovalue) +{ + /*This function computes the distance from p0 to the surface, given two points p0 and p1 + on either side of the surface. isovalue specifies + the value at the surface. Right now, this function returns a float. I'll have to think + of something better to do in the future. + */ + + //compute the normalized position of the surface between p0 and p1 + float val0 = ijk(p0.x, p0.y, p0.z); + float val1 = ijk(p1.x, p1.y, p1.z); + float isovalue_norm_pos = (isovalue - val0) / (val1 - val0); + //compute the actual position of the surface + point3D s_pos = p0 + isovalue_norm_pos * (p1 - p0); + //compute the distance from p0 to the surface + float result = (s_pos - p0).Length(); + //cout<<"distance: "< +void rtsImplicit3D::compute_distance_function_boundary(T isovalue, + rtsImplicit3D* &result, + rtsImplicit3D* &mask, bool sdf) +{ + /*This function creates an initial signed distance function from a threshold image. + All voxels adjacent to the surface specified by the threshold are initialized with a + distance value. Low values are inside, high values are outside. + */ + //current and neighboring voxel flags (false = inside, true = outside) + bool c, x_p, x_n, y_p, y_n, z_p, z_n; + float d_xp, d_xn, d_yp, d_yn, d_zp, d_zn; + float in_out = 1; + + //boundary condition function and the mask + result = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); + //get the parameterization + result->Parameterize(m_domain_min.x, m_domain_max.x, m_domain_min.y, m_domain_max.y, m_domain_min.z, m_domain_max.z); + (*result) = DIST_MAX; + result->setBoundary(DIST_MAX); + //create a mask + mask = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); + (*mask) = false; + + cout<<"done making boundary condition function"<= m_resolution.x) x_p = c; + else if(xyz(x+1, y, z) < isovalue) x_p = false; + if(y-1 < 0) y_n = c; //Y + else if(xyz(x, y-1, z) < isovalue) y_n = false; + if(y+1 >= m_resolution.y) y_p = c; + else if(xyz(x, y+1, z) < isovalue) y_p = false; + if(z-1 < 0) z_n = c; //Z + else if(xyz(x, y, z-1) < isovalue) z_n = false; + if(z+1 >= m_resolution.z) z_p = c; + else if(xyz(x, y, z+1) < isovalue) z_p = false; + + //set the distance from the isosurface + if(c == false && sdf) + in_out = -1.0; + if(x_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x-1, y, z), + isovalue) * in_out); + if(x_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x+1, y, z), + isovalue) * in_out); + if(y_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x, y-1, z), + isovalue) * in_out); + if(y_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x, y+1, z), + isovalue) * in_out); + if(z_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z-1), + getParameter(x, y, z), + isovalue) * in_out); + if(z_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x, y, z+1), + isovalue) * in_out); + + //set the mask to 1 if the voxel is on an edge node + if(x_n != c || x_p != c || y_n != c || y_p != c || z_n != c || z_p != c) + (*mask)(x, y, z) = true; + } + + + //if a line between the two voxels crosses the surface + //find the distance between the voxel center and the surface + + + cout<<"done computing boundary conditions"< +rtsImplicit3D* rtsImplicit3D::EstimateAmbient(T threshold) +{ + rtsImplicit3D* result = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); //create a new implicit function + (*result) = 0.0f; + rtsImplicit3D* temp = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); //temp buffer for current lighting iteration + (*temp) = 0.0f; + temp->setBoundary(1.0); + + cout<<"first iteration..."< 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; z--) + { + ambient = 0.0; + if(xyz(x-1, y, z) < threshold) + ambient += (*temp)(x-1, y, z); + if(xyz(x, y-1, z) < threshold) + ambient += (*temp)(x, y-1, z); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; y--) + for(z=0; z 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + { + ambient = 0.0; + if(xyz(x-1, y, z) < threshold) + ambient += (*temp)(x-1, y, z); + if(xyz(x, y+1, z) < threshold) + ambient += (*temp)(x, y+1, z); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=0; y 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=0; y=0; z--) + { + ambient = 0.0; + if(xyz(x+1, y, z) < threshold) + ambient += (*temp)(x+1, y, z); + if(xyz(x, y-1, z) < threshold) + ambient += (*temp)(x, y-1, z); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=0; z 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + { + ambient = 0.0; + if(xyz(x+1, y, z) < threshold) + ambient += (*temp)(x+1, y, z); + if(xyz(x, y+1, z) < threshold) + ambient += (*temp)(x, y+1, z); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."< +rtsImplicit3D* rtsImplicit3D::EstimateAttenuatedAmbient(T threshold, T transparent, float attenuation) +{ + rtsImplicit3D* result = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); //create a new implicit function + (*result) = 0.0f; + rtsImplicit3D* temp = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); //temp buffer for current lighting iteration + (*temp) = 0.0f; + temp->setBoundary(1.0); + + cout<<"first iteration..."< 3.0) + // cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; z--) + { + ambient = 0.0; + if(xyz(x-1, y, z) < threshold) + ambient += (*temp)(x-1, y, z)*(1.0 - (xyz(x-1, y, z)/255.0)*attenuation); + if(xyz(x, y-1, z) < threshold) + ambient += (*temp)(x, y-1, z)*(1.0 - (xyz(x, y-1, z)/255.0)*attenuation); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1)*(1.0 - (xyz(x, y, z+1)/255.0)*attenuation); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; y--) + for(z=0; z 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + { + ambient = 0.0; + if(xyz(x-1, y, z) < threshold) + ambient += (*temp)(x-1, y, z)*(1.0 - (xyz(x-1, y, z)/255.0)*attenuation); + if(xyz(x, y+1, z) < threshold) + ambient += (*temp)(x, y+1, z)*(1.0 - (xyz(x, y+1, z)/255.0)*attenuation); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1)*(1.0 - (xyz(x, y, z+1)/255.0)*attenuation); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=0; y 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=0; y=0; z--) + { + ambient = 0.0; + if(xyz(x+1, y, z) < threshold) + ambient += (*temp)(x+1, y, z)*(1.0 - (xyz(x+1, y, z)/255.0)*attenuation); + if(xyz(x, y-1, z) < threshold) + ambient += (*temp)(x, y-1, z)*(1.0 - (xyz(x, y-1, z)/255.0)*attenuation); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1)*(1.0 - (xyz(x, y, z+1)/255.0)*attenuation); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=0; z 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + { + ambient = 0.0; + if(xyz(x+1, y, z) < threshold) + ambient += (*temp)(x+1, y, z)*(1.0 - (xyz(x+1, y, z)/255.0)*attenuation); + if(xyz(x, y+1, z) < threshold) + ambient += (*temp)(x, y+1, z)*(1.0 - (xyz(x, y+1, z)/255.0)*attenuation); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1)*(1.0 - (xyz(x, y, z+1)/255.0)*attenuation); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."< +rtsImplicit3D* rtsImplicit3D::Isodistance_Manhattan(T isovalue, bool sdf) +{ + rtsImplicit3D* function; + rtsImplicit3D* mask; + compute_distance_function_boundary(isovalue, function, mask, sdf); + + //compute the manhattan distance for the entire function + //use fast sweeping to compute the manhattan distance + //0:X 0:Y 0:Z + cout<<"first iteration..."<(x, y, z), sdf); + cout<<"done."<=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = manhattan_distance(function, point3D(x, y, z), sdf); + cout<<"done."<=0; y--) + for(z=0; z(x, y, z), sdf); + cout<<"done."<=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = manhattan_distance(function, point3D(x, y, z), sdf); + cout<<"done."<=0; x--) + for(y=0; y(x, y, z), sdf); + cout<<"done."<=0; x--) + for(y=0; y=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = manhattan_distance(function, point3D(x, y, z), sdf); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=0; z(x, y, z), sdf); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = manhattan_distance(function, point3D(x, y, z), sdf); + cout<<"done."< +rtsImplicit3D>* rtsImplicit3D::Gradient() +{ + int x, y, z; + rtsImplicit3D>* result = new rtsImplicit3D>(m_resolution.x, m_resolution.y, m_resolution.z); + for(x=0; xxyz(x, y, z).x = xyz(x-1, y, z) - xyz(x, y, z); + result->xyz(x, y, z).y = xyz(x, y-1, z) - xyz(x, y, z); + result->xyz(x, y, z).z = xyz(x, y, z-1) - xyz(x, y, z); + } + return result; +} + + +template +int rtsImplicit3D::Neighbors26(indextype x, indextype y, indextype z, T isovalue) +{ + int neighbors = 0; + int u,v,w; + + for(u=-1; u<=1; u++) + for(v=-1; v<=1; v++) + for(w=-1; w<=1; w++) + if(xyz(x+u, y+v, z+w) >= isovalue) + neighbors++; + if(xyz(x, y, z) > isovalue) + neighbors--; + + return neighbors; +} + +template +unsigned int rtsImplicit3D::Neighbors6(indextype x, indextype y, indextype z, T threshold) +{ + + unsigned int neighbors = 0; + if(xyz(x+1, y, z) >= threshold) + neighbors++; + if(xyz(x-1, y, z) >= threshold) + neighbors++; + if(xyz(x, y+1, z) >= threshold) + neighbors++; + if(xyz(x, y-1, z) >= threshold) + neighbors++; + if(xyz(x, y, z+1) >= threshold) + neighbors++; + if(xyz(x, y, z-1) >= threshold) + neighbors++; + + return neighbors; +} + +template +bool rtsImplicit3D::TestTopology(T isovalue, unsigned int x, unsigned int y, unsigned int z) +{ + if(xyz(x,y,z) < isovalue) + return false; + //This function returns true if a voxel is necessary, otherwise it returns false + unsigned int neighbors = Neighbors(x, y, z, isovalue); + + if(neighbors == 3) + return false; + if(neighbors == 0 || neighbors == 1 || neighbors == 4) + return true; + if(neighbors == 2) + { + if(xyz(x-1, y, z) >= isovalue && xyz(x+1, y, z) >= isovalue) + return true; + if(xyz(x, y-1, z) >= isovalue && xyz(x, y+1, z) >= isovalue) + return true; + return false; + } + +} + +template +void rtsImplicit3D::FloodFill6(indextype x, indextype y, indextype z, T target_value) +{ + T old_value = xyz(x, y, z); //find the old value (the value being flood-filled) + if(target_value == old_value) //if the target value is the same as the old value, nothing to do + return; + + queue> Q; //create a queue for neighboring points + point3D current(x, y, z); //start with the current point + xyz(current.x, current.y, current.z) = target_value; + point3D next; + Q.push(current); + indextype u, v, w; + + while(!Q.empty()) //continue until the queue is empty + { + current = Q.front(); //get the first element from the queue + Q.pop(); + + if(current.x != m_resolution.x - 1) + if(xyz(current.x + 1, current.y, current.z) == old_value) + { + xyz(current.x + 1, current.y, current.z) = target_value; + Q.push(point3D(current.x + 1, current.y, current.z)); + } + if(current.x != 0) + if(xyz(current.x - 1, current.y, current.z) == old_value) + { + xyz(current.x - 1, current.y, current.z) = target_value; + Q.push(point3D(current.x - 1, current.y, current.z)); + } + if(current.y != m_resolution.y - 1) + if(xyz(current.x, current.y +1, current.z) == old_value) + { + xyz(current.x, current.y+1, current.z) = target_value; + Q.push(point3D(current.x, current.y+1, current.z)); + } + if(current.y != 0) + if(xyz(current.x, current.y-1, current.z) == old_value) + { + xyz(current.x, current.y-1, current.z) = target_value; + Q.push(point3D(current.x, current.y-1, current.z)); + } + if(current.z != m_resolution.z - 1) + if(xyz(current.x, current.y, current.z+1) == old_value) + { + xyz(current.x, current.y, current.z+1) = target_value; + Q.push(point3D(current.x, current.y, current.z+1)); + } + if(current.z != 0) + if(xyz(current.x, current.y, current.z-1) == old_value) + { + xyz(current.x, current.y, current.z-1) = target_value; + Q.push(point3D(current.x, current.y, current.z-1)); + } + + } + +} + +template +void rtsImplicit3D::FloodFill26(int x, int y, int z, T target_value) +{ + T old_value = xyz(x, y, z); + if(target_value == old_value) + return; + + queue> Q; + point3D current(x, y, z); + point3D next; + Q.push(current); + indextype u, v, w; + while(!Q.empty()) + { + current = Q.front(); + if(xyz(current.x, current.y, current.z) == old_value) + xyz(current.x, current.y, current.z) = target_value; + Q.pop(); + for(u=-1; u<=1; u++) + for(v=-1; v<=1; v++) + for(w=-1; w<=1; w++) + { + next.x = current.x + u; + next.y = current.y + v; + next.z = current.z + w; + + if(next.x >= 0 && next.x < m_resolution.x && + next.y >= 0 && next.y < m_resolution.y && + next.z >= 0 && next.z < m_resolution.z && + xyz(next.x, next.y, next.z) == old_value) + { + xyz(next.x, next.y, next.z) = target_value; + Q.push(next); + } + } + } + + +} + +template +void rtsImplicit3D::Binary(T threshold, T true_value) +{ + /** + This function converts an implicit function into a binary or characteristic function describing the solid represented by the level + set at isovalue "threshold". All values below threshold are set to zero while all values above threshold are set to the specified + "true_value". In order to use this function, the data type T must be able to be set to 0. + **/ + int max_index = m_resolution.x * m_resolution.y * m_resolution.z; //find the size of the data array + int i; + for(i=0; i= threshold) + m_data[i] = true_value; + else + m_data[i] = 0; +} + +template +vector> rtsImplicit3D::getEdgeNodes(T isovalue, bool protrusions = true) +{ + vector> result; + indextype x, y, z; + int neighbors; + for(x=0; x= isovalue) + { + neighbors = Neighbors26(x, y, z, isovalue); + if(protrusions == false && neighbors < 1) + continue; + if(neighbors < 26) + result.push_back(point3D(x, y, z)); + } + } + + return result; + +} + +template +unsigned int rtsImplicit3D::BackgroundComponents6(indextype x, indextype y, indextype z, T threshold, int n = 18) +{ + /** + This function computes the number of 6-connected background components in the local region of (x, y, z). + This computation is performed by testing all 6 possible voxels that can connect to the specified node. If + a background node is found, the entire background component associated with that node is filled and the counter + is incremented by 1. The value n specifies the connectivity domain for the flood fill. + The definition of background components is that specified by He, Kischell, Rioult and Holmes. + **/ + + //see if there is at least one BG component + if(Neighbors6(x, y, z, threshold) == 6) + return 0; + + + //retrieve the local region of the function + rtsImplicit3D local(3, 3, 3); + point3D corner(x-1, y-1, z-1); + indextype u, v, w; + for(u=0; u<3; u++) + for(v=0; v<3; v++) + for(w=0; w<3; w++) + local(u, v, w) = xyz(corner.x + u, corner.y + v, corner.z + w); + + //threshold the background to find inside/outside points + local.Binary(threshold, 1); + //fill points that are not in the connectivity domain + if(n == 18) + { + local(0, 0, 0) = 1; + local(0, 0, 2) = 1; + local(0, 2, 0) = 1; + local(0, 2, 2) = 1; + local(2, 0, 0) = 1; + local(2, 0, 2) = 1; + local(2, 2, 0) = 1; + local(2, 2, 2) = 1; + } + //local.toConsole(); + + //search all 6 possible connected points. If a background node is found, fill the component + unsigned int components = 0; + if(local(0, 1, 1) == 0) + { + components++; + local.FloodFill6(0, 1, 1, 1); + } + if(local(2, 1, 1) == 0) + { + components++; + local.FloodFill6(2, 1, 1, 1); + } + if(local(1, 0, 1) == 0) + { + components++; + local.FloodFill6(1, 0, 1, 1); + } + if(local(1, 2, 1) == 0) + { + components++; + local.FloodFill6(1, 2, 1, 1); + } + if(local(1, 1, 0) == 0) + { + components++; + local.FloodFill6(1, 1, 0, 1); + } + if(local(1, 1, 2) == 0) + { + components++; + local.FloodFill6(1, 1, 2, 1); + } + + return components; +} + +template +rtsImplicit3D rtsImplicit3D::Project2D() +{ + /** + This function projects the entire 3D function onto a 2D function along the z-axis. + **/ + rtsImplicit3D result(m_resolution.x, m_resolution.y, 1); + result = 0; + + indextype x, y, z; + for(x = 0; x +void rtsImplicit3D::Erode(T isovalue, T fill_value) +{ + vector> border_nodes; //get the border nodes for the image + indextype x, y, z; + int condition; + for(x=0; x= isovalue && BackgroundComponents6(x, y, z, isovalue) == 1) + { + condition = 0; + //now find the border pairs. A border point must meet two of the following conditions to be a border pair. + //south border: s(p) is background + if(xyz(x, y-1, z) < isovalue) + condition++; + //north border: n(p) is background, s(p) and s(s(p)) are foreground + if(xyz(x, y+1, z) < isovalue && xyz(x, y-1, z) >= isovalue && xyz(x, y-2, z) >= isovalue) + condition++; + //west border: w(p) is background + if(xyz(x-1, y, z) < isovalue) + condition++; + //east border: e(p) is background, w(p) and w(w(p)) are foreground + if(xyz(x+1, y, z) < isovalue && xyz(x-1, y, z) >= isovalue && xyz(x-2, y, z) >= isovalue) + condition++; + //up border: u(p) is background + if(xyz(x, y, z-1) < isovalue) + condition++; + //down border: d(p) is background, u(p) and u(u(p)) are foreground + if(xyz(x, y, z+1) < isovalue && xyz(x, y, z-1) >= isovalue && xyz(x, y, z-2) >= isovalue) + condition++; + + if(condition > 1) + border_nodes.push_back(point3D(x, y, z)); + } + cout<<"Number of border nodes: "<>::iterator i; + for(i=border_nodes.begin(); i!= border_nodes.end(); i++) + xyz((*i).x, (*i).y, (*i).z) = fill_value; + + +} + +template +void rtsImplicit3D::ClampMax(T max) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i max) + m_data[i] = max; +} + +template +void rtsImplicit3D::ClampMin(T min) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i +void rtsImplicit3D::ClampMin(T min, T value) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i +void rtsImplicit3D::MedianFilter(int dist_x, int dist_y, int dist_z, double factor = 0.5) +{ + rtsImplicit3D result = (*this); + indextype x, y, z; + indextype min_x, min_y, min_z; + indextype max_x, max_y, max_z; + indextype u, v, w; + vector region; + for(x=0; x +unsigned int rtsImplicit3D::Thin(T isovalue) +{ + /** + This function computes the skeleton of an isosurface embedded in the implicit function and + described by the "isovalue" parameter. + **/ + + vector> border_nodes; //get the border nodes for the image + indextype x, y, z; + int condition; + for(x=0; x= isovalue && BackgroundComponents6(x, y, z, isovalue) == 1 && Neighbors26(x, y, z, isovalue) != 1) + { + condition = 0; + //now find the border pairs. A border point must meet two of the following conditions to be a border pair. + //south border: s(p) is background + if(xyz(x, y-1, z) < isovalue) + condition++; + //north border: n(p) is background, s(p) and s(s(p)) are foreground + if(xyz(x, y+1, z) < isovalue && xyz(x, y-1, z) >= isovalue && xyz(x, y-2, z) >= isovalue) + condition++; + //west border: w(p) is background + if(xyz(x-1, y, z) < isovalue) + condition++; + //east border: e(p) is background, w(p) and w(w(p)) are foreground + if(xyz(x+1, y, z) < isovalue && xyz(x-1, y, z) >= isovalue && xyz(x-2, y, z) >= isovalue) + condition++; + //up border: u(p) is background + if(xyz(x, y, z-1) < isovalue) + condition++; + //down border: d(p) is background, u(p) and u(u(p)) are foreground + if(xyz(x, y, z+1) < isovalue && xyz(x, y, z-1) >= isovalue && xyz(x, y, z-2) >= isovalue) + condition++; + + if(condition > 1) + border_nodes.push_back(point3D(x, y, z)); + } + cout<<"Number of border nodes: "< local(3, 3, 3); //store the region local to the current voxel + int nodes_before, nodes_after; //number of neighboring nodes before and after the filling operation + point3D fill_start; + vector>::iterator i; + + /* + Here we determine if a point can be removed by looking at the number of foreground connected + components in the local region. If there is more than one connected component + */ + unsigned int removed = 0; + for(i=border_nodes.begin(); i= isovalue && local(1, 0, 0) >= isovalue && local(1, 2, 0) >= isovalue && local(2, 1, 0) >= isovalue) + // continue; + local(1, 1, 1) = 0; //remove the center voxel + local.Binary(isovalue, 1); + nodes_before = local.Neighbors26(1, 1, 1, 1); + //if(nodes_before == 1) //prevent reducing ends + // continue; + + //find an interior voxel to fill + for(x=0; x<3; x++) + for(y=0; y<3; y++) + for(z=0; z<3; z++) + if(local(x, y, z) > 0) + fill_start = point3D(x, y, z); + + //fill the local region + local.FloodFill26(fill_start.x, fill_start.y, fill_start.z, 2); + //get the number of filled neighbors + nodes_after = local.Neighbors26(1, 1, 1, 2); + if(nodes_after == nodes_before) + { + xyz((*i).x, (*i).y, (*i).z) = 0; + removed++; + //cout<<"removed"<>c;*/ + //} + } + return removed; +} + +/*Shape functions*/ +/*These functions create implicit shapes in the function. +Generally, the shape is based on the parameterization.*/ +template +void rtsImplicit3D::Sphere(double center_i, double center_j, double center_k, double radius, T in_value) +{ + point3D center(center_i, center_j, center_k); + //for each point in the function + indextype x, y, z; + double radius_squared = radius*radius; + vector3D point_to_point; + point3D result; + double distance_squared; + + for(x=0; x +void rtsImplicit3D::toConsole() +{ + cout< +#include "rtsVector3d.h" +#include "rtsPoint3d.h" +#include "rtsMatrix4x4.h" \ No newline at end of file diff --git a/rtsMath.cpp b/rtsMath.cpp new file mode 100755 index 0000000..a8d14e9 --- /dev/null +++ b/rtsMath.cpp @@ -0,0 +1,757 @@ +/*These files contain basic structures used frequently in the program and in computer +graphics in general. For more information, see the header file. + +-David Mayerich, 8/20/05*/ + +#include "rtsMath.h" + +//#include + +//using namespace std; + + + +point3D::point3D() +{ + x=0; y=0; z=0; +} + +point3D::point3D(double newx, double newy, double newz) +{ + x=newx; y=newy; z=newz; +} + +point3D point3D::operator +(vector3D param) +{ + point3D result; + result.x=x+param.x; + result.y=y+param.y; + result.z=z+param.z; + + return result; +} + +point3D point3D::operator -(vector3D param) +{ + point3D result; + result.x=x-param.x; + result.y=y-param.y; + result.z=z-param.z; + + return result; +} + +vector3D point3D::operator -(point3D param) +{ + vector3D result; + result.x=x-param.x; + result.y=y-param.y; + result.z=z-param.z; + + return result; +} + +void point3D::print() +{ + cout< m_x1) + return 0.0f; + if(y < m_y0 || y > m_y1) + return 0.0f; + + float x_size = m_x1 - m_x0; + float y_size = m_y1 - m_y0; + float scaled_x = (x-m_x0)/x_size; + float scaled_y = (y-m_y0)/y_size; + int x_index = scaled_x * m_x_resolution; + int y_index = scaled_y * m_y_resolution; + return m_values[y_index * m_x_resolution + x_index]; +} + +float* function2D::getBits() +{ + return m_values; +} + +void function2D::setBits(unsigned char* bits) +{ + //copy the given bits to the current function + //the member m_values can't just be set to bits because the datatypes may be different + for(int i=0; i m_values[current_max_index]) + current_max_index = i; + } + //cout<<"current max: "<>c; + float current_min = m_values[current_min_index]; + float current_max = m_values[current_max_index]; + //now loop through the function again and scale to the appropriate values + float scaled; + for(int i=0; i max) + m_values[i] = max; + } +} + +void function2D::Abs() +{ + for(int i=0; i +#include +using namespace std; + +class vector3D +{ +public: + float x; + float y; + float z; + + vector3D(); + vector3D(double newx, double newy, double newz); + vector3D operator+(vector3D param); + vector3D operator-(vector3D param); + double operator*(vector3D param); //inner product + vector3D cross(vector3D param); + vector3D operator*(double param); + + int normalize(); + double length(); + + void print(); +}; + + +class point3D +{ +public: + float x; + float y; + float z; + + point3D(); + point3D(double newx, double newy, double newz); + + //support for vector arithmetic + point3D operator+(vector3D param); + point3D operator-(vector3D param); + + vector3D operator-(point3D param); + + void print(); +}; + +class matrix4x4 +{ + + /*stored as: + | 0 4 8 12 | + | | + | 1 5 9 13 | + | | + | 2 6 10 14 | + | | + | 3 7 11 15 | + */ +public: + float matrix[16]; + matrix4x4(); + matrix4x4(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33); + matrix4x4(vector3D basis_x, vector3D basis_y, vector3D basis_z); + vector3D basis_x(); + vector3D basis_y(); + vector3D basis_z(); + point3D operator*(point3D param); + vector3D operator*(vector3D param); + double operator()(unsigned int row, unsigned int col); + void gl_set_matrix(float* gl_matrix); + void gl_get_matrix(float* gl_matrix); + matrix4x4 submatrix(unsigned int start_col, unsigned int start_row, unsigned int end_col, unsigned int end_row); + matrix4x4 transpose(); + void print(); +}; + + +class RGB +{ +public: + float r; + float g; + float b; +}; + +class RGBA +{ +public: + float r; + float g; + float b; + float a; + + RGBA(); + RGBA(double red, double green, double blue, double ambient); +}; + +class quaternion +{ +public: + float w; + float x; + float y; + float z; + + int normalize(); + quaternion operator*(quaternion param); + double* toMatrix(); + + quaternion(); + quaternion(double w, double x, double y, double z); + +}; + +class plane3D +{ +public: + point3D point; + vector3D normal; + + plane3D(); + plane3D(point3D point_on_plane, vector3D plane_normal); +}; + +class ray3D +{ +public: + point3D point; + vector3D direction; + + ray3D(); + ray3D(point3D start_point, vector3D direction); + ray3D(point3D first_point, point3D second_point); + + int intersect(plane3D plane, point3D& intersection_point); +}; + +class line3D +{ +private: + point3D m_p0; + point3D m_p1; + +public: + line3D(); + line3D(point3D p0, point3D p1); + + point3D get_point(double pos); //returns a point at pos = [0.0, 1.0] +}; + + +//at this point, this template class is only really working with floating point numbers (and doubles) +#define RTS_UNSIGNED_BYTE 1 +#define RTS_FLOAT 2 +#define RTS_DOUBLE 3 + +typedef unsigned int rtsBitType; + +class function2D +{ +public: + + function2D(float domain_x0, float domain_x1, float domain_y0, float domain_y1, int x_resolution, int y_resolution); + function2D(); + ~function2D(); + function2D(const function2D ©); //copy constructor + function2D& operator=(const function2D& f); + + void CreateGaussian(float mean_x, float mean_y, float std_dev); + void CreateConstant(float value); + void CreateCircleMask(float center_x, float center_y, float radius); + void Scale(float min, float max); //scales the function so that the range exists only in the specified bounds + void Clip(float min, float max); //clips the function so that the range exists only in the specified bounds + void Abs(); //sets every sample point to the absolute value + float Integral(); //returns the sum of the function + float Average(); + float operator ()(float x, float y); + + function2D operator*(function2D param); + function2D operator*(float param); + function2D operator+(function2D param); + function2D operator+(float param); + function2D operator-(function2D param); + + float* getBits(); + void setBits(float* bits); + void setBits(unsigned char* bits); + void setBits(double* bits); + void setBits(int* bits); + + +private: + float m_x0; + float m_x1; + float m_y0; + float m_y1; + int m_x_resolution; + int m_y_resolution; + float* m_values; +}; + + + + + + + + + +#endif diff --git a/rtsMatrix4x4.h b/rtsMatrix4x4.h new file mode 100755 index 0000000..4f053a5 --- /dev/null +++ b/rtsMatrix4x4.h @@ -0,0 +1,196 @@ +#include +#include +#include +#include + +#include "rtsVector3d.h" +#include "rtsPoint3d.h" + +using namespace std; +#ifndef RTSMATRIX4X4_H +#define RTSMATRIX4X4_H + +#define RTS_PI 3.14159 + +///This class represents a 4x4 matrix, which is often used to represent affine transformations on 3D points and vectors. + +/// +///This class is designed to work with point3d and vector3d. Data is stored internally in a column-major form which is compatible with OpenGL. +/// + +template +class matrix4x4 +{ + /*stored as: + | 0 4 8 12 | + | | + | 1 5 9 13 | + | | + | 2 6 10 14 | + | | + | 3 7 11 15 | + */ +public: + T m_matrix[16]; + + //constructors + matrix4x4(); /// operator*(vector3D rhs); /// operator*(point3D rhs); /// operator*(matrix4x4 rhs); /// +matrix4x4::matrix4x4() +{ + memset(m_matrix, 0, sizeof(T)*16); +} + +template +matrix4x4::matrix4x4(T c0r0, T c0r1, T c0r2, T c0r3, + T c1r0, T c1r1, T c1r2, T c1r3, + T c2r0, T c2r1, T c2r2, T c2r3, + T c3r0, T c3r1, T c3r2, T c3r3) +{ + + T new_matrix[16] = {c0r0,c0r1,c0r2,c0r3,c1r0,c1r1,c1r2,c1r3,c2r0,c2r1,c2r2,c2r3,c3r0,c3r1,c3r2,c3r3}; + memcpy(m_matrix, new_matrix, 16*sizeof(T)); +} + +template +vector3D matrix4x4::operator*(vector3D rhs) +{ + vector3D result; + result.x = m_matrix[0] * rhs.x + m_matrix[4] * rhs.y + m_matrix[8] * rhs.z; + result.y = m_matrix[1] * rhs.x + m_matrix[5] * rhs.y + m_matrix[9] * rhs.z; + result.z = m_matrix[2] * rhs.x + m_matrix[6] * rhs.y + m_matrix[10] * rhs.z; + return result; +} + +template +point3D matrix4x4::operator *(point3D rhs) +{ + point3D result; + result.x = m_matrix[0] * rhs.x + m_matrix[4] * rhs.y + m_matrix[8] * rhs.z + m_matrix[12]; + result.y = m_matrix[1] * rhs.x + m_matrix[5] * rhs.y + m_matrix[9] * rhs.z + m_matrix[13]; + result.z = m_matrix[2] * rhs.x + m_matrix[6] * rhs.y + m_matrix[10] * rhs.z + m_matrix[14]; + T w = m_matrix[3] + m_matrix[7] + m_matrix[11] + m_matrix[15]; + result.x/=w; + result.y/=w; + result.z/=w; + return result; +} + +template +matrix4x4 matrix4x4::operator *(matrix4x4 rhs) +{ + matrix4x4 result; + int i,j,r; + for(i = 0; i<4; i++) + for(j = 0; j<4; j++) + for(r=0; r<4; r++) + result(i, j) += (*this)(i, r) * rhs(r, j); + + return result; +} + + + + +template +void matrix4x4::SetIdentity() +{ + T new_matrix[16] = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}; + memcpy(m_matrix, new_matrix, 16*sizeof(T)); +} + +template +void matrix4x4::SetTranslation(T x, T y, T z) +{ + T new_matrix[16] = {1,0,0,0,0,1,0,0,0,0,1,0,x,y,z,1}; + memcpy(m_matrix, new_matrix, 16*sizeof(T)); +} + +template +void matrix4x4::SetScale(T x, T y, T z) +{ + T new_matrix[16] = {x,0,0,0,0,y,0,0,0,0,z,0,0,0,0,1}; + memcpy(m_matrix, new_matrix, 16*sizeof(T)); +} + +template +void matrix4x4::SetRotation(T angle, T x, T y, T z) +{ + //create the axis of rotation + vector3D axis(x, y, z); + T length = axis.Length(); //make sure that it is normalized + if(length != 1) + axis.Normalize(); + + T c = cos(angle*RTS_PI/180.0); //compute the sine and cosine of angle + T s = sin(angle*RTS_PI/180.0); + + //create the matrix + m_matrix[0] = x*x*(1-c) + c; + m_matrix[1] = y*x*(1-c) + z*s; + m_matrix[2] = x*z*(1-c) - y*s; + m_matrix[4] = x*y*(1-c) - z*s; + m_matrix[5] = y*y*(1-c) + c; + m_matrix[6] = y*z*(1-c) + x*s; + m_matrix[8] = x*z*(1-c) + y*s; + m_matrix[9] = y*z*(1-c) - x*s; + m_matrix[10]= z*z*(1-c) + c; + m_matrix[15]= 1; +} + + +template +void matrix4x4::Print(int width, int precision) +{ + cout< +#include +#include +#include + +//itk includes +#include "../../VesselAnalysis/VesselAnalysis/VOL_to_ITK.h" +#include "itkDanielssonDistanceMapImageFilter.h" +#include "itkBinaryThresholdImageFilter.h" +#include "itkConstNeighborhoodIterator.h" +#include "itkExpandImageFilter.h" +#include "itkDiscreteGaussianImageFilter.h" +#include "itkCastImageFilter.h" + + +/* This code uses the octree library designed by Simon Perreault (http://nomis80.org/code/octree.html)*/ +#include "octree/octree.h" + +#define OCTREE_SIZE 1024 +#define BUFFER_ZONE 0 + + +using namespace std; + + + +//definitions for simple structures +typedef vector> FilamentType; +typedef point3D CoordType; +typedef vector NetworkType; + +struct EdgeType +{ + unsigned int v0; + unsigned int v1; + float avg_radius; + float min_radius; + float max_radius; + float volume; + float length; + bool valid; +}; + +struct NodeType +{ + CoordType p; + vector edges; + bool valid; +}; + +struct ConnectType //this structures stores the info necessary to combine two fibers +{ + unsigned int edge0; + unsigned int edge1; + unsigned int node0; + unsigned int node1; + list::iterator fiber0; + list::iterator fiber1; +}; + +struct ConnectableType +{ + FilamentType fiber; + bool front; + bool back; + unsigned int id; +}; + +struct AttributeType +{ + float TotalFiberLength; + int NumFibers; + int NumPoints; + float TotalVolume; + int NumDisconnectedFibers; + int NumBoundaryFibers; + int NumBifurcations; +}; + +struct BranchType +{ + float angle; + unsigned int branch_id; +}; + + +class rtsNetwork +{ +private: + int id; //used for swc output + ofstream outfile; //also for swc + NetworkType network; //list of filaments that make up the network + vector NodeList; //vector of endpoints + vector EdgeList; //vector of vessels as edges + vector3D boundary; + vector3D position; + + + float calcFiberLength(unsigned int f); + float calcFiberBend(unsigned int f); + float calcTotalLength(); + bool isBoundaryNode(unsigned int node); + vector3D calcTrajectory(FilamentType f, bool end); + bool compareTrajectories(CoordType p0, vector3D v0, CoordType p1, vector3D v1, float distance, float cosine_angle); + void calcGraph(); + vector getConnections(unsigned int node); + CoordType toTissue(CoordType grid_coord); + FilamentType combineFibers(FilamentType f0, bool endpoint0, FilamentType f1, bool endpoint1); + bool isConnectable(ConnectableType c0, ConnectableType c1, bool& c0_end, bool& c1_end, float distance, float cosine_angle); + void traverseGraph(int node, int parent_id); + void outputFiberToSWC(int edge, int node_from, int parent_id); + + vector getFiberAngles(unsigned int fiber); + void reset(); + +public: + //attribute variables + AttributeType Attributes; + + //control variables + point3D voxel_size; + + //cleaning + int cleanDegenerateEdges(float length); + int cleanRedundantEdges(); + int cleanBarbs(float length); + + //methods + rtsOBJ LoadOBJModel(const char* filename); + void AddOBJModel(const char* filename); + void SaveSWCModel(const char *filename, float root_x, float root_y); + void SaveSWCModel(const char *filename); + void Clean(float degenerate_length, float barb_length); + void CalculateAttributes(); + rtsOBJ Repair(float max_distance, float cos_angle); + rtsOBJ CreateModel(); + void printFiberStats(unsigned int fiber); + void ReMesh(float resample_length); + void SaveAngles(const char* filename); + void SaveBends(const char* filename); + void SaveLengths(const char* filename); + void SaveMathematicaGraph(const char* filename); + void SaveMathematicaNodeDistances(const char* filename); + void SetVoxelSize(float dx, float dy, float dz){voxel_size.x = dx; voxel_size.y = dy; voxel_size.z = dz;} + void RemoveTerminalComponents(); + void RemoveBoundaryComponents(); + void GetRadiusFromVolume(const char* filename, unsigned int threshold, unsigned int range); + void GetRadiusFromDistanceMap(const char *filename, int range); + point3D GetFiberRadius(unsigned int fiber); + void ScaleNetwork(float x, float y, float z); + void SetOutputPosition(float x, float y, float z); + + +}; +//private +void rtsNetwork::reset() +{ + vector::iterator e; + for(e=EdgeList.begin(); e!=EdgeList.end(); e++) + (*e).valid = true; + + vector::iterator n; + for(n=NodeList.begin(); n!=NodeList.end(); n++) + (*n).valid = true; +} + +float rtsNetwork::calcFiberBend(unsigned int f) +{ + /*calculates the bend of a fiber.*/ + + //find the line connecting the two endpoints + point3D p1 = toTissue(NodeList[EdgeList[f].v0].p); + point3D p2 = toTissue(NodeList[EdgeList[f].v1].p); + + //find the largest distance between the filament and the line between endpoints + FilamentType::iterator i; + float max_distance = 0; + for(i = network[f].begin(); i!= network[f].end(); i++) + { + point3D p0 = toTissue((*i)); + + //find the distance between the current point and the line made by the endpoints + float d = ((p0 - p1).X(p0-p2).Length())/(p2-p1).Length(); + if(d > max_distance) + max_distance = d; + } + float fiber_length = calcFiberLength(f); + if(max_distance/fiber_length > 0.5) + { + cout<<"Something's wrong."< length) + { + newNetwork.push_back(network[e]); + removed--; + } + + } + //if the fiber is not an end fiber + else + { + newNetwork.push_back(network[e]); + removed--; + } + + } + + network.clear(); + network = newNetwork; + calcGraph(); + + cout<<"Barbs removed: "<*/ + + //form lists of degenerate and non-degenerate edges + int removed = 0; + + list degenerate; + list complete; + + //iterate through each fiber and put it in the appropriate list + int numFibers = network.size(); + int f; + ConnectableType c; + for(f=0; f connected_edges; + vector shared_vertices; + int numEdges, numVerts, e, e0, e1, v; + int connectedEdge; + //for each degenerate edge + list::iterator i; + for(i=degenerate.begin(); i!=degenerate.end(); i++) + { +/*DEGENERATE CASE 1 +In this case, we remove edges that are parts of very small cycles (ex short edges that +bridge between a bifurcation, forming a small triangle). +*/ + //get all of the edges connected to that edge + connected_edges.clear(); + //add edges connected to v0 + v = EdgeList[(*i).id].v0; + numEdges = NodeList[v].edges.size(); + for(e=0; e3 && + NodeList[EdgeList[(*i).id].v0].edges.size() >3) + { + delete_fiber = true; + removed++; + EdgeList[(*i).id].valid = false; + } + + + + + if(!delete_fiber) + complete.push_back((*i)); + + } + + //re-create the network from + NetworkType newNetwork; + for(i = complete.begin(); i!=complete.end(); i++) + newNetwork.push_back((*i).fiber); + + network = newNetwork; + calcGraph(); + + return removed; + + + + +} +bool rtsNetwork::isBoundaryNode(unsigned int node) +{ + CoordType p; + + p = NodeList[node].p; + if(NodeList[node].edges.size() > 1) + return false; + if(p.x > BUFFER_ZONE && p.y > BUFFER_ZONE && p.z > BUFFER_ZONE && + p.x < boundary.x - BUFFER_ZONE && p.y < boundary.y - BUFFER_ZONE && p.z < boundary.z - BUFFER_ZONE) + return false; + else + return true; +} + + +bool rtsNetwork::isConnectable(ConnectableType c0, ConnectableType c1, bool& c0_end, bool& c1_end, float distance, float cosine_angle) +{ + //tests to see if two ConnectableType fibers can be connected. If so, the function + //returns true as well as the optimal connected endpoints as and . + //For these parameters, 0 = the first point on the fiber and 1 = the last point. + + if(c0.id == 1381 && c1.id == 1407) + cout<<"here"< t0; + vector3D t1; + if(c0.front == 0) + { + t0 = calcTrajectory(c0.fiber, 0); + if(c1.front == 0) + { + t1 = calcTrajectory(c1.fiber, 0); + if(compareTrajectories(c0.fiber.front(), t0, c1.fiber.front(), t1, distance, cosine_angle)) + { + c0_end = 0; + c1_end = 0; + return true; + } + } + if(c1.back == 0) + { + t1 = calcTrajectory(c1.fiber, 1); + if(compareTrajectories(c0.fiber.front(), t0, c1.fiber.back(), t1, distance, cosine_angle)) + { + c0_end = 0; + c1_end = 1; + return true; + } + } + } + if(c0.back == 0) + { + t0 = calcTrajectory(c0.fiber, 1); + if(c1.front == 0) + { + t1 = calcTrajectory(c1.fiber, 0); + if(compareTrajectories(c0.fiber.back(), t0, c1.fiber.front(), t1, distance, cosine_angle)) + { + c0_end = 1; + c1_end = 0; + return true; + } + } + if(c1.back == 0) + { + t1 = calcTrajectory(c1.fiber, 1); + if(compareTrajectories(c0.fiber.back(), t0, c1.fiber.back(), t1, distance, cosine_angle)) + { + c0_end = 1; + c1_end = 1; + return true; + } + } + } + + + return false; + +} +FilamentType rtsNetwork::combineFibers(FilamentType f0, bool endpoint0, FilamentType f1, bool endpoint1) +{ + + //create the new filament + FilamentType newFilament; + //insert the first filament + //if the valence-1 vertex is at the beginning + if(endpoint0 == 0) + { + //add the edge backwards + for(int v=f0.size() - 1; v>=0; v--) + newFilament.push_back(f0[v]); + } + else + { + //otherwise we can just copy the filament over + newFilament = f0; + } + + //insert the second filament + //if the valence-1 vertex is at the beginning + if(endpoint1 == 0) + { + //add the edge in forwards + for(int v=0; v=0; v--) + newFilament.push_back(f1[v]); + } + + return newFilament; +} +vector3D rtsNetwork::calcTrajectory(FilamentType f, bool end) +{ + //calculates the trajectory of a fiber at the given endpoint (0 = first, 1 = last) + + CoordType pEndpoint; + CoordType pPrevpoint; + if(end == 0) + { + pEndpoint = f.front(); + pPrevpoint = f[1]; + //pPrevpoint = f[ceil(f.size()/4.0)]; + } + else + { + pEndpoint = f.back(); + pPrevpoint = f[f.size() - 2]; + //pPrevpoint = f[floor(f.size()*3.0/4.0)]; + } + + //pPrevpoint = f[f.size()/2]; + + + vector3D result = toTissue(pEndpoint) - toTissue(pPrevpoint); + result.Normalize(); + return result; +} +bool rtsNetwork::compareTrajectories(CoordType p0, vector3D v0, CoordType p1, vector3D v1, float distance, float cosine_angle) +{ + //determines of two points/trajectory pairs are compatible for connection + vector3D difference = p1 - p0; + //test distance + if(difference.Length() <= distance) + { + difference.Normalize(); + if(v0*difference >= cosine_angle && v1*difference <= -cosine_angle) + return true; + } + return false; +} +vector rtsNetwork::getConnections(unsigned int node) +{ + return NodeList[node].edges; + +} +point3D rtsNetwork::toTissue(CoordType grid_coord) +{ + //converts a coordinate from the original voxel grid coordinates to tissue-space coordinates + return CoordType(grid_coord.x * voxel_size.x, + grid_coord.y * voxel_size.y, + grid_coord.z * voxel_size.z); + + //return grid_coord; +} + +float rtsNetwork::calcFiberLength(unsigned int f) +{ + //This function calculates the total length of the given fiber + + float result = 0.0; + + //find the length of each fiber + int vertNum, v; + + vertNum = network[f].size(); + for(v=1; v outPoint; + //if we are traversing the fiber front-to-back + if(EdgeList[e].v0 == node_from) + { + if(parent_id == -1) + { + p=0; + outPoint = network[e][p] + position; + outfile<=0; p--) + { + outPoint = network[e][p] + position; + outfile< rootSeed(root_x, root_y, 0); + float distance = 9999999; + int closest_node; + + //find the closest node to the root seed + for(node = 0; node != NodeList.size(); node++) + { + float length = (NodeList[node].p - rootSeed).Length(); + if(length < distance) + { + closest_node = node; + distance = length; + cout< Max) Max = temp; + } + + //place each point ID inside the octree + unsigned int id = 0; + Octree tree(OCTREE_SIZE); + tree.setEmptyValue(UINT_MAX); + unsigned int v0, v1; + + + for(f=0; f"< complete; + list incomplete; + + cout<<"Finding Valence-1 Fibers..."< + int numFibers = network.size(); + int f; + unsigned int v0; + unsigned int v1; + int numVerts, v; + for(f=0; f::iterator i; + list::iterator j; + list::iterator temp; + FilamentType newFiber; + bool endpoint0, endpoint1; + + int iIndex, jIndex; + + iIndex = 0; + for(i=incomplete.begin(); i!=incomplete.end(); i++) + { + jIndex = iIndex; + j = i; + while(j != incomplete.end() && i != incomplete.end()) + { + if(i!=j) + { + if(isConnectable((*i), (*j), endpoint0, endpoint1, max_distance, cos_angle)) + { + ConnectableType newConnectable; + newConnectable.fiber = combineFibers((*i).fiber, endpoint0, (*j).fiber, endpoint1); + //determine the new connectivity + if(endpoint0 == 0) + newConnectable.front = (*i).back; + else + newConnectable.front = (*i).front; + + if(endpoint1 == 0) + newConnectable.back = (*j).back; + else + newConnectable.back = (*j).front; + + //remove the previous connectables + temp = i; + i++; + iIndex++; + incomplete.erase(temp); + temp = j; + //this is just in case the fibers are next to each otehr + if(j == i) + { + i++; + iIndex++; + j = i; + jIndex = iIndex; + } + else + { + j = i; + jIndex = iIndex; + } + incomplete.erase(temp); + //insert the new connectable in the proper list + if(newConnectable.front == 0 || newConnectable.back == 0) + incomplete.push_back(newConnectable); + else + complete.push_back(newConnectable); + + + + //numVerts = newConnectable.fiber.size(); + //preview.objBegin(OBJ_LINE_STRIP); + //for(v=0; v newNetwork; + for(i=incomplete.begin(); i!=incomplete.end(); i++) + newNetwork.push_back((*i).fiber); + for(i=complete.begin(); i!=complete.end(); i++) + newNetwork.push_back((*i).fiber); + + network = newNetwork; + calcGraph(); + + + //build the model to return + preview = CreateModel(); + + return preview; + +} +void rtsNetwork::printFiberStats(unsigned int fiber) +{ + /* + cout<<"-----------------------------------------------------"< currentTrajectory; + vector3D branchTrajectory; + unsigned int f; + + //get the list of angles + vector angles = getFiberAngles(fiber); + + unsigned int node = EdgeList[fiber].v0; + int numBranches = NodeList[node].edges.size()-1; + cout<<"V0 Valence: "< distanceVector; + point3D prevPoint; + for(f=0; f= resample_length) + { + newFiber.push_back(network[f][v]); + prevPoint = network[f][v]; + } + } + + //deal with the last vertex + //newFiber.push_back(network[f][v]); + + distanceVector = toTissue(network[f][v]) - toTissue(prevPoint); + if(distanceVector.Length() >= resample_length || newFiber.size() == 1) + { + newFiber.push_back(network[f][v]); + } + else + { + //change the last point + newFiber[newFiber.size() - 1] = network[f][v]; + } + + + //cout<<"old: "< angles = getFiberAngles(f); + for(int a=0; a179 && angles[a].angle < 181) + { + //cout<<"ERROR"<90 && angles[a].angle < 90.01) + { + //cout<<"ERROR"<2) + outfile<2) + outfile<"<"< distance; + outfile<<"d = {"; + for(i=0; iSetSpacing(spacing); + SaveSlice(volume, 20, "original.bmp"); + //volume->ReleaseDataFlagOn(); + +/* + cout<<"Expanding Image..."< ResizeFilterType; + ResizeFilterType::Pointer resizeFilter = ResizeFilterType::New(); + resizeFilter->SetExpandFactors(resample); + resizeFilter->SetInput(volume); + resizeFilter->Update(); + VOLType::Pointer resizedImage = resizeFilter->GetOutput(); + SaveSlice(resizedImage, 20, "resized.bmp"); + cout<<"done."< BlurFilterType; + BlurFilterType::Pointer blurFilter = BlurFilterType::New(); + blurFilter->SetUseImageSpacingOn(); + float variance[3] = {0.61, 1.5, 0.61}; + blurFilter->SetVariance(variance); + blurFilter->SetMaximumKernelWidth(8); + blurFilter->SetInput(volume); + try + { + blurFilter->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(); + + typedef itk::CastImageFilter CastingFilterType; + CastingFilterType::Pointer castFilter = CastingFilterType::New(); + castFilter->SetInput(blurredImage); + castFilter->Update(); + VOLType::Pointer resizedImage = castFilter->GetOutput(); + + SaveSlice(resizedImage, 20, "resized.bmp"); + + + //threshold the input image + cout<<"Thresholding Volume..."< ThresholdFilterType; + ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New(); + thresholdFilter->SetInsideValue(255); + thresholdFilter->SetOutsideValue(0); + thresholdFilter->SetLowerThreshold(threshold); + thresholdFilter->SetUpperThreshold(255); + thresholdFilter->SetInput(resizedImage); + try + { + thresholdFilter->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(); + //volume->ReleaseData(); + //thresholdFilter->ReleaseDataFlagOn(); + + SaveSlice(thresholdImage, 20, "threshold.bmp"); + + cout<<"done."< DistanceFilterType; + DistanceFilterType::Pointer distanceFilter = DistanceFilterType::New(); + distanceFilter->SetInput(thresholdImage); + distanceFilter->UseImageSpacingOn(); + + try + { + distanceFilter->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(), 20, "distance.bmp"); + FloatType::Pointer distanceMap = distanceFilter->GetOutput(); + //SaveFloatRAW(distanceMap, "distanceMap.raw"); + cout<<"done."< NeighborhoodIteratorType; + NeighborhoodIteratorType::RadiusType radius; + radius.Fill(range); + NeighborhoodIteratorType i(radius, distanceMap, distanceMap->GetBufferedRegion()); + vector OffsetVector; + OffsetVector.resize((range*2+1)*(range*2+1)*(range*2+1)); + int x, y, z, j; + j=0; + for(x=-range; x<=range; x++) + for(y=-range; y<=range; y++) + for(z=-range; z<=range; z++) + { + OffsetVector[j][0]=x; + OffsetVector[j][1]=y; + OffsetVector[j][2]=z; + //cout<<"offset: "< position; + float total_radius, near_radius, total_volume, max_radius, min_radius; + FloatType::IndexType pixelIndex; + float prev_radius; + point3D p0, p1; + float height; + for(f=0; f max_radius) + max_radius = near_radius; + if(near_radius < min_radius) + min_radius = near_radius; + total_radius += near_radius; + if(v>0) + { + //compute the volume of the segment + p0 = toTissue(network[f][v-1]); + p1 = toTissue(network[f][v]); + height = (p1 - p0).Length(); + total_volume += ((3.14159*height)/3.0)*(prev_radius * prev_radius + near_radius*near_radius + prev_radius*near_radius); + + } + prev_radius = near_radius; + } + EdgeList[f].avg_radius = total_radius/numVertices; + EdgeList[f].min_radius = min_radius; + EdgeList[f].max_radius = max_radius; + EdgeList[f].volume = total_volume; + } + + cout<<"done."< NeighborhoodIteratorType; + NeighborhoodIteratorType::RadiusType radius; + radius.Fill(range); + NeighborhoodIteratorType i(radius, distanceMap, distanceMap->GetRequestedRegion()); + vector OffsetVector; + OffsetVector.resize((range*2+1)*(range*2+1)*(range*2+1)); + int x, y, z, j; + j=0; + for(x=-range; x<=range; x++) + for(y=-range; y<=range; y++) + for(z=-range; z<=range; z++) + { + OffsetVector[j][0]=x; + OffsetVector[j][1]=y; + OffsetVector[j][2]=z; + //cout<<"offset: "< position; + float total_radius, max_radius; + FloatType::IndexType pixelIndex; + for(f=0; f rtsNetwork::GetFiberRadius(unsigned int fiber) +{ + point3D result; + result.x = EdgeList[fiber].min_radius; + result.y = EdgeList[fiber].max_radius; + result.z = EdgeList[fiber].avg_radius; + return result; +} \ No newline at end of file diff --git a/rtsOctree.h b/rtsOctree.h new file mode 100755 index 0000000..fb60cf4 --- /dev/null +++ b/rtsOctree.h @@ -0,0 +1,70 @@ +#ifndef RTSOCTREE_H +#define RTSOCTREE_H + +#include "rtspoint3D.h" + +template +struct octree_node +{ + unsigned int center; + T data; + octree_node* ppp; + octree_node* ppn; + octree_node* pnp; + octree_node* pnn; + octree_node* npp; + octree_node* npn; + octree_node* nnp; + octree_node* nnn; + octree_node(); +} + +template +octree_node::octree_node() +{ + ppp = NULL; + ppn = NULL; + pnp = NULL; + pnn = NULL; + npp = NULL; + npn = NULL; + nnp = NULL; + nnn = NULL; +} + + +template +class rtsOctree +{ +public: + unsigned int num_leaves; + point3D center; + octree_node* root; + rtsOctree(unsigned int sizex, unsigned int sizey, unsigned int sizez); + void Insert(unsigned int x, unsigned int y, unsigned int z, T value); + +}; + +template +rtsOctree::rtsOctree(unsigned int sizex, unsigned int sizey, unsigned int sizez) +{ + center.x = sizex/2; + center.y = sizey/2; + center.z = sizez/2; + root = new octree_node(); + num_leaves = 1; +} + +template +void rtsOctree::Insert(unsigned int x, unsigned int y, unsigned int z, T value) +{ + point3D current; + point3D destination(x, y, z); + while(!(current == destination)) + { + + + + + +#endif \ No newline at end of file diff --git a/rtsParser.h b/rtsParser.h new file mode 100755 index 0000000..650c0dd --- /dev/null +++ b/rtsParser.h @@ -0,0 +1,279 @@ +#include +#include + +using namespace std; + +//define the parameter data types +#define RTS_ERROR 0 +#define RTS_OK 1 + + +#define RTS_STRING 2 +#define RTS_DOUBLE 3 + +struct parameter +{ + //name of the specified parameter + char* name; + int ID; + char* char_value; + double double_value; + int type; + bool set; +}; + +class rtsParser +{ +private: + vector parameters; + vector::iterator p_SearchParams(char* name); + bool p_SetParameter(char* name, char* value); + bool p_SetParameter(char* name, double value); + +public: + void AddParameter(char* name, int ID, int type); + void AddParameter(char* name, int type); + void OutputParameters(); + void Load(const char* filename); + int GetDoubleParameter(char* name, double& result); + int GetStringParameter(char* name, char*& result); +}; + +vector::iterator rtsParser::p_SearchParams(char *name) +{ + //search the parameters vector for a name matching the input parameter + + vector::iterator iter; + + //run through the vector + for(iter = parameters.begin(); iter != parameters.end(); iter++) + { + //if the name matches the parameter name, return the iterator + if(strcmp((*iter).name, name) == 0) + return iter; + } + + return parameters.end(); +} + +bool rtsParser::p_SetParameter(char *name, char *value) +{ + //sets the character value of a parameter + + //first, find the parameter + vector::iterator iter; + for(iter = parameters.begin(); iter != parameters.end(); iter++) + { + //if the parameter is found + if(strcmp((*iter).name, name) == 0) + { + //if the parameter type is wrong, return false + if((*iter).type != RTS_STRING) + return false; + //otherwise, set the parameter value + (*iter).char_value = value; + (*iter).set = true; + return true; + } + } + //if the parameter was not found, return false + return false; +} + +bool rtsParser::p_SetParameter(char *name, double value) +{ + //sets the character value of a parameter + + //first, find the parameter + vector::iterator iter; + for(iter = parameters.begin(); iter != parameters.end(); iter++) + { + //if the parameter is found + if(strcmp((*iter).name, name) == 0) + { + //if the parameter type is wrong, return false + if((*iter).type != RTS_DOUBLE) + return false; + //otherwise, set the parameter value + (*iter).double_value = value; + (*iter).set = true; + return true; + } + } + //if the parameter was not found, return false + return false; +} + +void rtsParser::Load(const char* filename) +{ + //loads a parameter file and fills the list with the parameter values + + //create an input stream and load the file + ifstream infile; + infile.open(filename); + + //create temporary variables to store values + char param_name[1000]; + vector::iterator iter; + + //for each line in the parameter file + while(!infile.eof()) + { + //get the parameter name token + infile.get(param_name, 100, ' '); + //find the proper parameter in the parameter list + iter = p_SearchParams(param_name); + + //test to make sure the parameter was found + if(iter == parameters.end()) + { + cout<<"Error, could not find parameter: "<>equals; + + //cout<<"infile>>equals: "<::iterator iter = p_SearchParams(name); + + //check for errors + if(iter == parameters.end()) + { + cout<<"Error finding parameter: "<::iterator iter = p_SearchParams(name); + + //check for errors + if(iter == parameters.end()) + { + cout<<"Error finding parameter: "<::iterator iter; + for(iter = parameters.begin(); iter!= parameters.end(); iter++) + { + //test to see if the parameter was set by the file + if((*iter).set) + { + cout<<"name: "<<(*iter).name; + + if((*iter).type == RTS_DOUBLE) + cout<<" value: "<<(*iter).double_value< for linear algebra operations. + +template class point3D +{ + //friend class vector3D; +public: + //data values + T x; + T y; + T z; + + point3D(); /// param); /// param); /// operator+(vector3D param); /// operator-(vector3D param); /// operator-(point3D param); /// operator point3D(); /// &rhs) + { + os<<"("< & operator=(const point3D & rhs) + { + if(this != &rhs) + { + x = rhs.x; + y = rhs.y; + z = rhs.z; + } + return *this; + }*/ + + void print(); +}; + +template +template +point3D::operator point3D() +{ + point3D cast_result(x, y, z); + return cast_result; +} + +template point3D::point3D() +{ + x=0; + y=0; + z=0; +} + +template point3D::point3D(T new_x, T new_y, T new_z) +{ + x=new_x; + y=new_y; + z=new_z; +} + +template +point3D point3D::operator -(vector3D param) +{ + point3D result; //create the result + + result.x = x-param.x; //perform the computation + result.y = y-param.y; + result.z = z-param.z; + + return result; +} + +template +vector3D point3D::operator -(point3D param) +{ + vector3D result; + result.x = x - param.x; + result.y = y - param.y; + result.z = z - param.z; + + return result; +} + +template +point3D point3D::operator+(vector3D param) +{ + point3D result; //create the result + + result.x = x+param.x; //perform the computation + result.y = y+param.y; + result.z = z+param.z; + + return result; +} + +template +bool point3D::operator ==(point3D param) +{ + if(x == param.x && y == param.y && z == param.z) + return true; + else + return false; +} + +template +bool point3D::operator !=(point3D param) +{ + if(x != param.x || y != param.y || z != param.z) + return true; + else + return false; +} + + + +template +void point3D::print() +{ + cout<<"("< +ostream& point3D::operator<<(ostream& os, point3D &rhs) +{ + os<<"("< +#include +using namespace std; + +void rtsProgressBar(int percent) +{ + stringstream bar; + static int x = 0; + string slash[4]; + slash[0] = "\\"; + slash[1] = "-"; + slash[2] = "/"; + slash[3] = "|"; + bar<<"["; + for(int i=0; i<40; i++) + { + if(percent > (float)i/(float)40 *100) + bar << "*"; + else + bar << " "; + } + bar<<"]"; + cout << "\r"; // carriage return back to beginning of line + cout << bar.str() << " " << slash[x] << " " << percent << " %"; // print the bars and percentage + x++; // increment to make the slash appear to rotate + if(x == 4) + x = 0; // reset slash animation +} \ No newline at end of file diff --git a/rtsQuaternion.h b/rtsQuaternion.h new file mode 100755 index 0000000..bef1331 --- /dev/null +++ b/rtsQuaternion.h @@ -0,0 +1,144 @@ +#include "rtsMatrix4x4.h" + +#ifndef RTS_QUATERNION_H +#define RTS_QUATERNION_H + +template +class rtsQuaternion +{ +public: + T w; + T x; + T y; + T z; + + void normalize(); + void CreateRotation(T theta, T axis_x, T axis_y, T axis_z); + rtsQuaternion operator*(rtsQuaternion &rhs); + matrix4x4 toMatrix(); + + + rtsQuaternion(); + rtsQuaternion(T w, T x, T y, T z); + +}; + +template +void rtsQuaternion::normalize() +{ + double length=sqrt(w*w + x*x + y*y + z*z); + w=w/length; + x=x/length; + y=y/length; + z=z/length; +} + +template +void rtsQuaternion::CreateRotation(T theta, T axis_x, T axis_y, T axis_z) +{ + //assign the given Euler rotation to this quaternion + w = cos(theta/2.0); + x = axis_x*sin(theta/2.0); + y = axis_y*sin(theta/2.0); + z = axis_z*sin(theta/2.0); + + +} + +template +rtsQuaternion rtsQuaternion::operator *(rtsQuaternion ¶m) +{ + float A, B, C, D, E, F, G, H; + + + A = (w + x)*(param.w + param.x); + B = (z - y)*(param.y - param.z); + C = (w - x)*(param.y + param.z); + D = (y + z)*(param.w - param.x); + E = (x + z)*(param.x + param.y); + F = (x - z)*(param.x - param.y); + G = (w + y)*(param.w - param.z); + H = (w - y)*(param.w + param.z); + + rtsQuaternion result; + result.w = B + (-E - F + G + H) /2; + result.x = A - (E + F + G + H)/2; + result.y = C + (E - F + G - H)/2; + result.z = D + (E - F - G + H)/2; + + return result; +} + +template +matrix4x4 rtsQuaternion::toMatrix() +{ + matrix4x4 result; + + + double wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; + + + // calculate coefficients + x2 = x + x; y2 = y + y; + z2 = z + z; + xx = x * x2; xy = x * y2; xz = x * z2; + yy = y * y2; yz = y * z2; zz = z * z2; + wx = w * x2; wy = w * y2; wz = w * z2; + + result(0, 0) = 1.0 - (yy + zz); + result(0, 1) = xy - wz; + //m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz; + + result(0, 2) = xz + wy; + result(0, 3) = 0.0; + //m[2][0] = xz + wy; m[3][0] = 0.0; + + result(1, 0) = xy + wz; + result(1, 1) = 1.0 - (xx + zz); + //m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz); + + result(1, 2) = yz - wx; + result(1, 3) = 0.0; + //m[2][1] = yz - wx; m[3][1] = 0.0; + + result(2, 0) = xz - wy; + result(2, 1) = yz + wx; + //m[0][2] = xz - wy; m[1][2] = yz + wx; + + result(2, 2) = 1.0 - (xx + yy); + result(3, 2) = 0.0; + //m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0; + + result(3, 0) = 0.0; + result(3, 1) = 0.0; + result(3, 2) = 0.0; + result(3, 3) = 1.0; + //m[0][3] = 0; m[1][3] = 0; + //m[2][3] = 0; m[3][3] = 1; + /* + double* orientationmatrix=(double*)m; + char c; + + + double* result=new double[16]; + double* array=(double*)m; + for(int i=0; i<16; i++) + result[i]=array[i]; + */ + + return result; +} + +template +rtsQuaternion::rtsQuaternion() +{ + w=0.0; x=0.0; y=0.0; z=0.0; +} + +template +rtsQuaternion::rtsQuaternion(T c, T i, T j, T k) +{ + w=c; x=i; y=j; z=k; +} + +#endif diff --git a/rtsSkeleton.h b/rtsSkeleton.h new file mode 100755 index 0000000..b85d884 --- /dev/null +++ b/rtsSkeleton.h @@ -0,0 +1,107 @@ +#include +using namespace std; + +#include "rtsPoint3d.h" +#include "rts_itkVolume.h" +typedef vector> filament; + +#define BACKGROUND_NODE 0 +#define SKELETON_NODE 255 +#define ENDPOINT_NODE 128 +#define VISITED_NODE 64 + +class rtsSkeleton +{ + rts_itkVolume implicit_skeleton; + vector explicit_filaments; + vector> explicit_endpoints; + + void ComputeEndPoints(); + +public: + void ConstructExplicitSkeleton(); + void SmoothExplicitSkeleton(int iterations); + void SaveExplicitSkeleton(const char* filename); +} + +void rtsSkeleton::ComputeEndPoints() +{ + /*This function finds all of the filament end points in the implicit skeleton. + The end points are stored in the explicit_endpoints vector. + An end point is defined as a node with (n == 1) or (n > 2) connected components. + */ + + unsigned int max_x = implicit_skeleton.DimX(); + unsigned int max_y = implicit_skeleton.DimY(); + unsigned int max_z = implicit_skeleton.DimZ(); + unsigned int conn; + + indextype x, y, z; + for(x=0; x 2) //if the number of connected components meets the + //criteria, store the node in the explicit_endpoints vector. + { + explicit_endpoints.push_back(point3D(x, y, z)); + } + } + + } + + //tag the endpoints in the implicit function + vector>::iterator i; + for(i=explicit_endpoints.begin(); i!=explicit_endpoints.end(); i++) + implicit_skeleton.xyz(i->x, i->y, i->z) = ENDPOINT_NODE; + + //cout<<"Number of end points: "<>::iterator i; + rtsFunction3D local; + unsigned int x, y, z; + for(i = explicit_endpoints.begin(); i != explicit_endpoints.end(); i++) + { + //cout<<"Tracing Filament..."<print(); + local = getLocalRegion(i->x, i->y, i->z); + local(1, 1, 1) = 0; + //local.toConsole(); + for(x=0; x<3; x++) + for(y=0; y<3; y++) + for(z=0; z<3; z++) + if(local.xyz(x, y, z) > VISITED_NODE) + { + //cout<<(int)local.xyz(x, y, z)<x - 1 + x, + // i->y - 1 + y, + // i->z - 1 + z)<(i->x - 1 + x, + i->y - 1 + y, + i->z - 1 + z)); + } + //since we have tracked all filaments attached to an endpoint + //set the endpoint as visited + implicit_skeleton.xyz(i->x, i->y, i->z) = VISITED_NODE; + } + + //cout<<"Tracing complete"< +#include + +using namespace std; + +typedef vector> filament; +typedef unsigned int indextype; + +#define BACKGROUND_NODE 0 +#define SKELETON_NODE 255 +#define ENDPOINT_NODE 128 +#define VISITED_NODE 64 + +class rtsSkeletonizer +{ +private: + rts_itkVolume implicit_skeleton; + /*Key: + 0 - background node + 255 - skeleton node + 128 - endpoint node + */ + + vector explicit_filaments; + vector> explicit_endpoints; + + + +public: + rtsSkeletonizer(rts_itkVolume input); + unsigned int BackgroundComponents6(rts_itkVolume* function, + indextype x, + indextype y, + indextype z, + unsigned char threshold); + unsigned int rtsSkeletonizer::Peel(unsigned char isovalue); + int Neighbors26(rts_itkVolume* function, + indextype x, + indextype y, + indextype z, + unsigned char isovalue); + vector> FloodFill6(rts_itkVolume* function, indextype x, indextype y, indextype z, unsigned char target_value); + void FloodFill26(rts_itkVolume* function, int x, int y, int z, unsigned char target_value); + unsigned int Neighbors6(rts_itkVolume* function, indextype x, indextype y, indextype z, unsigned char threshold); + rts_itkVolume getImplicitResult(){return implicit_skeleton;} + unsigned int NumConnectedComponents(indextype x, indextype y, indextype z, unsigned char threshold); + + void ComputeEndPoints(); //find all of the filament end points + void TraceFilament(point3D p0, point3D p1); + rts_itkVolume getLocalRegion(unsigned int x, unsigned int y, unsigned int z); + + void ConstructExplicitSkeleton(); + void SmoothExplicitSkeleton(int iterations); + void SaveExplicitSkeleton(const char* filename); + + +}; + +void rtsSkeletonizer::SmoothExplicitSkeleton(int iterations) +{ + /*This function smooths the vessels by repeatedly taking the dual of the skeleton. + Branch points and end points are constrained to their initial positions. + */ + + vector::iterator f; + int num_verts, end_vert; + int v; + point3D new_vert; + + for(int i = 0; isize(); + end_vert = num_verts - 1; + + //take care of the first vertex + new_filament.push_back((*f)[0]); + + for(v=1; v::iterator i; + filament::iterator f; + for(i=explicit_filaments.begin(); i!=explicit_filaments.end(); i++) + { + output.objBegin(OBJ_LINE_STRIP); + //cout<<"start filament"<begin(); f!=i->end(); f++) + { + output.objVertex3f((*f).x, (*f).y, (*f).z); + //f->print(); + } + //cout<<"end filament"< rtsSkeletonizer::getLocalRegion(unsigned int x, unsigned int y, unsigned int z) +{ + rts_itkVolume local(3, 3, 3); + point3D corner; + indextype u, v, w; + corner = point3D(x-1, y-1, z-1); + for(u=0; u<3; u++) + for(v=0; v<3; v++) + for(w=0; w<3; w++) + local.SetPixel(u, v, w, implicit_skeleton.GetPixel(corner.x + u, corner.y + v, corner.z + w)); + return local; +} + + +void rtsSkeletonizer::TraceFilament(point3D p0, point3D p1) +{ + //create the new filament and start it with the two given points + filament result; + result.push_back(p0); + result.push_back(p1); + + //if(p0 == point3D(156, 433, 254)) + // cout<<"Stop here"< local; + point3D current = p1; + point3D next; + point3D possible_end; + int x, y, z; + int c; //possible connections + + while(1) //continue tracing until the next endpoint + { + c=0; + local = getLocalRegion(current.x, current.y, current.z); + //cout<<"Local Region at ("<(1, 1, 1) + vector3D(x, y, z); + } + //if it is an endpoint node, check for a termination + if(local(x, y, z) == ENDPOINT_NODE) + { + //if we are not backtracking to the start node + possible_end = current - vector3D(1, 1, 1) + vector3D(x, y, z); + if(possible_end != p0 || result.size() > 2) + { + //terminate the fiber + result.push_back(current - vector3D(1, 1, 1) + vector3D(x, y, z)); + explicit_filaments.push_back(result); + implicit_skeleton.SetPixel(current.x, current.y, current.z, VISITED_NODE); + return; + } + } + } + //return when there is nowhere to go + if(c == 0) + return; + //now we have the next node in the filament, go ahead and label the current + //one as traversed + implicit_skeleton.SetPixel(current.x, current.y, current.z, VISITED_NODE); + //now insert it into the fiber and move to the next node + result.push_back(next); + if(current == next) + { + //cout<<"I've been waiting for you Obi-Wan"<>::iterator i; + rts_itkVolume local; + unsigned int x, y, z; + for(i = explicit_endpoints.begin(); i != explicit_endpoints.end(); i++) + { + //cout<<"Tracing Filament..."<print(); + local = getLocalRegion(i->x, i->y, i->z); + local.SetPixel(1, 1, 1, 0); + //local.toConsole(); + for(x=0; x<3; x++) + for(y=0; y<3; y++) + for(z=0; z<3; z++) + if(local.GetPixel(x, y, z) > VISITED_NODE) + { + //cout<<(int)local.xyz(x, y, z)<x - 1 + x, + // i->y - 1 + y, + // i->z - 1 + z)<(i->x - 1 + x, + i->y - 1 + y, + i->z - 1 + z)); + } + //since we have tracked all filaments attached to an endpoint + //set the endpoint as visited + implicit_skeleton.SetPixel(i->x, i->y, i->z, VISITED_NODE); + } + + //cout<<"Tracing complete"< input) +{ + implicit_skeleton = input; +} + +void rtsSkeletonizer::ComputeEndPoints() +{ + /*This function finds all of the filament end points in the implicit skeleton. + The end points are stored in the explicit_endpoints vector. + An end point is defined as a node with (n == 1) or (n > 2) connected components. + */ + + unsigned int max_x = implicit_skeleton.DimX(); + unsigned int max_y = implicit_skeleton.DimY(); + unsigned int max_z = implicit_skeleton.DimZ(); + unsigned int conn; + + indextype x, y, z; + for(x=0; x 2) //if the number of connected components meets the + //criteria, store the node in the explicit_endpoints vector. + { + explicit_endpoints.push_back(point3D(x, y, z)); + } + } + + } + + //tag the endpoints in the implicit function + vector>::iterator i; + for(i=explicit_endpoints.begin(); i!=explicit_endpoints.end(); i++) + implicit_skeleton.SetPixel(i->x, i->y, i->z, ENDPOINT_NODE); + + //cout<<"Number of end points: "< local(3, 3, 3); + + + local = getLocalRegion(x, y, z); +// local.toConsole(); + local.SetPixel(1, 1, 1, 0); +// local.toConsole(); + + indextype xi, yi, zi; + //iterate through each voxel + for(xi=0; xi<3; xi++) + for(yi=0; yi<3; yi++) + for(zi=0; zi<3; zi++) + if(local(xi, yi, zi) >= threshold) + { + FloodFill6(&local, xi, yi, zi, 0); + result++; + } + /* + if(result == 1 || result > 2) + { + cout<* function, + indextype x, + indextype y, + indextype z, + unsigned char threshold) +{ + /** + This function computes the number of 6-connected background components in the local region of (x, y, z). + This computation is performed by testing all 6 possible voxels that can connect to the specified node. If + a background node is found, the entire background component associated with that node is filled and the counter + is incremented by 1. The value n specifies the connectivity domain for the flood fill. + The definition of background components is that specified by He, Kischell, Rioult and Holmes. + **/ + + //see if there is at least one BG component + if(Neighbors6(function, x, y, z, threshold) == 6) + return 0; + + + //retrieve the local region of the function + rts_itkVolume local(3, 3, 3); + point3D corner(x-1, y-1, z-1); + indextype u, v, w; + for(u=0; u<3; u++) + for(v=0; v<3; v++) + for(w=0; w<3; w++) + local.SetPixel(u, v, w, function->GetPixel(corner.x + u, corner.y + v, corner.z + w)); + + //threshold the background to find inside/outside points + local.Binary(threshold, 1); + //fill points that are not in the connectivity domain + /*if(n == 18) + { + local(0, 0, 0) = 1; + local(0, 0, 2) = 1; + local(0, 2, 0) = 1; + local(0, 2, 2) = 1; + local(2, 0, 0) = 1; + local(2, 0, 2) = 1; + local(2, 2, 0) = 1; + local(2, 2, 2) = 1; + }*/ + //local.toConsole(); + + //search all 6 possible connected points. If a background node is found, fill the component + unsigned int components = 0; + if(local(0, 1, 1) == 0) + { + components++; + FloodFill6(&local, 0, 1, 1, 1); + } + if(local(2, 1, 1) == 0) + { + components++; + FloodFill6(&local, 2, 1, 1, 1); + } + if(local(1, 0, 1) == 0) + { + components++; + FloodFill6(&local, 1, 0, 1, 1); + } + if(local(1, 2, 1) == 0) + { + components++; + FloodFill6(&local, 1, 2, 1, 1); + } + if(local(1, 1, 0) == 0) + { + components++; + FloodFill6(&local, 1, 1, 0, 1); + } + if(local(1, 1, 2) == 0) + { + components++; + FloodFill6(&local, 1, 1, 2, 1); + } + + return components; +} + +unsigned int rtsSkeletonizer::Neighbors6(rts_itkVolume* function, indextype x, indextype y, indextype z, unsigned char threshold) +{ + + unsigned int neighbors = 0; + if(function->GetPixel(x+1, y, z) >= threshold) + neighbors++; + if(function->GetPixel(x-1, y, z) >= threshold) + neighbors++; + if(function->GetPixel(x, y+1, z) >= threshold) + neighbors++; + if(function->GetPixel(x, y-1, z) >= threshold) + neighbors++; + if(function->GetPixel(x, y, z+1) >= threshold) + neighbors++; + if(function->GetPixel(x, y, z-1) >= threshold) + neighbors++; + + return neighbors; +} + +int rtsSkeletonizer::Neighbors26(rts_itkVolume* function, + indextype x, + indextype y, + indextype z, + unsigned char isovalue) +{ + int neighbors = 0; + int u,v,w; + + for(u=-1; u<=1; u++) + for(v=-1; v<=1; v++) + for(w=-1; w<=1; w++) + if(function->GetPixel(x+u, y+v, z+w) >= isovalue) + neighbors++; + if(function->GetPixel(x, y, z) > isovalue) + neighbors--; + + return neighbors; +} + +unsigned int rtsSkeletonizer::Peel(unsigned char isovalue) +{ + /** + Removes one layer of pixels from the specified isosurface. + **/ + + unsigned int res_x = implicit_skeleton.DimX(); + unsigned int res_y = implicit_skeleton.DimY(); + unsigned int res_z = implicit_skeleton.DimZ(); + vector> border_nodes; //get the border nodes for the image + indextype x, y, z; + int condition; + for(x=0; x= isovalue && BackgroundComponents6(&implicit_skeleton, x, y, z, isovalue) == 1 && Neighbors26(&implicit_skeleton, x, y, z, isovalue) != 1) + { + condition = 0; + //now find the border pairs. A border point must meet two of the following conditions to be a border pair. + //south border: s(p) is background + if(implicit_skeleton(x, y-1, z) < isovalue) + condition++; + //north border: n(p) is background, s(p) and s(s(p)) are foreground + if(implicit_skeleton(x, y+1, z) < isovalue && implicit_skeleton(x, y-1, z) >= isovalue && implicit_skeleton(x, y-2, z) >= isovalue) + condition++; + //west border: w(p) is background + if(implicit_skeleton(x-1, y, z) < isovalue) + condition++; + //east border: e(p) is background, w(p) and w(w(p)) are foreground + if(implicit_skeleton(x+1, y, z) < isovalue && implicit_skeleton(x-1, y, z) >= isovalue && implicit_skeleton(x-2, y, z) >= isovalue) + condition++; + //up border: u(p) is background + if(implicit_skeleton(x, y, z-1) < isovalue) + condition++; + //down border: d(p) is background, u(p) and u(u(p)) are foreground + if(implicit_skeleton(x, y, z+1) < isovalue && implicit_skeleton(x, y, z-1) >= isovalue && implicit_skeleton(x, y, z-2) >= isovalue) + condition++; + + if(condition > 1) + border_nodes.push_back(point3D(x, y, z)); + } + //cout<<"Number of border nodes: "< local(3, 3, 3); //store the region local to the current voxel + int nodes_before, nodes_after; //number of neighboring nodes before and after the filling operation + point3D fill_start; + vector>::iterator i; + + /* + Here we determine if a point can be removed by looking at the number of foreground connected + components in the local region. If there is more than one connected component + */ + unsigned int removed = 0; + for(i=border_nodes.begin(); i 0) + fill_start = point3D(x, y, z); + + //fill the local region + FloodFill26(&local, fill_start.x, fill_start.y, fill_start.z, 2); + //get the number of filled neighbors + nodes_after = Neighbors26(&local, 1, 1, 1, 2); + if(nodes_after == nodes_before) + { + implicit_skeleton.SetPixel((*i).x, (*i).y, (*i).z, 0); + removed++; + } + + } + return removed; +} + +vector> rtsSkeletonizer::FloodFill6(rts_itkVolume* function, indextype x, indextype y, indextype z, unsigned char target_value) +{ + //create a vector containing all of the filled nodes + vector> result; + + unsigned char old_value = function->GetPixel(x, y, z); //find the old value (the value being flood-filled) + if(target_value == old_value) //if the target value is the same as the old value, nothing to do + return result; + + queue> Q; //create a queue for neighboring points + point3D current(x, y, z); //start with the current point + function->SetPixel(current.x, current.y, current.z, target_value); + point3D next; + Q.push(current); + indextype u, v, w; + + + while(!Q.empty()) //continue until the queue is empty + { + current = Q.front(); //get the first element from the queue + Q.pop(); + + if(current.x != function->DimY() - 1) + if(function->GetPixel(current.x + 1, current.y, current.z) == old_value) + { + function->SetPixel(current.x + 1, current.y, current.z, target_value); + result.push_back(point3D(current.x + 1, current.y, current.z)); + Q.push(point3D(current.x + 1, current.y, current.z)); + } + if(current.x != 0) + if(function->GetPixel(current.x - 1, current.y, current.z) == old_value) + { + function->SetPixel(current.x - 1, current.y, current.z, target_value); + result.push_back(point3D(current.x - 1, current.y, current.z)); + Q.push(point3D(current.x - 1, current.y, current.z)); + } + if(current.y != function->DimY() - 1) + if(function->GetPixel(current.x, current.y +1, current.z) == old_value) + { + function->SetPixel(current.x, current.y+1, current.z, target_value); + result.push_back(point3D(current.x, current.y+1, current.z)); + Q.push(point3D(current.x, current.y+1, current.z)); + } + if(current.y != 0) + if(function->GetPixel(current.x, current.y-1, current.z) == old_value) + { + function->SetPixel(current.x, current.y-1, current.z, target_value); + result.push_back(point3D(current.x, current.y-1, current.z)); + Q.push(point3D(current.x, current.y-1, current.z)); + } + if(current.z != function->DimZ() - 1) + if(function->GetPixel(current.x, current.y, current.z+1) == old_value) + { + function->SetPixel(current.x, current.y, current.z+1, target_value); + result.push_back(point3D(current.x, current.y, current.z+1)); + Q.push(point3D(current.x, current.y, current.z+1)); + } + if(current.z != 0) + if(function->GetPixel(current.x, current.y, current.z-1) == old_value) + { + function->SetPixel(current.x, current.y, current.z-1, target_value); + result.push_back(point3D(current.x, current.y, current.z-1)); + Q.push(point3D(current.x, current.y, current.z-1)); + } + + } + + return result; + +} + +void rtsSkeletonizer::FloodFill26(rts_itkVolume* function, int x, int y, int z, unsigned char target_value) +{ + unsigned char old_value = function->GetPixel(x, y, z); + if(target_value == old_value) + return; + + queue> Q; + point3D current(x, y, z); + point3D next; + Q.push(current); + indextype u, v, w; + while(!Q.empty()) + { + current = Q.front(); + if(function->GetPixel(current.x, current.y, current.z) == old_value) + function->SetPixel(current.x, current.y, current.z, target_value); + Q.pop(); + + unsigned int res_x = function->DimX(); + unsigned int res_y = function->DimY(); + unsigned int res_z = function->DimZ(); + for(u=-1; u<=1; u++) + for(v=-1; v<=1; v++) + for(w=-1; w<=1; w++) + { + next.x = current.x + u; + next.y = current.y + v; + next.z = current.z + w; + + if(next.x >= 0 && next.x < res_x && + next.y >= 0 && next.y < res_y && + next.z >= 0 && next.z < res_z && + function->GetPixel(next.x, next.y, next.z) == old_value) + { + function->SetPixel(next.x, next.y, next.z, target_value); + Q.push(next); + } + } + } + + +} + + + + + + + +#endif \ No newline at end of file diff --git a/rtsSourceCode.h b/rtsSourceCode.h new file mode 100755 index 0000000..0ff6c25 --- /dev/null +++ b/rtsSourceCode.h @@ -0,0 +1,65 @@ +#ifndef RTSSOURCECODE_H +#define RTSSOURCECODE_H + +#include +#include +#include +#include + +using namespace std; + +///This class defines generic source code that can be loaded from text files. It is primarily used by the rts_glShaderProgram class for GLSL programming. + +class rtsSourceCode +{ +public: + vector source; //the actual source code + void clear() /// min_chars) + total_chars = num_chars; + else + total_chars = min_chars; + result = new char[total_chars + 1]; + //initialize the string to 0's + for(int i=0; i= start_index && (j < start_index + num_length)) + { + filename[j] = number[j - start_index]; + } + //otherwise output the mask value + else + filename[j] = mask[j]; + } + filename[length] = 0; + result[i] = filename; + } + return result; +} + + +unsigned char* rtsCalculateDifferenceImage(int length, unsigned char* a, unsigned char* b) +{ + //calculates the difference between two images and returns the absolute value + unsigned char* result = new unsigned char[length]; + for(int i=0; i +#include +#include +#include +#include "rtsMath.h" + +using namespace std; + +char* rtsInt_to_String(int num, int min_chars); +char** rtsGetFileList(const char* mask, unsigned int start, unsigned int end); +unsigned char* rtsCalculateDifferenceImage(int length, unsigned char* a, unsigned char* b); +unsigned int rtsSumPixels(int length, unsigned char* pixels); +unsigned char* rts2DGaussian(int width, int height, double std_dev); +unsigned char* rtsInvertImage(int width, int height, unsigned char* pixels); +unsigned char* rtsMultiplyImages(int width, int height, unsigned char* pixels_a, unsigned char* pixels_b); + +#endif \ No newline at end of file diff --git a/rtsVector3d.h b/rtsVector3d.h new file mode 100755 index 0000000..38ff66d --- /dev/null +++ b/rtsVector3d.h @@ -0,0 +1,164 @@ +///This class is used to store information for a 3D vector. +#include +#include +using namespace std; + +#ifndef RTSVECTOR3D_H +#define RTSVECTOR3D_H + + +template class vector3D +{ + //friend class point3D; +public: + //data values + T x; + T y; + T z; + + vector3D(); /// operator+(vector3D param); /// operator-(vector3D param); /// param); /// operator*(T param); /// X(vector3D param); /// operator*(const T lhs, vector3D rhs){return rhs*lhs;} /// Times(vector3D param); /// Normalize(); /// operator vector3D(); /// &rhs) + { + os<<"("< +template +vector3D::operator vector3D() +{ + vector3D cast_result(x, y, z); + return cast_result; +} + +template vector3D::vector3D() +{ + x=0; + y=0; + z=0; +} + +template vector3D::vector3D(T new_x, T new_y, T new_z) +{ + x=new_x; + y=new_y; + z=new_z; +} + +template +vector3D vector3D::operator -(vector3D param) +{ + vector3D result; //create the result + + result.x = x-param.x; //perform the computation + result.y = y-param.y; + result.z = z-param.z; + + return result; +} + +template +vector3D vector3D::operator+(vector3D param) +{ + vector3D result; //create the result + + result.x = x+param.x; //perform the computation + result.y = y+param.y; + result.z = z+param.z; + + return result; +} + +template +vector3D vector3D::Times(vector3D param) +{ + vector3D result; //create the result + + result.x = x*param.x; //perform the computation + result.y = y*param.y; + result.z = z*param.z; + + return result; +} + +template +vector3D vector3D::operator*(T param) +{ + vector3D result; //create the result + + result.x = x*param; //perform the computation + result.y = y*param; + result.z = z*param; + + return result; +} + +template +T vector3D::operator *(vector3D param) +{ + //This function computes the dot product between two vectors + return x*param.x + y*param.y + z*param.z; +} + +template +vector3D vector3D::X(vector3D param) +{ + vector3D result; + result.x=y*param.z - z*param.y; + result.y=z*param.x - x*param.z; + result.z=x*param.y - y*param.x; + + return result; +} + +template +vector3D vector3D::Normalize() +{ + T length = Length(); + if(length ==0.0) + { + x = y = z = 0; + } + else + { + x/= length; + y /=length; + z /=length; + } + return *this; +} + +template +T vector3D::Length() +{ + return sqrt(x*x + y*y + z*z); +} + +template +void vector3D::print() +{ + cout<<"["<insert(front_back, 0, 0, 0); + this->insert(front_back, 0, 0, m_size_z-1); + this->insert(left_right, 0, 0, 0); + this->insert(left_right, m_size_x-1, 0, 0); + this->insert(top_bottom, 0, 0, 0); + this->insert(top_bottom, 0, m_size_y-1, 0); + +} + +void rtsVolume::invert() +{ + //inverts the data stored in the volume + unsigned int length = m_size_x*m_size_y*m_size_z; + for(int i=0; i= threshold) + m_data[i] = 255; +} + +void rtsVolume::blit3D(const unsigned char* source, + unsigned int s_sx, unsigned int s_sy, unsigned int s_sz, + unsigned char* dest, + unsigned int d_px, unsigned int d_py, unsigned int d_pz, + unsigned int d_sx, unsigned int d_sy, unsigned int d_sz) +{ + unsigned int ps, pd; //stores the mapping for the source point to the dest point + //find the maximum points that can be blit to (in case source overlaps the edges of dest) + unsigned int blit_size_x = min(s_sx, d_sx - d_px); + unsigned int blit_size_y = min(s_sy, d_sy - d_py); + unsigned int blit_size_z = min(s_sz, d_sz - d_pz); + + unsigned int source_z_offset = s_sx * s_sy; + unsigned int dest_z_offset = d_sx * d_sy; + + unsigned int z,y; + for(z=0; z +#include +#include + +using namespace std; + +class rtsVolume +{ + +private: + unsigned char* m_data; //pointer to the volume data + unsigned int m_size_x; //variables specifying the size of the volume + unsigned int m_size_y; + unsigned int m_size_z; + + //static function for copying 3D data from one pointer to another + //this function does not test boundaries so can quite easily crash + void blit3D(const unsigned char* source, + unsigned int s_sx, unsigned int s_sy, unsigned int s_sz, + unsigned char* dest, + unsigned int d_px, unsigned int d_py, unsigned int d_pz, + unsigned int d_sx, unsigned int d_sy, unsigned int d_sz); + +public: + rtsVolume(); + //construct a blank volume of a given size + rtsVolume(unsigned int size_x, unsigned int size_y, unsigned int size_z); + //construct a volume from specified data + rtsVolume(const unsigned char* data, unsigned int size_x, unsigned int size_y, unsigned int size_z); + rtsVolume(const rtsVolume &original); //copy constructor + ~rtsVolume(); + + //overloaded operators + rtsVolume& operator=(const rtsVolume& original); + inline unsigned char operator()(unsigned int x, unsigned int y, unsigned int z); + + //load and save methods + void open(const char* filename); + void save(const char* filename); + /*Allow resizing of the canvas. This resizes the volume without + resizing the existing data within the volume*/ + void resize_canvas(unsigned int size_x, unsigned int size_y, unsigned int size_z); + void insert(const rtsVolume source, unsigned int pos_x, unsigned int pos_y, unsigned int pos_z); + void blacken_border(); + void invert(); + void blacken(unsigned char threshold); + void whiten(unsigned char threshold); + + //get functions + unsigned char* get_bits(); + unsigned int get_dimx() {return m_size_x;} + unsigned int get_dimy() {return m_size_y;} + unsigned int get_dimz() {return m_size_z;} + + + +}; + + + +#endif \ No newline at end of file diff --git a/rts_cudaBrewer.h b/rts_cudaBrewer.h new file mode 100755 index 0000000..885188d --- /dev/null +++ b/rts_cudaBrewer.h @@ -0,0 +1,59 @@ +#include "rtsVector3d.h" +#include "cudaHandleError.h" + +#define BREWER_CTRL_PTS 11 +texture cudaTexBrewer; +cudaArray* gpuBrewer; + + +__device__ float4 colorBrewer(float val, float min_range, float max_range, float min_fade = 0.000) +{ + float t = (val - min_range)/(max_range - min_range)*((float)(BREWER_CTRL_PTS-2)/BREWER_CTRL_PTS); + float shift = 1.0/BREWER_CTRL_PTS; + float4 color = tex1D(cudaTexBrewer, t+shift); + if(t < min_fade) + color.w = (val - min_range)/(max_range - min_range)/min_fade; + return color; +} + + +void rts_cudaInitBrewer() +{ + //allocate CPU space + float4 cpuColorMap[BREWER_CTRL_PTS]; + + //define control points + cpuColorMap[0] = make_float4(0.192157f, 0.211765f, 0.584314f, 1.0f); + cpuColorMap[1] = make_float4(0.270588f, 0.458824f, 0.705882f, 1.0f); + cpuColorMap[2] = make_float4(0.454902f, 0.678431f, 0.819608f, 1.0f); + cpuColorMap[3] = make_float4(0.670588f, 0.85098f, 0.913725f, 1.0f); + cpuColorMap[4] = make_float4(0.878431f, 0.952941f, 0.972549f, 1.0f); + cpuColorMap[5] = make_float4(1.0f, 1.0f, 0.74902f, 1.0f); + cpuColorMap[6] = make_float4(0.996078f, 0.878431f, 0.564706f, 1.0f); + cpuColorMap[7] = make_float4(0.992157f, 0.682353f, 0.380392f, 1.0f); + cpuColorMap[8] = make_float4(0.956863f, 0.427451f, 0.262745f, 1.0f); + cpuColorMap[9] = make_float4(0.843137f, 0.188235f, 0.152941f, 1.0f); + cpuColorMap[10] = make_float4(0.647059f, 0.0f, 0.14902f, 1.0f); + + + int width = BREWER_CTRL_PTS; + int height = 0; + + + // allocate array and copy colormap data + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 32, 32, 32, cudaChannelFormatKindFloat); + + HANDLE_ERROR(cudaMallocArray(&gpuBrewer, &channelDesc, width, height)); + + cudaMemcpyToArray(gpuBrewer, 0, 0, cpuColorMap, sizeof(float4)*width, cudaMemcpyHostToDevice); + + // set texture parameters + cudaTexBrewer.addressMode[0] = cudaAddressModeClamp; + //texBrewer.addressMode[1] = cudaAddressModeClamp; + cudaTexBrewer.filterMode = cudaFilterModeLinear; + cudaTexBrewer.normalized = true; // access with normalized texture coordinates + + // Bind the array to the texture + HANDLE_ERROR( cudaBindTextureToArray( cudaTexBrewer, gpuBrewer, channelDesc)); + +} diff --git a/rts_cudaCufftShift.h b/rts_cudaCufftShift.h new file mode 100755 index 0000000..c42cde4 --- /dev/null +++ b/rts_cudaCufftShift.h @@ -0,0 +1,65 @@ +#ifndef CUDA_CUFFT_SHIFT_H +#define CUDA_CUFFT_SHIFT_H + +#define BLOCK_SIZE 16 + +__global__ void devCufftShift(char* gpuSource, int sE, int sX, int sY, int sZ) +{ + int ix = blockIdx.x * blockDim.x + threadIdx.x; + int blocks_per_slice = sY/blockDim.y + 1; + int iy = (blockIdx.y % blocks_per_slice)*blockDim.y + threadIdx.y; + int iz = blockIdx.y/blocks_per_slice; + + if(ix >= sX || iy >= sY || iz >= sZ/2) + return; + + //array index + int i = iz*sX*sY*sE + iy*sX*sE + ix*sE; + + int iSwap = (iz + sZ/2)*sX*sY*sE; + + if(iy < sY/2) + iSwap += (iy + sY/2)*sX*sE; + else + iSwap += (iy - sY/2)*sX*sE; + + if(ix < sX/2) + iSwap += (ix + sX/2)*sE; + else + iSwap += (ix - sX/2)*sE; + //iSwap = (iz + sZ/2)*sX*sY*sE + (iy + sY/2)*sX*sE + (ix + sX/2)*sE; + + char temp; + for(int e=0; e>>(gpuSource, elementSize, sX, sY, sZ); + + + +} + + +#endif \ No newline at end of file diff --git a/rts_glBrewer.glsl b/rts_glBrewer.glsl new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/rts_glBrewer.glsl diff --git a/rts_glBrewer.h b/rts_glBrewer.h new file mode 100755 index 0000000..18ca3e4 --- /dev/null +++ b/rts_glBrewer.h @@ -0,0 +1,17 @@ +#include "rtsPoint3d.h" + +void rts_glBrewerPts(point3D* brewerPts) +{ + //define control points + brewerPts[0] = point3D(0.192157f, 0.211765f, 0.584314f); + brewerPts[1] = point3D(0.270588f, 0.458824f, 0.705882f); + brewerPts[2] = point3D(0.454902f, 0.678431f, 0.819608f); + brewerPts[3] = point3D(0.670588f, 0.85098f, 0.913725f); + brewerPts[4] = point3D(0.878431f, 0.952941f, 0.972549f); + brewerPts[5] = point3D(1.0f, 1.0f, 0.74902f); + brewerPts[6] = point3D(0.996078f, 0.878431f, 0.564706f); + brewerPts[7] = point3D(0.992157f, 0.682353f, 0.380392f); + brewerPts[8] = point3D(0.956863f, 0.427451f, 0.262745f); + brewerPts[9] = point3D(0.843137f, 0.188235f, 0.152941f); + brewerPts[10] = point3D(0.647059f, 0.0f, 0.14902f); +} \ No newline at end of file diff --git a/rts_glFilamentNetwork.cpp b/rts_glFilamentNetwork.cpp new file mode 100755 index 0000000..404260f --- /dev/null +++ b/rts_glFilamentNetwork.cpp @@ -0,0 +1,17 @@ +#include "rts_glFilamentNetwork.h" + +void rts_glFilamentNetwork::glRender() +{ + ((rts_glOBJ*)network)->glRender(); +} + +void rts_glFilamentNetwork::glRenderSelected() +{ + ((rts_glOBJ*)network)->glRenderSelected(); +} + +int rts_glFilamentNetwork::LoadFIB(const char* filename) +{ + ((rts_glOBJ*)network)->Invalidate(); + return fib_load(filename); +} \ No newline at end of file diff --git a/rts_glFilamentNetwork.h b/rts_glFilamentNetwork.h new file mode 100755 index 0000000..00c9114 --- /dev/null +++ b/rts_glFilamentNetwork.h @@ -0,0 +1,26 @@ +#ifndef RTS_GLFILAMENTNETWORK_H +#define RTS_GLFILAMENTNETWORK_H + +#include "rtsFilamentNetwork.h" +#include "rts_glOBJ.h" +#include +#include +#include + +class rts_glFilamentNetwork:public rtsFilamentNetwork +{ +public: + rts_glFilamentNetwork(){network = new rts_glOBJ();} + void glRender(); + void glRenderSelected(); + + int LoadFIB(const char* filename); //overload the parent function to reset the display list + + void Pick(unsigned int x, unsigned int y, unsigned int size_x, unsigned int size_y) + { + ((rts_glOBJ*)network)->Pick(x, y, size_x, size_y); + } +}; + + +#endif \ No newline at end of file diff --git a/rts_glIntegrateTexture.cpp b/rts_glIntegrateTexture.cpp new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/rts_glIntegrateTexture.cpp diff --git a/rts_glIntegrateTexture.h b/rts_glIntegrateTexture.h new file mode 100755 index 0000000..2e86d67 --- /dev/null +++ b/rts_glIntegrateTexture.h @@ -0,0 +1,172 @@ +/*This class performs integration across a series of rectangular +texture samples. Basically, this is a downsample using a large box +filter and can be used to sum the results of multiple calculations +that are combined in a single texture.*/ + +#include "rts_glRenderToTexture.h" +#include "rts_glShaderProgram.h" + +#define MEAN 0 +#define SUM 1 +#define MIN 2 +#define MAX 3 + + +class rts_glIntegrateTexture +{ +private: + int x_sample_size; + int y_sample_size; + int x_sample_num; + int y_sample_num; + + rts_glShaderProgram x_pass_mean; + rts_glShaderProgram y_pass_mean; + + rts_glShaderProgram x_pass_min; + rts_glShaderProgram y_pass_min; + + rts_glShaderProgram x_pass_max; + rts_glShaderProgram y_pass_max; + + //this is a two-pass downsample + rts_glRenderToTexture x_pass; + rts_glRenderToTexture y_pass; + + void initialize_shaders(); + inline void x_pass_enable(int type, rts_glTextureMap texture); + inline void x_pass_disable(int type); + inline void y_pass_enable(int type); + inline void y_pass_disable(int type); + +public: + //initialize the integrator with the number and size of samples + void Init(int x_size, int y_size, + int samples_x, int samples_y, + rts_glTextureMap test); + + void Integrate(float* result, rts_glTextureMap texture, int type = MEAN); + rts_glTextureMap getResultTexture(){return y_pass.GetTexture(0);} +}; + +void rts_glIntegrateTexture::initialize_shaders() +{ + //load and initialize the integration shaders + x_pass_mean.AttachShader(GL_FRAGMENT_SHADER, + "x_pass_mean.glsl"); + x_pass_mean.Compile(); + x_pass_mean.Link(); + cout<<"x_pass_mean.glsl"< 4) + glBegin(GL_POLYGON); + else if(primitives[id].p.size() == 4) + glBegin(GL_QUADS); + else if(primitives[id].p.size() == 3) + glBegin(GL_TRIANGLES); + else + return; + + //now run through each vertex + unsigned int num_vertices = primitives[id].p.size(); + for(unsigned int v=0; v::iterator p; + for(p = selected_primitives.begin(); p!=selected_primitives.end(); p++) + f_RenderPrimitive(*p); + } + return OBJ_OK; +} + + +void rts_glOBJ::SelectPrimitive(unsigned int primitive) +{ + //adds a primitive to the selection list + selected_primitives.push_back(primitive); + selected_primitives.unique(); +} + +void rts_glOBJ::UnselectPrimitive(unsigned int primitive) +{ + selected_primitives.remove(primitive); +} + +void rts_glOBJ::SelectMultipleHits(GLuint* buffer, unsigned int num_hits) +{ + GLuint* hit_entry = buffer; + GLuint num_names; + GLuint nearest_name; + GLuint minZ = 0xffffffff; + + //push the hits into the selection buffer + for(int h=0; h::iterator p; + for(p = selected_primitives.begin(); p != selected_primitives.end(); p++) + { + primitive selected_prim = primitives[(*p)]; + //create a new primitive + primitive new_prim; + new_prim.mask = selected_prim.mask; + new_prim.type = selected_prim.type; + + //for each vertex in the primitive + int num_vertices = selected_prim.p.size(); + for(int v = 0; v selected_v; + + list::iterator p; //selected primitive + vector::iterator v; //vertex + + //insert all selected vertex indices into selected_v + for(p = selected_primitives.begin(); p!=selected_primitives.end(); p++) + { + for(v=primitives[(*p)].p.begin(); v!=primitives[(*p)].p.end(); v++) + { + selected_v.push_back((*v).v); + } + } + selected_v.unique(); //remove redundant entries + + //now find all primitives connected to these vertices + int num_primitives = primitives.size(); + int prim; + list::iterator s_v; + for(prim =0; prim* vertex_to_prim = new vector[v_list.size()]; + int num_primitives = primitives.size(); + int p; + int num_vertices, v; + int vertex; + for(p=0; p selected_verts; + list::iterator sel; + for(sel = selected_primitives.begin(); sel != selected_primitives.end(); sel++) + { + num_vertices = primitives[(*sel)].p.size(); + for(v=0; v::iterator s_v; + for(s_v = selected_verts.begin(); s_v != selected_verts.end(); s_v++) + { + num_primitives = vertex_to_prim[(*s_v)].size(); + for(p=0; p +#include +#include +#include + +using namespace std; + +#define BUFSIZE 20000 + +#define OBJ_NOT_SELECTED 0x0000 +#define OBJ_SELECTED 0x0001 +#define OBJ_SELECTED_PRIMITIVES 0x0002 + +#define RTS_GLOBJ_SINGLE_NEW_SELECTION 0 +#define RTS_GLOBJ_SINGLE_ADD_SELECTION 1 +#define RTS_GLOBJ_SINGLE_SUB_SELECTION 2 + +#define RTS_GLOBJ_MULTI_NEW_SELECTION 3 +#define RTS_GLOBJ_MULTI_ADD_SELECTION 4 +#define RTS_GLOBJ_MULTI_SUB_SELECTION 5 + +class rts_glOBJ : public rtsOBJ +{ +private: + int is_selected; //the object, or part of the object, is selected + list selected_primitives; + + //rendering variables + GLint dl; + bool dl_valid; //true if the display list is valid + + OBJint f_CreateDisplayList(); + + void f_RenderPointList(unsigned int pointlist); + void f_RenderLineStrip(unsigned int line); + void f_RenderFace(unsigned int face); + + OBJint f_RenderTexCoord(vertex_texture &texcoord); + OBJint f_RenderNormal(vertex_normal &normal); + OBJint f_RenderVertex(vertex_position &v); + OBJint f_RenderPrimitive(unsigned int id); + + void SelectMultipleHits(GLuint* buffer, unsigned int num_hits); + void SelectClosestHit(GLuint* buffer, unsigned int num_hits); + void SelectPrimitive(unsigned int primitive); + void UnselectMultipleHits(GLuint* buffer, unsigned int num_hits); + void UnselectClosestHit(GLuint* buffer, unsigned int num_hits); + void UnselectPrimitive(unsigned int primitive); + +public: + //constructors + //basic + rts_glOBJ() + { + is_selected = false; + dl_valid = false; + cout< +#include +#include "rts_glTextureMap.h" + +using namespace std; + +class rts_glRenderToTexture +{ +private: + bool init; + + GLuint fbo; //framebuffer object + int width; //width and height of the framebuffer + int height; + vector textures; + +public: + //constructors + rts_glRenderToTexture(){init = false; fbo = 0;} + rts_glRenderToTexture(int width, int height){Init(width, height);} + + void Init(int width, int height); //initialization + void Clean(); + + void AddTexture(GLenum target, + GLint internalformat = 1, + GLenum format = GL_LUMINANCE, + GLenum datatype = GL_UNSIGNED_BYTE, + GLint interpolation = GL_NEAREST); + void BeginTexture(int texture){textures[texture].BeginTexture();} + void EndTexture(int texture){textures[texture].EndTexture();} + rts_glTextureMap GetTexture(int texture){return textures[texture];} + + void BeginRender(int texture); + void EndRender(); + + int Width(){return width;} + int Height(){return height;} + void UseMaxViewport(){glViewport(0, 0, width, height);} + +}; + +#endif diff --git a/rts_glRenderableDTGrid.cpp b/rts_glRenderableDTGrid.cpp new file mode 100755 index 0000000..1a24fcc --- /dev/null +++ b/rts_glRenderableDTGrid.cpp @@ -0,0 +1,260 @@ +#include "rts_glRenderableDTGrid.h" + + +/*ITERATOR INITIALIZATION*/ +void rts_glRenderableDTGrid::init_iter_ppp() +{ + m_iterator = begin(); + m_iter_type = PPP; +} +void rts_glRenderableDTGrid::init_iter_nnn() +{ + m_iterator = last(); + m_iter_type = NNN; +} +void rts_glRenderableDTGrid::init_iter_ppn() +{ + m_iterator = begin(); //put the iterator at the beginning of the data set + + if(m_iterator.grid->acc.size() > 1) //if there is more than one pcolumn + { + m_iterator.loc.iv = m_iterator.grid->proj2D.value[1].to_value - 1; + m_iterator.loc.z = zCoord[m_iterator.grid->proj2D.value[1].to_coord - 1]; + } + else + { + m_iterator.loc.iv = value.size() - 1; + m_iterator.loc.z = zCoord.back(); + } + m_iter_type = PPN; +} + +void rts_glRenderableDTGrid::init_iter_npp() +{ + //set the 1D iterator location + m_iterator.Iterator2D.Iterator1D.loc.iv = proj2D.proj1D.value.size()-1; //start at the last 1D p-column + m_iterator.Iterator2D.Iterator1D.loc.ic = proj2D.proj1D.xCoord.size() - 2; + m_iterator.Iterator2D.Iterator1D.loc.x = proj2D.proj1D.xCoord[m_iterator.Iterator2D.Iterator1D.loc.ic+1]; + m_iterator.Iterator2D.Iterator1D.value = proj2D.proj1D.value[m_iterator.Iterator2D.Iterator1D.loc.iv]; + m_iterator.Iterator2D.Iterator1D.grid = &(proj2D.proj1D); + + //set the 2D iterator location + m_iterator.Iterator2D.loc.iv = proj2D.proj1D.value[m_iterator.Iterator2D.Iterator1D.loc.iv].to_value; + m_iterator.Iterator2D.loc.ic = proj2D.proj1D.value[m_iterator.Iterator2D.Iterator1D.loc.iv].to_coord; + m_iterator.Iterator2D.loc.y = proj2D.yCoord[m_iterator.Iterator2D.loc.ic]; + m_iterator.Iterator2D.value = proj2D.value[m_iterator.Iterator2D.loc.iv]; + m_iterator.Iterator2D.grid = &(proj2D); + + //set the 3D iterator location + m_iterator.loc.iv = proj2D.value[m_iterator.Iterator2D.loc.iv].to_value; + m_iterator.loc.ic = proj2D.value[m_iterator.Iterator2D.loc.iv].to_coord; + m_iterator.loc.z = zCoord[m_iterator.loc.ic]; + m_iterator.value = value[m_iterator.loc.iv]; + m_iterator.grid = this; + + m_iter_type = NPP; +} + +void rts_glRenderableDTGrid::iter_next_npp() +{ + //if we are at the end of a p-column + if(m_iterator.loc.iv == value.size() - 1 || //if we are at the end of the last p-column or + (m_iterator.Iterator2D.loc.iv != m_iterator.grid->proj2D.value.size() - 1 && + m_iterator.loc.iv == proj2D.value[m_iterator.Iterator2D.loc.iv + 1].to_value - 1)) //we are at the end of a p-column + { + iter_next_npx(m_iterator.Iterator2D); //increment the 2D iterator + m_iterator.loc.iv = proj2D.value[m_iterator.Iterator2D.loc.iv].to_value; + m_iterator.loc.ic = proj2D.value[m_iterator.Iterator2D.loc.iv].to_coord; + m_iterator.loc.z = zCoord[m_iterator.loc.ic]; + } + //if we are at the end of a connected component + else if(m_iterator.loc.z == zCoord[m_iterator.loc.ic+1]) + { + m_iterator.loc.iv++; + m_iterator.loc.ic+=2; + m_iterator.loc.z = zCoord[m_iterator.loc.ic]; + } + //else if we are in a p-column + else + { + m_iterator.loc.iv++; + m_iterator.loc.z++; + } + m_iterator.value = value[m_iterator.loc.iv]; +} + +void rts_glRenderableDTGrid::iter_next_ppn() +{ + //if we are at the beginning of a p-column + if(m_iterator.loc.z == zCoord[m_iterator.loc.ic] && + m_iterator.loc.ic == proj2D.value[m_iterator.Iterator2D.loc.iv].to_coord) + { + m_iterator.Iterator2D.increment(); //move to the next p-column + if(m_iterator.Iterator2D.loc.iv >= proj2D.value.size()) //return + return; + //now update the 3D locator + if(m_iterator.Iterator2D.loc.iv == proj2D.value.size() - 1) //if this is the last p-column + { + m_iterator.loc.iv = value.size() - 1; + m_iterator.loc.ic = zCoord.size() - 2; + m_iterator.loc.z = zCoord.back(); + } + else + { + m_iterator.loc.iv = proj2D.value[m_iterator.Iterator2D.loc.iv+1].to_value - 1; + m_iterator.loc.ic = proj2D.value[m_iterator.Iterator2D.loc.iv+1].to_coord - 2; + m_iterator.loc.z = zCoord[m_iterator.loc.ic + 1]; + } + } + //if we are at the beginning of a connected component + else if(m_iterator.loc.z == zCoord[m_iterator.loc.ic]) + { + m_iterator.loc.iv-=1; + m_iterator.loc.ic-=2; + m_iterator.loc.z = zCoord[m_iterator.loc.ic + 1]; + } + //if we're in the middle of a connected component + else + { + m_iterator.loc.iv--; + m_iterator.loc.z--; + } + m_iterator.value = value[m_iterator.loc.iv]; +} + +void rts_glRenderableDTGrid::iter_next_npx(rtsDTGrid2D::iterator &i2d) +{ + //if we are at the end of a p-column + if(i2d.loc.iv == i2d.grid->value.size() - 1 || //if this is the last p-column + (i2d.Iterator1D.loc.iv != i2d.grid->proj1D.value.size() - 1 && //we are not in the last p-column and + i2d.loc.iv == i2d.grid->proj1D.value[i2d.Iterator1D.loc.iv+1].to_value - 1)) + { + //if(i2d.Iterator1D.loc.iv == 0) //if it is the first p-column + // return; + i2d.Iterator1D.decrement(); //decrement the 1D iterator + //update the 2D locator + i2d.loc.iv = i2d.grid->proj1D.value[i2d.Iterator1D.loc.iv].to_value; + i2d.loc.ic = i2d.grid->proj1D.value[i2d.Iterator1D.loc.iv].to_coord; + i2d.loc.y = i2d.grid->yCoord[i2d.loc.ic]; + } + //if we are at the end of a connected component + else if(i2d.loc.y == i2d.grid->yCoord[i2d.loc.ic+1]) + { + i2d.loc.iv++; + i2d.loc.ic+=2; + i2d.loc.y = i2d.grid->yCoord[i2d.loc.ic]; + } + else + { + i2d.loc.iv++; + i2d.loc.y++; + } + //set value + i2d.value = i2d.grid->value[i2d.loc.iv]; +} + + +void rts_glRenderableDTGrid::iter_next() +{ + if(m_iter_type == PPP) + m_iterator.increment(); + if(m_iter_type == NNN) + m_iterator.decrement(); + if(m_iter_type == PPN) + iter_next_ppn(); + if(m_iter_type == NPP) + iter_next_npp(); +} +void rts_glRenderableDTGrid::RenderPoints(unsigned int size, float camera_x, float camera_y, float camera_z) +{ + /*This function renders a single point to the screen for each voxel in the + DT-Grid. + */ + //determine which directions to iterate + if(camera_x > 0) + { + if(camera_y > 0) + { + if(camera_z > 0) + { + //cout<<"+++"< 0) + { + //cout<<"+-+"< 0) + { + if(camera_z > 0) + { + //cout<<"-++"< 0) + { + //cout<<"--+"< +{ +private: + IteratorType m_iter_type; + rtsDTGrid3D::iterator m_iterator; + void init_iter_ppp(); + void init_iter_ppn(); + void iter_next_ppn(); + void init_iter_npp(); + void iter_next_npp(); + void init_iter_nnn(); + void iter_next_npx(rtsDTGrid2D::iterator &i2d); + void iter_next(); +public: + void RenderPoints(unsigned int size, float camera_x, float camera_y, float camera_z); + +}; + + +#endif \ No newline at end of file diff --git a/rts_glShaderObject.h b/rts_glShaderObject.h new file mode 100755 index 0000000..85a96c5 --- /dev/null +++ b/rts_glShaderObject.h @@ -0,0 +1,115 @@ +#ifndef RTS_GLSHADERS +#define RTS_GLSHADERS + +#include +//#include "windows.h" +#include +#include "rtsSourceCode.h" + +class rts_glShaderObject +{ +private: + void init() + { + id = 0; + compiled = false; + type = GL_FRAGMENT_SHADER; + } +public: + bool compiled; + GLenum type; + rtsSourceCode source; + GLuint id; + string log; + + rts_glShaderObject(GLenum type, const char* filename) + { + init(); //initialize the shader + SetType(type); //set the shader type + LoadSource(filename); //load the source code + } + rts_glShaderObject(GLenum type, rtsSourceCode sourceCode) + { + init(); //initialize the shader + SetType(type); //set the shader type + source = sourceCode; + } + rts_glShaderObject() + { + init(); + } + rts_glShaderObject(GLenum type) + { + init(); + SetType(type); + } + void LoadSource(const char* filename) + { + source = rtsSourceCode(filename); //get the shader source code + + } + void SetType(GLenum type) + { + if(id != 0) //if a shader currently exists, delete it + { + glDeleteShader(id); + id = 0; + } + type = type; + id = glCreateShader(type); //create a shader object + if(id == 0) //if a shader was not created, log an error + { + log = "Error getting shader ID from OpenGL"; + return; + } + } + void UploadSource() + { + //create the structure for the shader source code + GLsizei count = source.source.size(); + GLchar** code_string = new GLchar*[count]; + GLint* length = new GLint[count]; + for(int l = 0; l + +using namespace std; + +class rts_glShaderProgram +{ +private: + void get_uniforms() + { + GLint num_uniforms; + glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &num_uniforms); //get the number of uniform variables + GLint max_name_length; + glGetProgramiv(id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_length); //get the maximum uniform name length + GLchar* name_buffer = new GLchar[max_name_length]; //create a buffer to store the name + GLsizei length; //I'm not using these yet + GLint size; + GLenum type; //variable's data type + GLint location; //GPU location of the variable + for(int i=0; i shader_list; //list of opengl shaders + vector uniform_list; //list of active uniform variables + vector texture_list; //list of texture maps + + rts_glShaderProgram() + { + linked = false; + id = 0; + } + void AttachShader(rts_glShaderObject shader) + { + if(id == 0) + { + Init(); + } + if(shader.id == 0) //if the shader is invalid + { + log = "Shader is invalid"; + return; + } + + //attach the shader to the program + glAttachShader(id, shader.id); //attach the shader to the program in OpenGL + CHECK_OPENGL_ERROR + shader_list.push_back(shader); //push the shader onto our list for later access + } + //type = GL_FRAGMENT_SHADER or GL_VERTEX_SHADER + void AttachShader(GLenum type, const char* filename) + { + rts_glShaderObject shader(type, filename); + AttachShader(shader); + } + void AttachShader(GLenum type, rtsSourceCode source) + { + rts_glShaderObject shader(type, source); + AttachShader(shader); + } + void PrintLog() + { + cout<::iterator iter; + for(iter = shader_list.begin(); iter != shader_list.end(); iter++) + { + (*iter).Compile(); + //(*iter).PrintLog(); + } + } + void Link() + { + glLinkProgram(id); //link the current shader program + GLint link_status; //test to see if the link went alright + glGetProgramiv(id, GL_LINK_STATUS, &link_status); + if(link_status != GL_TRUE) + { + linked = false; + } + else + linked = true; + + GLsizei length; + GLchar buffer[1000]; + glGetProgramInfoLog(id, 1000, &length, buffer); + log = buffer; + + get_uniforms(); //create the list of active uniform variables + } + void BeginProgram() + { + CHECK_OPENGL_ERROR + if(id == 0) //if the program is invalid, return + { + log = "Invalid program, cannot use."; + return; + } + if(!linked) + { + cout<<"Shader Program used without being linked."< 0) + glActiveTexture(GL_TEXTURE0); + CHECK_OPENGL_ERROR + + //return to OpenGL default shading + glUseProgram(0); + CHECK_OPENGL_ERROR + } + void PrintUniforms() + { + cout<<"Shader Uniforms: "< +#include + +using namespace std; + +enum rtsUniformEnum {RTS_FLOAT, RTS_INT, RTS_BOOL, RTS_FLOAT_MATRIX}; + +///This class stores a single uniform variable for GLSL and is designed to be used by the rts_glShaderProgram class. +struct rts_glShaderUniform +{ +public: + string name; //the name of the variable + GLint location; //the location in the program + void* p_value; //pointer to the global data representing the value in main memory + GLenum type; //variable type (float, int, vec2, etc.) + //rtsUniformEnum rts_type; //type of variable in rts format + //unsigned int num; //the number of values required by the variable (1 for float, 2 for vec2, etc.) + string log; + + //void convert_type(GLenum gl_type); //converts the OpenGL data type to something useful for rts + void submit_to_gpu() + { + if(location < 0) + return; + if(p_value == NULL) + { + cout<<"Error in uniform address: "<(width, height, depth); //assign the texture size + //get_type(); //guess the type based on the size + texture_type = type; //set the type of texture + glEnable(texture_type); //enable the texture map + CHECK_OPENGL_ERROR + glBindTexture(texture_type, name); //bind the texture for editing + CHECK_OPENGL_ERROR + set_wrapping(); //set the texture wrapping parameters + CHECK_OPENGL_ERROR + glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, interpolation); //set filtering + CHECK_OPENGL_ERROR + glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, interpolation); + CHECK_OPENGL_ERROR + internal_format = internalformat; //set the number of components per pixel + pixel_format = format; //set the pixel format + data_type = datatype; //set the data type + SetBits(bits); //send the bits to the OpenGL driver + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //replace the specified vertex color + CHECK_OPENGL_ERROR + glDisable(texture_type); +} \ No newline at end of file diff --git a/rts_glTextureMap.h b/rts_glTextureMap.h new file mode 100755 index 0000000..9ab7736 --- /dev/null +++ b/rts_glTextureMap.h @@ -0,0 +1,260 @@ +#ifndef RTS_GLTEXTUREMAP_H +#define RTS_GLTEXTUREMAP_H + +#include +#include "rtsVector3d.h" +#include "CHECK_OPENGL_ERROR.h" +#include + +///This class stores an OpenGL texture map and is used by rts_glShaderProgram. +class rts_glTextureMap +{ +private: + void get_type() //guesses the texture type based on the size + { + if(size.y == 0) + texture_type = GL_TEXTURE_1D; + else if(size.z == 0) + texture_type = GL_TEXTURE_2D; + else + texture_type = GL_TEXTURE_3D; + } + void set_wrapping() //set the texture wrapping based on the dimensions + { + CHECK_OPENGL_ERROR + switch(texture_type) + { + case GL_TEXTURE_3D: + glTexParameteri(texture_type, GL_TEXTURE_WRAP_R_EXT, GL_REPEAT); + case GL_TEXTURE_2D: + glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + case GL_TEXTURE_1D: + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT); + break; + case GL_TEXTURE_RECTANGLE_ARB: + glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + break; + + default: + break; + } + CHECK_OPENGL_ERROR + } + //void set_bits(GLvoid* bits); +public: + vector3D size; //vector representing the size of the texture + GLuint name; //texture name assigned by OpenGL + GLenum texture_type; //1D, 2D, 3D + GLint internal_format; //number of components (ex. 4 for RGBA) + GLenum pixel_format; //type of data (RGBA, LUMINANCE) + GLenum data_type; //data type of the bits (float, int, etc.) + + //constructor + rts_glTextureMap() + { + name = 0; + } + + void BeginTexture() + { + glEnable(texture_type); + glBindTexture(texture_type, name); + CHECK_OPENGL_ERROR + } + void EndTexture() + { + glDisable(texture_type); + CHECK_OPENGL_ERROR + } + + ///Creates an OpenGL texture map. This function requires basic information about the texture map as well as a pointer to the bit data describing the texture. + void Init(GLvoid *bits, + GLenum type = GL_TEXTURE_2D, + GLsizei width = 256, + GLsizei height = 256, + GLsizei depth = 0, + GLint internalformat = 1, + GLenum format = GL_LUMINANCE, + GLenum datatype = GL_UNSIGNED_BYTE, + GLint interpolation = GL_LINEAR) + { + CHECK_OPENGL_ERROR + if(name != 0) + glDeleteTextures(1, &name); + + + CHECK_OPENGL_ERROR + if(datatype == GL_FLOAT) + { + glPixelStorei(GL_PACK_ALIGNMENT, 4); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); //I honestly don't know what this does but it fixes problems + } + else if(datatype == GL_UNSIGNED_BYTE) + { + //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + //glPixelStorei(GL_PACK_ALIGNMENT, 1); + } + else if(datatype == GL_UNSIGNED_SHORT) + { + //glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + //glPixelStorei(GL_PACK_ALIGNMENT, 2); + } + CHECK_OPENGL_ERROR + glGenTextures(1, &name); //get the texture name from OpenGL + //cout<<"OpenGL Name: "<(width, height, depth); //assign the texture size + //get_type(); //guess the type based on the size + texture_type = type; //set the type of texture + glEnable(texture_type); //enable the texture map + CHECK_OPENGL_ERROR + glBindTexture(texture_type, name); //bind the texture for editing + CHECK_OPENGL_ERROR + set_wrapping(); //set the texture wrapping parameters + CHECK_OPENGL_ERROR + glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, interpolation); //set filtering + CHECK_OPENGL_ERROR + glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, interpolation); + CHECK_OPENGL_ERROR + internal_format = internalformat; //set the number of components per pixel + pixel_format = format; //set the pixel format + data_type = datatype; //set the data type + SetBits(bits); //send the bits to the OpenGL driver + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //replace the specified vertex color + CHECK_OPENGL_ERROR + glDisable(texture_type); + + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + void Clean() + { + if(name != 0) + { + glDeleteTextures(1, &name); + CHECK_OPENGL_ERROR + name = 0; + } + } + void SetBits(GLvoid *bits) + { + glEnable(texture_type); //enable the texture map + CHECK_OPENGL_ERROR + glBindTexture(texture_type, name); + CHECK_OPENGL_ERROR + + switch(texture_type) + { + case GL_TEXTURE_3D: + glTexImage3D(texture_type, 0, internal_format, size.x, size.y, size.z, 0, pixel_format, data_type, bits); + CHECK_OPENGL_ERROR + break; + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE_ARB: + glTexImage2D(texture_type, 0, internal_format, size.x, size.y, 0, pixel_format, data_type, bits); + CHECK_OPENGL_ERROR + break; + case GL_TEXTURE_1D: + glTexImage1D(texture_type, 0, internal_format, size.x, 0, pixel_format, data_type, bits); + CHECK_OPENGL_ERROR + break; + default: + //glTexImage2D(texture_type, 0, internal_format, size.x, size.y, 0, pixel_format, data_type, bits); + break; + } + CHECK_OPENGL_ERROR + } + void ResetBits(GLvoid *bits) + { + glEnable(texture_type); //enable the texture map + CHECK_OPENGL_ERROR + glBindTexture(texture_type, name); + CHECK_OPENGL_ERROR + + switch(texture_type) + { + case GL_TEXTURE_3D: + //glTexImage3D(texture_type, 0, internal_format, size.x, size.y, size.z, 0, pixel_format, data_type, bits); + break; + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE_ARB: + glTexSubImage2D(texture_type, 0, 0, 0, size.x, size.y, pixel_format, data_type, bits); + CHECK_OPENGL_ERROR + break; + case GL_TEXTURE_1D: + //glTexImage1D(texture_type, 0, internal_format, size.x, 0, pixel_format, data_type, bits); + break; + default: + //glTexImage2D(texture_type, 0, internal_format, size.x, size.y, 0, pixel_format, data_type, bits); + break; + } + glDisable(texture_type); + CHECK_OPENGL_ERROR + } + void* GetBits(GLenum format, GLenum type) + { + //returns the texture data + + int components; + switch(format) + { + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + components = 1; + break; + case GL_LUMINANCE_ALPHA: + components = 2; + break; + case GL_RGB: + case GL_BGR: + components = 3; + break; + case GL_RGBA: + case GL_BGRA: + components = 4; + break; + } + + int type_size; + switch(type) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + type_size = sizeof(char); + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + type_size = sizeof(short); + break; + case GL_UNSIGNED_INT: + case GL_INT: + type_size = sizeof(int); + break; + case GL_FLOAT: + type_size = sizeof(float); + break; + } + + //allocate memory for the texture + void* result = malloc(components*type_size * size.x * size.y); + + BeginTexture(); + glGetTexImage(texture_type, 0, format, type, result); + + CHECK_OPENGL_ERROR + EndTexture(); + + + return result; + + } +}; + +#define RTS_UNKNOWN 0 + +#endif \ No newline at end of file diff --git a/rts_glTrueEyes.h b/rts_glTrueEyes.h new file mode 100755 index 0000000..1a8809e --- /dev/null +++ b/rts_glTrueEyes.h @@ -0,0 +1,304 @@ +#include +#include + +#include "rtsCamera.h" +#include "rtsSourceCode.h" +#include "rts_glShaderProgram.h" +using namespace std; + +#include + +class rts_glTrueEyes +{ + static int glut_window; + + static rts_glShaderProgram shader; + static string source_file; + static rtsCamera camera; + static int mouse_x; + static int mouse_y; + static float camera_pos[3]; + static float volume_size[3]; + static rts_glTextureMap volume; + + static bool zooming; + + static void DrawCube() + { + float sx = volume_size[0]/2; + float sy = volume_size[1]/2; + float sz = volume_size[2]/2; + float tx = volume_size[0]/2; + float ty = volume_size[1]/2; + float tz = volume_size[2]/2; + + glBegin(GL_QUADS); + glTexCoord3f(-tx, -ty, -tz); + glVertex3f(-sx, -sy, -sz); + glTexCoord3f(-tx, ty, -tz); + glVertex3f(-sx, sy, -sz); + glTexCoord3f(tx, ty, -tz); + glVertex3f(sx, sy, -sz); + glTexCoord3f(tx, -ty, -tz); + glVertex3f(sx, -sy, -sz); + + glTexCoord3f(-tx, -ty, tz); + glVertex3f(-sx, -sy, sz); + glTexCoord3f(-tx, ty, tz); + glVertex3f(-sx, sy, sz); + glTexCoord3f(tx, ty, tz); + glVertex3f(sx, sy, sz); + glTexCoord3f(tx, -ty, tz); + glVertex3f(sx, -sy, sz); + + glTexCoord3f(-tx, -ty, -tz); + glVertex3f(-sx, -sy, -sz); + glTexCoord3f(-tx, -ty, tz); + glVertex3f(-sx, -sy, sz); + glTexCoord3f(tx, -ty, tz); + glVertex3f(sx, -sy, sz); + glTexCoord3f(tx, -ty, -tz); + glVertex3f(sx, -sy, -sz); + + glTexCoord3f(-tx, ty, -tz); + glVertex3f(-sx, sy, -sz); + glTexCoord3f(-tx, ty, tz); + glVertex3f(-sx, sy, sz); + glTexCoord3f(tx, ty, tz); + glVertex3f(sx, sy, sz); + glTexCoord3f(tx, ty, -tz); + glVertex3f(sx, sy, -sz); + + glTexCoord3f(-tx, -ty, -tz); + glVertex3f(-sx, -sy, -sz); + glTexCoord3f(-tx, -ty, tz); + glVertex3f(-sx, -sy, sz); + glTexCoord3f(-tx, ty, tz); + glVertex3f(-sx, sy, sz); + glTexCoord3f(-tx, ty, -tz); + glVertex3f(-sx, sy, -sz); + + glTexCoord3f(tx, -ty, -tz); + glVertex3f(sx, -sy, -sz); + glTexCoord3f(tx, -ty, tz); + glVertex3f(sx, -sy, sz); + glTexCoord3f(tx, ty, tz); + glVertex3f(sx, sy, sz); + glTexCoord3f(tx, ty, -tz); + glVertex3f(sx, sy, -sz); + glEnd(); + } + + static void DisplayFunction() + { + + + //set up the viewport and projection + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); + float aspect_ratio = (float)glutGet(GLUT_WINDOW_WIDTH)/(float)glutGet(GLUT_WINDOW_HEIGHT); + gluPerspective(camera.getFOV(), aspect_ratio, 0.01, 10); + + //clear the screen + glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); + + + //set up the camera + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + point3D pos = camera.getPosition(); + vector3D up = camera.getUp(); + gluLookAt(pos.x, pos.y, pos.z, 0, 0, 0, up.x, up.y, up.z); + + //draw a cube + glColor3f(1.0, 0.0, 0.0); + shader.UpdateGlobalUniforms(); + shader.BeginProgram(); + DrawCube(); + shader.EndProgram(); + + glutSwapBuffers(); + } + static void IdleFunction() + { + glutPostRedisplay(); + } + + static void MouseDrag(int x, int y) + { + int dx = x - mouse_x; + int dy = y - mouse_y; + + if(zooming) + { + camera.Zoom(dy); + } + else + { + + camera.OrbitFocus(-dx*0.01, dy*0.01); + point3D pos = camera.getPosition(); + camera_pos[0] = pos.x; + camera_pos[1] = pos.y; + camera_pos[2] = pos.z; + } + + mouse_x = x; + mouse_y = y; + + glutPostRedisplay(); + + } + + static void MouseMove(int x, int y) + { + mouse_x = x; + mouse_y = y; + + } + static void KeyPress(unsigned char key, int x, int y) + { + //reload the shader + if(key == 'r' || key == 'R') + { + UpdateShader(); + + + } + + } + + static void MousePress(int button, int state, int x, int y) + { + if(state == GLUT_DOWN && button == GLUT_MIDDLE_BUTTON) + zooming = true; + else + zooming = false; + } + + static void UpdateShader() + { + //load the source code + shader.Clean(); + shader.AttachShader(GL_FRAGMENT_SHADER, source_file.c_str()); + + //compile the shader + shader.Compile(); + shader.PrintLog(); + shader.Link(); + shader.PrintLog(); + + if(!shader.linked) + { + cout<<"Error linking shader."< 0) + texture_volume.blacken(m_min_threshold); + if(m_max_threshold < 255) + texture_volume.whiten(m_max_threshold); + + + + //if we are optimizing the texture, make the dimensions a power-of-two + if(m_optimize) + { + PD.StartTimer(RESIZE_DATA); + //find the maximum dimension + unsigned int max_dimension = max(max(m_source.get_dimx(), m_source.get_dimy()), m_source.get_dimz()); + + unsigned int new_dimension = 2; + //calculate the new dimension + while(new_dimension < max_dimension) + new_dimension *= 2; + //resize the texture volume + texture_volume.resize_canvas(new_dimension, new_dimension, new_dimension); + PD.EndTimer(RESIZE_DATA); + } + + //apply the new image to the texture + glBindTexture(GL_TEXTURE_3D, m_volume_texture); + unsigned int dimx = texture_volume.get_dimx(); + unsigned int dimy = texture_volume.get_dimy(); + unsigned int dimz = texture_volume.get_dimz(); + m_texture_size = vector3D((double)dimx, (double)dimy, (double)dimz); + unsigned char* bits = texture_volume.get_bits(); + glTexImage3D(GL_TEXTURE_3D, 0, GL_ALPHA8, dimx, dimy, dimz, 0, GL_ALPHA, + GL_UNSIGNED_BYTE, bits); + + PD.EndTimer(LOAD_TEXTURE); + +} + + + + diff --git a/rts_glVolumeViewer.h b/rts_glVolumeViewer.h new file mode 100755 index 0000000..b40344a --- /dev/null +++ b/rts_glVolumeViewer.h @@ -0,0 +1,67 @@ +#ifndef RTS_GLVOLUMEVIEWER_H +#define RTS_GLVOLUMEVIEWER_H + +#include +#include +#include +#include +//#include +#include +#include +//#include +#include "rtsMath.h" +#include "rtsVolume.h" +#include "rts_glUtilities.h" + +class rts_glVolumeViewer +{ +private: + + rtsVolume m_source; + GLuint m_volume_texture; + vector3D m_texture_size; //size of the volume being viewed (in voxels) + vector3D m_voxel_size; + bool m_optimize; //optimization flag (use more texture space for faster viz) + + point3D m_p; //position of the volume (0,0,0) corner in space + vector3D m_dimensions; + + double m_alpha_scale; + unsigned char m_min_threshold; //min and max thresholds to be displayed + unsigned char m_max_threshold; + + unsigned int m_num_planes; + + GLuint m_dl_planes; //planes display list + + + double m_inner_radius; //radius of the inscribed sphere + double m_outer_radius; //radius of the circumscribed sphere + + void m_draw_plane(point3D p, vector3D n, vector3D u); //draws a camera-oriented plane at point with normal n + void m_load_texture(); + + +public: + rts_glVolumeViewer(); + //rts_glVolumeViewer(rtsVolume volume_data, point3D position); + rts_glVolumeViewer(rtsVolume volume_data, + point3D position, + vector3D voxel_size); + void SetSize(float x, float y, float z); + void SetVoxelSize(float x, float y, float z); + vector3D GetSize(); + vector3D GetVoxelSize(); + void RenderBoundingBox(); + void RenderCameraSlice(point3D eye_point, vector3D camera_up, float slice_number = 0.0); + void RenderVolume(point3D eye_point, vector3D camera_up); + void SetAlphaScale(double scale){m_alpha_scale = scale;} + void SetNumPlanes(unsigned int planes); + void SetThreshold(unsigned char lower, unsigned char upper); + void Optimize(bool flag); + void Invert(); +}; + + + +#endif \ No newline at end of file diff --git a/rts_glutRenderWindow.h b/rts_glutRenderWindow.h new file mode 100755 index 0000000..aa97a19 --- /dev/null +++ b/rts_glutRenderWindow.h @@ -0,0 +1,155 @@ +#include +#include +#include "rtsQuaternion.h" +#include "rtsCamera.h" + +float d_angle = 0.05; + +rtsCamera rts_glut_camera; +unsigned int mouse_x; +unsigned int mouse_y; +int mouse_button; + + +//user display function pointer +void (*UserDisplay)(void); + + + +/*void KeyboardFunction(unsigned char key, int x, int y) +{ + if(key == 27) + exit(0); + +}*/ + +/*void SpecialKeys(int key, int x, int y) +{ + rtsQuaternion new_rotation; + + if(key == GLUT_KEY_UP) + rts_glut_camera.OrbitFocus(0, d_angle); + if(key == GLUT_KEY_DOWN) + rts_glut_camera.OrbitFocus(0, -d_angle); + if(key == GLUT_KEY_LEFT) + rts_glut_camera.OrbitFocus(d_angle, 0.0); + if(key == GLUT_KEY_RIGHT) + rts_glut_camera.OrbitFocus(-d_angle, 0.0); +}*/ + +void MouseDrag(int x, int y) +{ + int dx = x - mouse_x; + int dy = y - mouse_y; + + if(mouse_button == GLUT_LEFT_BUTTON) + rts_glut_camera.OrbitFocus(-dx*0.01, dy*0.01); + else if(mouse_button == GLUT_MIDDLE_BUTTON) + rts_glut_camera.Zoom(dy*rts_glut_camera.getFOV()/60.0); + + mouse_x = x; + mouse_y = y; + +} + +void MouseMove(int x, int y) +{ + mouse_x = x; + mouse_y = y; +} + +void MouseClick(int button, int state, int x, int y) +{ + if(state == GLUT_DOWN) + mouse_button = button; + + +} + +void IdleFunction() +{ + glutPostRedisplay(); +} + +void RenderCamera() +{ + //set viewport + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); + + //compute the aspect ratio + float aspect_ratio = (float)glutGet(GLUT_WINDOW_WIDTH)/(float)glutGet(GLUT_WINDOW_HEIGHT); + gluPerspective(rts_glut_camera.getFOV(), aspect_ratio, 0.01, 10.0); + + //render the camera + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + point3D camera_position = rts_glut_camera.getPosition(); + vector3D camera_up = rts_glut_camera.getUp(); + gluLookAt(camera_position.x, + camera_position.y, + camera_position.z, + 0.0, 0.0, 0.0, + camera_up.x, + camera_up.y, + camera_up.z); +} + +void rts_glutInitialize(const char* WindowName, int width = 1024, int height = 768) +{ + char *myargv [1]; + int myargc=1; + myargv [0]=strdup ("AppName"); + glutInit(&myargc, myargv); + + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); + glutInitWindowSize(width, height); + glutInitWindowPosition(200,0); + glutCreateWindow(WindowName); + + //initialize GLEW + GLenum err = glewInit(); + if(err != GLEW_OK) + fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); + if (!glewIsSupported("GL_VERSION_2_0")) + { + printf("OpenGL 2.0 not supported\n"); + //exit(1); + } + glEnable(GL_DEPTH_TEST); + + glClearColor(1.0, 1.0, 1.0, 0.0); + + rts_glut_camera.setPosition(0.0, 0.0, -1.0); + rts_glut_camera.setFOV(60); + rts_glut_camera.LookAt(0.0, 0.0, 0.0, 0.0, 1.0, 0.0); +} + +void DisplayFunction() +{ + RenderCamera(); + UserDisplay(); + glutSwapBuffers(); +} + +void rts_glutStart(void (*display_func)(void)) +{ + //glutSpecialFunc(SpecialKeys); + //glutKeyboardFunc(KeyboardFunction); + glutDisplayFunc(DisplayFunction); + glutMotionFunc(MouseDrag); + glutMouseFunc(MouseClick); + glutPassiveMotionFunc(MouseMove); + UserDisplay = display_func; + glutIdleFunc(IdleFunction); + + + + //glutReshapeFunc(ReshapeFunction); + //glutMouseFunc(MouseFunction); + //glutMotionFunc(MotionFunction); + glutMainLoop(); + +} diff --git a/rts_itkFunctions.h b/rts_itkFunctions.h new file mode 100755 index 0000000..b95669a --- /dev/null +++ b/rts_itkFunctions.h @@ -0,0 +1,168 @@ +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkRAWImageIO.h" +#include "itkImageRegionIteratorWithIndex.h" + +typedef itk::Image VOLType; + +VOLType::Pointer rts_itkNewVOL(int x, int y, int z) +{ + //Create a new image and allocate the desired amount of space + //typedef itk::Image ImageType; + VOLType::Pointer result = VOLType::New(); + VOLType::RegionType region; + VOLType::SizeType size = {x, y, z}; + region.SetSize(size); + VOLType::IndexType index = {0, 0, 0}; + region.SetIndex(index); + result->SetRegions(region); + result->Allocate(); + + return result; + +} + +VOLType::Pointer rts_itkLoadVOL(const char* filename, unsigned int max_slices = 512) +{ + //first load the header information + ifstream infile(filename, ios::in | ios::binary); //create the files stream + if(!infile) + return VOLType::New(); + + unsigned int size_x, size_y, size_z; //create variables to store the size of the data set + //load the dimensions of the data set + infile.read((char*)&size_x, sizeof(int)); //load the file header + infile.read((char*)&size_y, sizeof(int)); + infile.read((char*)&size_z, sizeof(int)); + + //close the file + infile.close(); + + + VOLType::Pointer volume; + + + //create the reader + typedef itk::ImageFileReader ReaderType; + typedef itk::RawImageIO RawType; + + ReaderType::Pointer reader = ReaderType::New(); + RawType::Pointer rawIO = RawType::New(); + + + + reader->SetImageIO(rawIO); + reader->SetFileName(filename); + + //set the raw IO parameters + rawIO->SetFileTypeToBinary(); + + + //set the format of the RAW file + rawIO->SetHeaderSize(12); + rawIO->SetDimensions(0, size_x); + rawIO->SetDimensions(1, size_y); + + if(size_z < max_slices) + rawIO->SetDimensions(2, size_z); + else + rawIO->SetDimensions(2, max_slices); + + //read the file + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(); + + return volume; +} +VOLType::Pointer rts_itkLoadRAW(const char* filename, unsigned int size_x, unsigned int size_y, unsigned int size_z) +{ + //first load the header information + ifstream infile(filename, ios::in | ios::binary); //create the files stream + if(!infile) + return VOLType::New(); + + + + //close the file + infile.close(); + + + VOLType::Pointer volume; + + + //create the reader + typedef itk::ImageFileReader ReaderType; + typedef itk::RawImageIO RawType; + + ReaderType::Pointer reader = ReaderType::New(); + RawType::Pointer rawIO = RawType::New(); + + + + reader->SetImageIO(rawIO); + reader->SetFileName(filename); + + //set the raw IO parameters + rawIO->SetFileTypeToBinary(); + + + //set the format of the RAW file + rawIO->SetHeaderSize(0); + rawIO->SetDimensions(0, size_x); + rawIO->SetDimensions(1, size_y); + rawIO->SetDimensions(2, size_z); + + + //read the file + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(); + + return volume; +} +void rts_itkSaveVOL(VOLType::Pointer itk_image, const char* filename) +{ + typedef itk::ImageRegionIteratorWithIndex IteratorType; + IteratorType i(itk_image, itk_image->GetLargestPossibleRegion()); + + //create variables for size and position + VOLType::IndexType index; + VOLType::SizeType size; + //get the volume size + size = itk_image->GetLargestPossibleRegion().GetSize(); + unsigned char* buffer = new unsigned char[size[0]*size[1]*size[2]]; + + for(i.GoToBegin(); !i.IsAtEnd(); ++i) + { + index = i.GetIndex(); + buffer[index[0] + size[0] * (index[1] + index[2] * size[1])] = i.Get(); + } + + + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume size to the file + outfile.write((char*)&size[0], sizeof(int)); + outfile.write((char*)&size[1], sizeof(int)); + outfile.write((char*)&size[2], sizeof(int)); + + outfile.write((char*)buffer, sizeof(char)*size[0]*size[1]*size[2]); + outfile.close(); +} \ No newline at end of file diff --git a/rts_itkImage.h b/rts_itkImage.h new file mode 100755 index 0000000..7e8747d --- /dev/null +++ b/rts_itkImage.h @@ -0,0 +1,334 @@ +#ifndef _RTS_ITK_IMAGE_H +#define _RTS_ITK_IMAGE_H + +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itkCastImageFilter.h" +#include "itkRescaleIntensityImageFilter.h" +#include "rtsDTGrid2D.h" + +#include + +using namespace std; + + + +template +class rts_itkImage +{ +public: + typedef itk::Image ITKImageType; + typedef typename ITKImageType::Pointer ITKPointerType; + ITKPointerType image_source; + +public: + rts_itkImage(); + rts_itkImage(int res_x, int res_y); + void Allocate(int res_x, int res_y); + void LoadImage(string filename); + void LoadRAW(int header_size, int res_x, int res_y, string filename); + void SaveImage(string filename); + void SaveRAW(string filename); + void CastAndSaveImage(string filename); + void RescaleImage(T min, T max); + void InsertDTGrid(rtsDTGrid2D* grid, bool debug = 0); + T* GetPointer(); + rts_itkImage SubImage(int px, int py, int sx, int sy); + + void SetPixel(int x, int y, T value); + T GetPixel(int x, int y); + + //element-wise operators + rts_itkImage operator+(T rhs); + + int DimX(){return image_source->GetLargestPossibleRegion().GetSize()[0];} + int DimY(){return image_source->GetLargestPossibleRegion().GetSize()[1];} + + +}; + +template +rts_itkImage rts_itkImage::operator+(T rhs) +{ + rts_itkImage result(DimX(), DimY()); + + int x, y; + for(x=0; x +void rts_itkImage::SetPixel(int x, int y, T value) +{ + ITKImageType::IndexType index; + index[0] = x; + index[1] = y; + image_source->SetPixel(index, value); +} + +template +T rts_itkImage::GetPixel(int x, int y) +{ + ITKImageType::IndexType index; + index[0] = x; + index[1] = y; + return image_source->GetPixel(index); +} + +template +rts_itkImage::rts_itkImage() +{ + if(image_source.IsNotNull()) + image_source = NULL; + image_source = ITKImageType::New(); +} + +template +rts_itkImage::rts_itkImage(int res_x, int res_y) +{ + Allocate(res_x, res_y); +} + +template +void rts_itkImage::Allocate(int res_x, int res_y) +{ + if(image_source.IsNotNull()) + { + image_source = NULL; + } + + image_source = ITKImageType::New(); + + ITKImageType::RegionType region; + ITKImageType::SizeType size; + size[0] = res_x; + size[1] = res_y; + + region.SetSize(size); + image_source->SetRegions(region); + + try + { + image_source->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +rts_itkImage rts_itkImage::SubImage(int px, int py, int sx, int sy) +{ + /*This function returns the sub-volume specified by a corner point and size*/ + + //first make sure that the sub-volume is contained within the image + if(px < 0) {sx += px; px = 0;} + if(py < 0) {sy += py; py = 0;} + if(px >= DimX()) px = DimX() - 1; + if(py >= DimY()) py = DimY() - 1; + if(px + sx > DimX()) sx = DimX() - px - 1; + if(py + sy > DimY()) sy = DimY() - py - 1; + + cout< destination(sx, sy); + + //get an iterator for the destination volume + itk::ImageRegionIterator d(destination.image_source, destination.image_source->GetLargestPossibleRegion()); + + //get an iterator for the source region + ITKImageType::RegionType region; + ITKImageType::IndexType index; + ITKImageType::SizeType size; + index[0] = px; index[1] = py; + size[0] = sx; size[1] = sy; + region.SetIndex(index); + region.SetSize(size); + itk::ImageRegionIterator s(image_source, region); + + //copy the data from source region to destination volume + for(s.GoToBegin(), d.GoToBegin(); + !s.IsAtEnd(); + s++, d++) + d.Set(s.Get()); + + return destination; + +} + +template +T* rts_itkImage::GetPointer() +{ + return image_source->GetBufferPointer(); +} + +template +void rts_itkImage::LoadImage(string filename) +{ + typedef itk::ImageFileReader ReaderType; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filename.c_str()); + image_source = reader->GetOutput(); + + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkImage::LoadRAW(int header_size, int size_x, + int size_y, string filename) +{ + Allocate(size_x, size_y); + + + ifstream infile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!infile) + return; + //first read the header + char* header = new char[header_size]; + infile.read((char*)header, header_size); + + //now read the actual data + infile.read((char*)image_source->GetBufferPointer(), DimX()*DimY()*sizeof(T)); + + infile.close(); +} + +template +void rts_itkImage::SaveImage(string filename) +{ + typedef itk::ImageFileWriter WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(filename.c_str()); + writer->SetInput(image_source); + + try + { + writer->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkImage::SaveRAW(string filename) +{ + ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!outfile) + return; + + outfile.write((char*)image_source->GetBufferPointer(), DimX()*DimY()*sizeof(T)); + outfile.close(); +} + +template +void rts_itkImage::CastAndSaveImage(string filename) +{ + //create the destination image + typedef itk::Image DestinationType; + DestinationType::Pointer dest_image = DestinationType::New(); + + //create the casting filter + typedef itk::CastImageFilter CastFilterType; + CastFilterType::Pointer castFilter = CastFilterType::New(); + castFilter->SetInput(image_source); + + + //cast the current image + dest_image = castFilter->GetOutput(); + + //save the result + typedef itk::ImageFileWriter WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(filename.c_str()); + writer->SetInput(dest_image); + + try + { + writer->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkImage::RescaleImage(T min_v, T max_v) +{ + typedef itk::RescaleIntensityImageFilter RescaleFilter; + RescaleFilter::Pointer rescaleFilter = RescaleFilter::New(); + rescaleFilter->SetInput(image_source); + rescaleFilter->SetOutputMinimum(min_v); + rescaleFilter->SetOutputMaximum(max_v); + image_source = rescaleFilter->GetOutput(); + rescaleFilter->Update(); +} + +template +void rts_itkImage::InsertDTGrid(rtsDTGrid2D* grid, bool debug = false) +{ + //find the extents of the DT Grid + int min_x, min_y, max_x, max_y; + grid->getBounds(min_x, min_y, max_x, max_y); + + //allocate the appropriate amount of space + ITKImageType::RegionType region; + ITKImageType::SizeType size; + size[0] = (max_x - min_x) + 1; + size[1] = (max_y - min_y) + 1; + region.SetSize(size); + image_source->SetRegions(region); + + try + { + image_source->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<FillBuffer(grid->background); + + //copy values from the DT Grid to the image + ITKImageType::IndexType index; //create an image index + rtsDTGrid2D::iterator i; //create an iterator + + for(i = grid->begin(); i!= grid->after(); i++) + { + index[0] = i.X1() - min_x; + index[1] = i.X2() - min_y; + image_source->SetPixel(index, i.Value()); + + //cout< +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itkRawImageIO.h" +#include "itkImageRegionIterator.h" +#include +#include "rtsFilename.h" +#include "rtsDTGrid3D.h" +using namespace std; + +#include "itkRescaleIntensityImageFilter.h" + +#include "rts_itkImage.h" + +void rtsProgressBar(int percent); + +template class rts_itkVolume +{ +public: + typedef int uint; + typedef itk::Image ITKVolumeType; + typedef typename ITKVolumeType::Pointer PointerType; + typedef itk::Image ITKSliceType; + + //typedef itk::Image ITKVolumeType; +private: + //pointer to the data + PointerType imageData; + + char* UnicodeToANSI(wchar_t* unicodestr) + { + int a = wcslen(unicodestr)+1; + char *ansistr = new char[a]; + ::WideCharToMultiByte(CP_ACP, + 0, + unicodestr, + -1, + ansistr, + a, + NULL, + NULL); + return ansistr; + + } + + BSTR ANSIToUnicode(const char* ansistr) + { + /*On a side note: This BSTR crap isn't the way to go. + Try to use wchar_t (Unicode) where possible. Already changed it in + the above function because it was causing a bug.*/ + + int a = strlen(ansistr); + BSTR unicodestr = SysAllocStringLen(NULL, a); + ::MultiByteToWideChar(CP_ACP, 0, ansistr, a, unicodestr, a); + return unicodestr; + } + +public: + //construct an implicit function with a size of 1 + rts_itkVolume(); ///GetBufferPointer();} + T GetMin(); + T GetMax(); + + void SetITKPointer(PointerType pointer){imageData = pointer;} + uint DimX(){return imageData->GetLargestPossibleRegion().GetSize()[0];} + uint DimY(){return imageData->GetLargestPossibleRegion().GetSize()[1];} + uint DimZ(){return imageData->GetLargestPossibleRegion().GetSize()[2];} + + float VoxelSizeX(){return imageData->GetSpacing()[0];} + float VoxelSizeY(){return imageData->GetSpacing()[1];} + float VoxelSizeZ(){return imageData->GetSpacing()[2];} + void SetPixel(uint x, uint y, uint z, T value); + void SetSlice(rts_itkImage image, int slice); + T GetPixel(uint x, uint y, uint z); + rts_itkImage GetSlice(int slice); + rts_itkVolume SubVolume(uint px, uint py, uint pz, uint sx, uint sy, uint sz); + + //mathematica operations + T operator=(T rhs); + rts_itkVolume operator-(T rhs); + rts_itkVolume operator+(T rhs); + rts_itkVolume operator-(rts_itkVolume rhs); + + void Print(ostream &os); + + //simple data processing + void Rescale(T new_min, T new_max); + void Binary(T threshold, T true_value); ///* grid, bool debug = false); +}; + +template +rts_itkVolume rts_itkVolume::SubVolume(uint px, uint py, uint pz, uint sx, uint sy, uint sz) +{ + /*This function returns the sub-volume specified by a corner point and size*/ + + //first make sure that the sub-volume is contained within the image + if(px < 0) {sx += px; px = 0;} + if(py < 0) {sy += py; py = 0;} + if(pz < 0) {sz += pz; pz = 0;} + if(px >= DimX()) px = DimX() - 1; + if(py >= DimY()) py = DimY() - 1; + if(pz >= DimZ()) pz = DimZ() - 1; + if(px + sx > DimX()) sx = DimX() - px - 1; + if(py + sy > DimY()) sy = DimY() - py - 1; + if(pz + sz > DimZ()) sz = DimZ() - pz - 1; + + //cout< d(destination.imageData, destination.imageData->GetLargestPossibleRegion()); + + //get an iterator for the source region + ITKVolumeType::RegionType region; + ITKVolumeType::IndexType index; + ITKVolumeType::SizeType size; + index[0] = px; index[1] = py; index[2] = pz; + size[0] = sx; size[1] = sy; size[2] = sz; + region.SetIndex(index); + region.SetSize(size); + itk::ImageRegionIterator s(imageData, region); + + //copy the data from source region to destination volume + for(s.GoToBegin(), d.GoToBegin(); + !s.IsAtEnd(); + s++, d++) + d.Set(s.Get()); + + return destination; + +} + +template +T rts_itkVolume::operator=(T rhs) +{ + /*itk::ImageRegionIterator i(imageData, imageData->GetLargestPossibleRegion()); + + for(i.GoToBegin(); !i.IsAtEnd(); i++) + i.Set(rhs); +*/ + imageData->FillBuffer(rhs); + return rhs; +} +template +rts_itkVolume rts_itkVolume::operator-(T rhs) +{ + rts_itkVolume result(DimX(), DimY(), DimZ()); + + itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); + itk::ImageRegionIterator r(imageData, imageData->GetLargestPossibleRegion()); + + for(r.GoToBegin(), w.GoToBegin(); !r.IsAtEnd(); r++, w++) + w.Set(r.Get() - rhs); + + return result; +} + +template +rts_itkVolume rts_itkVolume::operator+(T rhs) +{ + rts_itkVolume result(DimX(), DimY(), DimZ()); + + itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); + itk::ImageRegionIterator r(imageData, imageData->GetLargestPossibleRegion()); + + for(r.GoToBegin(), w.GoToBegin(); !r.IsAtEnd(); r++, w++) + w.Set(r.Get() + rhs); + + return result; +} + +template +rts_itkVolume rts_itkVolume::operator-(rts_itkVolume rhs) +{ + rts_itkVolume result(DimX(), DimY(), DimZ()); + + itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); + itk::ImageRegionIterator r(rhs.imageData, rhs.imageData->GetLargestPossibleRegion()); + itk::ImageRegionIterator l(imageData, imageData->GetLargestPossibleRegion()); + + for(r.GoToBegin(), l.GoToBegin(), w.GoToBegin(); + !r.IsAtEnd(); + r++, l++, w++) + w.Set(l.Get() - r.Get()); + + return result; +} + +template +void rts_itkVolume::Print(ostream &os) +{ + ITKVolumeType::SizeType size; + size = imageData->GetLargestPossibleRegion().GetSize(); + + int x, y, z; + for(z=0; z +rts_itkVolume::rts_itkVolume() +{ + imageData = ITKVolumeType::New(); +} + +template +rts_itkVolume::rts_itkVolume(uint res_x, uint res_y, uint res_z) +{ + imageData = ITKVolumeType::New(); + + itk::Image::RegionType region; + itk::Image::SizeType size; + size[0] = res_x; + size[1] = res_y; + size[2] = res_z; + + region.SetSize(size); + imageData->SetRegions(region); + + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkVolume::Init(uint res_x, uint res_y, uint res_z) +{ + itk::Image::RegionType region; + itk::Image::SizeType size; + size[0] = res_x; + size[1] = res_y; + size[2] = res_z; + + region.SetSize(size); + imageData->SetRegions(region); + + + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkVolume::SetSpacing(float voxel_x, float voxel_y, float voxel_z) +{ + float spacing[3]; + spacing[0] = voxel_x; spacing[1]= voxel_y; spacing[2] = voxel_z; + imageData->SetSpacing(spacing); +} + + +template +inline T rts_itkVolume::GetPixel(uint x, uint y, uint z) +{ + T result; + if(x < 0 || x >= DimX() || y < 0 || y >= DimY() || z < 0 || z >= DimZ()) + { + memset(&result, 0, sizeof(T)); + return result; + } + + itk::Image::IndexType index; + index[0] = x; index[1] = y; index[2] = z; + return imageData->GetPixel(index); +} + +template +inline T rts_itkVolume::GetMin() +{ + int ix, iy, iz; + T currentMin = GetPixel(0, 0, 0); + T n; + for(ix=0; ix +inline T rts_itkVolume::GetMax() +{ + int ix, iy, iz; + T currentMax = GetPixel(0, 0, 0); + T n; + for(ix=0; ix currentMax) + currentMax = n; + } + return currentMax; +} + +template +inline T rts_itkVolume::operator ()(uint x, uint y, uint z) +{ + return GetPixel(x, y, z); +} + + + +template +void rts_itkVolume::LoadRAW(uint header_size, uint size_x, + uint size_y, uint size_z, string filename) +{ + ITKVolumeType::RegionType region; + ITKVolumeType::SizeType size; + size[0] = size_x; + size[1] = size_y; + size[2] = size_z; + region.SetSize(size); + imageData->SetRegions(region); + + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + + infile.close(); +} + +template +void rts_itkVolume::LoadRAV(string filename) +{ + + //open the file + ifstream infile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!infile) + return; + + //first read the header + int dimx, dimy, dimz, bytesize; + infile.read((char*)&dimx, sizeof(int)); + infile.read((char*)&dimy, sizeof(int)); + infile.read((char*)&dimz, sizeof(int)); + infile.read((char*)&bytesize, sizeof(int)); + + //allocate space for the image + ITKVolumeType::RegionType region; + ITKVolumeType::SizeType size; + size[0] = dimx; + size[1] = dimy; + size[2] = dimz; + region.SetSize(size); + imageData->SetRegions(region); + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + + infile.close(); +} + +template +void rts_itkVolume::LoadVOL(string filename) +{ + + //open the file + ifstream infile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!infile) + return; + + //first read the header + int dimx, dimy, dimz, bytesize; + infile.read((char*)&dimx, sizeof(int)); + infile.read((char*)&dimy, sizeof(int)); + infile.read((char*)&dimz, sizeof(int)); + + //allocate space for the image + ITKVolumeType::RegionType region; + ITKVolumeType::SizeType size; + size[0] = dimx; + size[1] = dimy; + size[2] = dimz; + region.SetSize(size); + imageData->SetRegions(region); + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + + infile.close(); +} + +template +void rts_itkVolume::LoadStack(string directory, string filename_mask, int max_files = -1) +{ + /*Load a list of file names based on the user-specified mask*/ + //create the complete mask + if(directory[directory.size() - 1] != '/') + directory += '/'; + + string full_mask = directory; + full_mask += filename_mask; + + //create a temporary vector to store the file names + vector fileList; + //create a handle for the search + HANDLE search_handle; + WIN32_FIND_DATA found_data; + + //start the search + BSTR unicodestr = ANSIToUnicode(full_mask.c_str()); + search_handle = FindFirstFile(unicodestr, &found_data); + ::SysFreeString(unicodestr); + + //if there are no files, return + if(search_handle == INVALID_HANDLE_VALUE) + return; + + string new_file; + char* ansistr = UnicodeToANSI(found_data.cFileName); + //char* ansistr = (char*)found_data.cFileName; + //save the first filename + new_file = directory; + new_file += ansistr; + fileList.push_back(new_file); + delete[] ansistr; + + //now loop through the rest of the files + while(FindNextFile(search_handle, &found_data)) + { + char* ansistr = UnicodeToANSI(found_data.cFileName); + new_file = directory; + new_file += ansistr; + //cout< ReaderType; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(fileList[0].getString()); + ITKSliceType::Pointer image = reader->GetOutput(); + + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<(fileList.size(), max_files); + cout<<"Loading: "<GetLargestPossibleRegion().GetSize(); //get the slice size + ITKVolumeType::SizeType volSize; //compute the volume size + volSize[0] = size[0]; + volSize[1] = size[1]; + volSize[2] = max_files; + + imageData = ITKVolumeType::New(); //create the volume + ITKVolumeType::RegionType region; + region.SetSize(volSize); + imageData->SetRegions(region); + imageData->Allocate(); //allocate space + + + + for(i=0; iSetFileName(fileList[i].getString()); + ITKSliceType::Pointer slice = reader->GetOutput(); + reader->Update(); + InsertSlice(i, slice); + //cout< +void rts_itkVolume::LoadSlice(string filename, int slice) +{ + //load the specified image + typedef itk::ImageFileReader ReaderType; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filename.c_str()); + ITKSliceType::Pointer image = reader->GetOutput(); + + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +rts_itkImage rts_itkVolume::GetSlice(int slice) +{ + //create a new image + rts_itkImage outSlice(DimX(), DimY()); + + int x, y; + for(x=0; x +void rts_itkVolume::SetSlice(rts_itkImage image, int slice) +{ + int x, y; + for(x=0; x +void rts_itkVolume::SaveRAV(string filename) +{ + ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!outfile) + return; + + int dimx = DimX(); + int dimy = DimY(); + int dimz = DimZ(); + int bytesize = sizeof(T); + + outfile.write((char*)&dimx, sizeof(int)); + outfile.write((char*)&dimy, sizeof(int)); + outfile.write((char*)&dimz, sizeof(int)); + outfile.write((char*)&bytesize, sizeof(int)); + + outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + outfile.close(); + +} + +template +void rts_itkVolume::SaveVOL(string filename) +{ + ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!outfile) + return; + + int dimx = DimX(); + int dimy = DimY(); + int dimz = DimZ(); + + outfile.write((char*)&dimx, sizeof(int)); + outfile.write((char*)&dimy, sizeof(int)); + outfile.write((char*)&dimz, sizeof(int)); + + outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + outfile.close(); + +} + +template +void rts_itkVolume::InsertSlice(uint z_position, typename ITKSliceType::Pointer slice) +{ + itk::Image::SizeType size = slice->GetLargestPossibleRegion().GetSize(); + itk::Image::IndexType index; + int x, y; + for(x=0; xGetPixel(index)); + } + + + +} + +template +void rts_itkVolume::SaveRAW(string filename) +{ + ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!outfile) + return; + + outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + outfile.close(); +} + +template +void rts_itkVolume::SetPixel(uint x, uint y, uint z, T value) +{ + ITKVolumeType::IndexType index; + index[0] = x; + index[1] = y; + index[2] = z; + imageData->SetPixel(index, value); +} + +template +void rts_itkVolume::Rescale(T new_min, T new_max) +{ + typedef itk::RescaleIntensityImageFilter RescaleFilterType; + RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New(); + rescaleFilter->SetOutputMinimum(new_min); + rescaleFilter->SetOutputMaximum(new_max); + rescaleFilter->SetInput(imageData); + rescaleFilter->Update(); + + imageData = rescaleFilter->GetOutput(); +} + +template +void rts_itkVolume::Binary(T threshold, T true_value) +{ + /** + This function converts an implicit function into a binary or characteristic function describing the solid represented by the level + set at isovalue "threshold". All values below threshold are set to zero while all values above threshold are set to the specified + "true_value". In order to use this function, the data type T must be able to be set to 0. + **/ + int max_index = DimX() * DimY() * DimZ(); //find the size of the data array + int i; + T* ptrBits = imageData->GetBufferPointer(); + for(i=0; i= threshold) + ptrBits[i] = true_value; + else + ptrBits[i] = 0; +} + + +template +void rts_itkVolume::InsertDTGrid(rtsDTGrid3D* grid, bool debug = false) +{ + //find the extents of the DT Grid + int min_x, min_y, min_z, max_x, max_y, max_z; + grid->getBounds(min_x, min_y, min_z, max_x, max_y, max_z); + + //allocate the appropriate amount of space + ITKVolumeType::RegionType region; + ITKVolumeType::SizeType size; + size[0] = (max_x - min_x) + 1; + size[1] = (max_y - min_y) + 1; + size[2] = (max_z - min_z) + 1; + region.SetSize(size); + imageData->SetRegions(region); + + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<FillBuffer(grid->background); + + //copy values from the DT Grid to the image + ITKVolumeType::IndexType index; //create an image index + rtsDTGrid3D::iterator i; //create an iterator + + for(i = grid->begin(); i!= grid->after(); i++) + { + index[0] = i.X1() - min_x; + index[1] = i.X2() - min_y; + index[2] = i.X3() - min_z; + imageData->SetPixel(index, i.Value()); + + //cout< +rtsCamera::rtsCamera() +{ + position = point3D(0, 0, 0); + view_vector = vector3D(0, 0, -1); + up_vector = vector3D(0, 1, 0); + lookat_point = point3D(0, 0, -1); + + pers_view_angle = 60; + ortho_width = 1.0; + ortho_height = 1.0; + + near_plane = 1; + far_plane = 100; +} + +rtsCamera::LookAt( + +/* +rtsCamera::rtsCamera(rtsCameraState initial_state) +{ + m_camera_state = initial_state; + + //make sure that the view and lookat vectors are orthogonal + vector3D lookat = m_camera_state.lookat - m_camera_state.position; + vector3D up = m_camera_state.up; + vector3D side = lookat.X(up); + up = side.X(lookat); + up.Normalize(); + m_camera_state.up = up; +} + +rtsCameraState rtsCamera::getState() +{ + return m_camera_state; +} + + + + +void rtsCamera::setState(rtsCameraState camera_state) +{ + m_camera_state = camera_state; + + //re-orthogonalize the vectors + vector3D view = m_camera_state.lookat - m_camera_state.position; + vector3D side = view.X(m_camera_state.up); + m_camera_state.up = side.X(view); + m_camera_state.up.Normalize(); +} + +void rtsCamera::LookAt(point3D point) +{ + //looks at a point + + //find the new view vector + vector3D view = point - m_camera_state.position; + + //normalize the view vector + view.Normalize(); + + //prepare a new side vector and up vector + vector3D side; + vector3D up; + + //get the up vector + //if the new viewvector is at 0 or 180 degrees to the up vector + float cos_angle = view*m_camera_state.up; + if(cos_angle == 1.0f || cos_angle == -1.0f) + { + //re-calculate the up vector + up = m_camera_state.up.X(m_camera_state.lookat - m_camera_state.position); + } + else + { + //otherwise, just get the current up vector + up = m_camera_state.up; + } + + + //correct the up vector based on the new view vector + side = up.X(view); + up = view.X(side); + up.Normalize(); + + //change the camera state + m_camera_state.up = up; + m_camera_state.lookat = point; +} + +void rtsCamera::Position(point3D p) +{ + m_camera_state.position = p; +} + +void rtsCamera::Up(vector3D up) +{ + m_camera_state.up = up; +} + +void rtsCamera::DollyPosition(point3D p) +{ + vector3D adjustment = p-m_camera_state.position; + m_camera_state.position = p; + m_camera_state.lookat = m_camera_state.lookat + adjustment; +} + +point3D rtsCamera::getLookAtPoint() +{ + return m_camera_state.lookat; +} + + + +void rtsCamera::Pan(double x, double y) +{ + //first calculate the lookat and side vectors + vector3D lookatvector=m_camera_state.lookat - m_camera_state.position; + vector3D sidevector = lookatvector.X(m_camera_state.up); + sidevector.Normalize(); + + m_camera_state.position=m_camera_state.position+sidevector*x; + m_camera_state.lookat=m_camera_state.lookat+sidevector*x; + + vector3D upvector = lookatvector.X(sidevector); + upvector.Normalize(); + m_camera_state.position=m_camera_state.position+upvector*y; + m_camera_state.lookat=m_camera_state.lookat+upvector*y; +} + +void rtsCamera::RotateUpDown(double degrees) +{ + //first calculate the lookat and side vectors + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + vector3D sidevector = lookatvector.X(m_camera_state.up); + m_camera_state.up=sidevector.X(lookatvector); + m_camera_state.up.Normalize(); + sidevector.Normalize(); + + //translate the look-at point to the origin (and the camera with it) + point3D origin = point3D(0.0, 0.0, 0.0); + vector3D translateCamera = origin-m_camera_state.lookat; + + point3D translatedCamera=m_camera_state.position+translateCamera; + + //the next step is to rotate the side vector so that it lines up with the z axis + double a=sidevector.x; + double b=sidevector.y; + double c=sidevector.z; + + double d=sqrt(b*b + c*c); + + //error correction for when we are already looking down the z-axis + if(d==0) + return; + + vector3D XZplane = vector3D(translatedCamera.x, + (translatedCamera.y*c/d - translatedCamera.z*b/d), + (translatedCamera.y*b/d + translatedCamera.z*c/d)); + + vector3D Zaxis = vector3D(XZplane.x*d - XZplane.z*a, + XZplane.y, + XZplane.x*a + XZplane.z*d); + + vector3D rotated = vector3D(Zaxis.x*cos(TORADIANS(degrees)) - Zaxis.y*sin(TORADIANS(degrees)), + Zaxis.x*sin(TORADIANS(degrees)) + Zaxis.y*cos(TORADIANS(degrees)), + Zaxis.z); + + vector3D XZout = vector3D( rotated.x*(d/(a*a + d*d)) + rotated.z*(a/(a*a + d*d)), + rotated.y, + rotated.x*(-a/(a*a+d*d)) + rotated.z*(d/(a*a + d*d))); + + vector3D result = vector3D( XZout.x, + XZout.y*(c*d/(b*b + c*c)) + XZout.z*(b*d/(b*b + c*c)), + XZout.y*(-b*d/(b*b + c*c)) + XZout.z*(c*d/(b*b + c*c))); + + result=result-translateCamera; + + m_camera_state.position.x=result.x; + m_camera_state.position.y=result.y; + m_camera_state.position.z=result.z; + +} + +void rtsCamera::Yaw(double degrees) +{ + //basically, we have to rotate the look-at point around the up vector + //first, translate the look-at point so that the camera is at the origin + point3D origin(0.0, 0.0, 0.0); + point3D temp_lookat = m_camera_state.lookat - (m_camera_state.position - origin); + + //create a rotation matrix to rotate the lookat point around the up vector + float x=m_camera_state.up.x; + float y=m_camera_state.up.y; + float z=m_camera_state.up.z; + float c=cos(TORADIANS(-degrees)); + float s=sin(TORADIANS(-degrees)); + float t=1.0 - cos(TORADIANS(-degrees)); + float m00 = t*x*x + c; + float m01 = t*x*y + s*z; + float m02 = t*x*z - s*y; + float m03 = 0; + float m10 = t*x*y - s*z; + float m11 = t*y*y + c; + float m12 = t*y*z + s*x; + float m13 = 0; + float m20 = t*x*z + s*y; + float m21 = t*y*z - s*x; + float m22 = t*z*z + c; + float m23 = 0; + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + matrix4x4 rotation(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33); + point3D result = rotation*temp_lookat + (m_camera_state.position - origin); + m_camera_state.lookat = result; +} + +void rtsCamera::Pitch(double degrees) +{ + //basically, we have to rotate the look-at point and up vector around the side vector + //first, translate the look-at point so that the camera is at the origin + point3D origin(0.0, 0.0, 0.0); + + //find all three necessary vectors + vector3D temp_lookat = m_camera_state.lookat - m_camera_state.position; + double lookat_length = temp_lookat.Length(); + vector3D temp_up = m_camera_state.up; + vector3D temp_side = temp_lookat.X(temp_up); + temp_lookat.Normalize(); + temp_up.Normalize(); + temp_side.Normalize(); + + + //create a rotation matrix to rotate around the side vector + float x=temp_side.x; + float y=temp_side.y; + float z=temp_side.z; + float c=cos(TORADIANS(degrees)); + float s=sin(TORADIANS(degrees)); + float t=1.0 - cos(TORADIANS(degrees)); + float m00 = t*x*x + c; + float m01 = t*x*y + s*z; + float m02 = t*x*z - s*y; + float m03 = 0; + float m10 = t*x*y - s*z; + float m11 = t*y*y + c; + float m12 = t*y*z + s*x; + float m13 = 0; + float m20 = t*x*z + s*y; + float m21 = t*y*z - s*x; + float m22 = t*z*z + c; + float m23 = 0; + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + matrix4x4 rotation(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33); + + //rotate the up and look-at vectors around the side vector + vector3D result_lookat = rotation*temp_lookat; + vector3D result_up = rotation*temp_up; + result_lookat.Normalize(); + result_up.Normalize(); + + m_camera_state.lookat = m_camera_state.position + result_lookat * lookat_length; + m_camera_state.up = result_up; +} + + +void rtsCamera::RotateLeftRight(double degrees) +//this function rotates the camera around the up vector (which always points along hte positive +//Y world axis). +{ + //translate the look-at point to the origin (and the camera with it) + point3D origin = point3D(0.0, 0.0, 0.0); + vector3D translateCamera = origin-m_camera_state.lookat; + + point3D translatedCamera=m_camera_state.position+translateCamera; + + + //perform the rotation around the look-at point + //using the y-axis as the rotation axis + point3D newcamera; + newcamera.x=translatedCamera.x*cos(TORADIANS(degrees)) - translatedCamera.z*sin(TORADIANS(degrees)); + newcamera.z=translatedCamera.x*sin(TORADIANS(degrees)) + translatedCamera.z*cos(TORADIANS(degrees)); + newcamera.y=translatedCamera.y; + + vector3D newup; + newup.x=m_camera_state.up.x*cos(TORADIANS(degrees)) - m_camera_state.up.z*sin(TORADIANS(degrees)); + newup.z=m_camera_state.up.x*sin(TORADIANS(degrees)) + m_camera_state.up.z*cos(TORADIANS(degrees)); + newup.y=m_camera_state.up.y; + + //translate the lookat point back to it's original position (along with the camera) + newcamera=newcamera-translateCamera; + + m_camera_state.position.x=newcamera.x; + m_camera_state.position.y=newcamera.y; + m_camera_state.position.z=newcamera.z; + + m_camera_state.up.x=newup.x; + m_camera_state.up.y=newup.y; + m_camera_state.up.z=newup.z; + m_camera_state.up.Normalize(); + +} + +void rtsCamera::Forward(double distance) +{ + //calculate the lookat vector (direction of travel) + vector3D old_lookat=m_camera_state.lookat-m_camera_state.position; + old_lookat.Normalize(); + + //calculate the new position of the camera + point3D new_position = m_camera_state.position+old_lookat*distance; + //now calculate the new lookat vector + vector3D new_lookat=m_camera_state.lookat-new_position; + //find the length of the new lookat vector + + //move the camera to the new position + m_camera_state.position = new_position; +} + +void rtsCamera::ScaleForward(double factor, double min, double max) +{ + //This function moves the camera forward, scaling the magnitude + //of the motion by the length of the view vector. Basically, the closer + //the camera is to the lookat point, the slower the camera moves. + + //calculate the lookat vector (direction of travel) + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + //find the length of the view vector + double length = lookatvector.Length(); + //normalize + lookatvector.Normalize(); + + //prevent motion if the bounds would be passed + double new_distance = length - (factor*length); + if(new_distance < min || new_distance > max) + factor = 0; + //move the camera + m_camera_state.position=m_camera_state.position+lookatvector*factor*length; + lookatvector=m_camera_state.lookat-m_camera_state.position; + +} + +void rtsCamera::DollyLeftRight(double distance) +{ + //calculate the side vector vector (direction of travel) + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + vector3D side = lookatvector.X(m_camera_state.up); + side.Normalize(); + + m_camera_state.position=m_camera_state.position+side*distance; + m_camera_state.lookat = m_camera_state.lookat + side*distance; + //lookatvector=m_camera_state.lookat-m_camera_state.position; +} + +void rtsCamera::DollyUpDown(double distance) +{ + //move along the up vector + m_camera_state.up.Normalize(); + + m_camera_state.position=m_camera_state.position+m_camera_state.up*distance; + m_camera_state.lookat = m_camera_state.lookat + m_camera_state.up*distance; + //lookatvector=m_camera_state.lookat-m_camera_state.position; +} + +void rtsCamera::Zoom(double angle) +{ + m_camera_state.pers_view_angle += angle; +} + +*/ \ No newline at end of file diff --git a/rts_old_Camera.h b/rts_old_Camera.h new file mode 100755 index 0000000..4b542e8 --- /dev/null +++ b/rts_old_Camera.h @@ -0,0 +1,77 @@ +#include "rtsLinearAlgebra.h" + +#ifndef _RTSMATH_H +#define _RTSMATH_H + +#define CAMERA_UP -1 +#define CAMERA_DOWN 1 +#define CAMERA_LEFT -1 +#define CAMERA_RIGHT 1 + +struct rtsCameraState +{ + point3D position; + point3D lookat; + vector3D up; + float pers_view_angle; + float ortho_width; + float ortho_height; + float near_plane; + float far_plane; +}; + +class rtsCamera +{ + //members + point3D position; + vector3D view_vector; + vector3D up_vector; + point3D lookat_point; + float pers_view_angle; + float ortho_width; + float ortho_height; + float near_plane; + float far_plane; + +public: + + + //constructors + rtsCamera(); + ~rtsCamera(){}; + + //methods + void LookAt(point3D pos, point3D lookat, vector3D up); + /* + void RotateUpDown(double degrees); + void RotateLeftRight(double degrees); + void Pan(double x, double y); + void Yaw(double degrees); + void Pitch(double degrees); + void Forward(double distance); + void ScaleForward(double factor, double min = 0, double max = 999999); + void DollyLeftRight(double distance); + void DollyUpDown(double distance); + void Zoom(double angle); + void LookAt(point3D point); + void Position(point3D point); + void Up(vector3D up); + void DollyPosition(point3D point); //moves the camera but keeps the current orientation + */ + + //get methods + rtsCameraState getState(); + vector3D getView(){return view_vector;} + vector3D getUp(){return up_vector;} + point3D getPosition(){return position;} + point3D getLookAt(){return lookat_point;} + double getViewAngle(){return pers_view_angle;} + double getNearPlane(){return near_plane;} + double getFarPlane(){return far_plane;} + double getOrthoWidth(){return ortho_width;} + double getOrthoHeight(){return ortho_height;} + + +}; + +#endif \ No newline at end of file diff --git a/rts_vtkFunctions.h b/rts_vtkFunctions.h new file mode 100755 index 0000000..00d0572 --- /dev/null +++ b/rts_vtkFunctions.h @@ -0,0 +1,55 @@ +#include "vtkImageData.h" +#include "rtsVolume.h" +#include "rtsImplicit3D.h" + +/*vtkImageData* rtsVolume2vtkImageData(rtsVolume* inputVolume, int data_type) +{ + vtkImageData* outputImageData = vtkImageData::New(); + outputImageData->SetScalarType(data_type); + outputImageData->SetDimensions(inputVolume->get_dimx(), inputVolume->get_dimy(), inputVolume->get_dimz()); + unsigned char* scalar_pointer = (unsigned char*)outputImageData->GetScalarPointer(); + unsigned char* volume_pointer = inputVolume->get_bits(); + unsigned int vol_size = inputVolume->get_dimx()*inputVolume->get_dimy()*inputVolume->get_dimz(); + for(int i=0; i +vtkImageData* rtsImplicit3D2vtkImageData(rtsImplicit3D* in_function, int data_type) +{ + //create the vtkImageData class for storing a uniform grid + vtkImageData* outputImageData = vtkImageData::New(); + //set the data type of the scalar field + outputImageData->SetScalarType(data_type); + //set the dimensions of the image data based on the function resolution + outputImageData->SetDimensions(in_function->DimX(), in_function->DimY(), in_function->DimZ()); + //get a pointer to the scalar field data and the function data + unsigned char* scalar_pointer = (unsigned char*)outputImageData->GetScalarPointer(); + unsigned char* volume_pointer = (unsigned char*)in_function->GetBits(); + unsigned int vol_size; + switch(data_type) + { + case VTK_UNSIGNED_CHAR: + vol_size = sizeof(char)*in_function->DimX()*in_function->DimY()*in_function->DimZ(); + break; + case VTK_DOUBLE: + vol_size = sizeof(double)*in_function->DimX()*in_function->DimY()*in_function->DimZ(); + break; + default: + exit(1); + } + + memcpy(scalar_pointer, volume_pointer, vol_size); + + //for(int i=0; i +using namespace std; + + +#pragma comment( lib, "comctl32" ) + +#include +#include +#include +#include + +bool rtsOpenFileDialog( char *filename, int filenameSize, const char *filetypes="All Files (*.*)\0*.*;") +{ + OPENFILENAME *ofn = (OPENFILENAME*)GlobalAlloc(GMEM_FIXED,sizeof(OPENFILENAME)); + ZeroMemory(ofn, sizeof(OPENFILENAME)); + ofn->lStructSize = sizeof(OPENFILENAME); + ofn->hwndOwner = NULL; + ofn->lpstrFile = filename; + cout<lpstrFile<nMaxFile = filenameSize; + ofn->lpstrFilter = filetypes ? filetypes : "All Files (*.*)\0*.*;"; + ofn->nFilterIndex = 0; + ofn->lpstrFileTitle = NULL; + ofn->nMaxFileTitle = 0; + ofn->lpstrInitialDir = NULL; + ofn->Flags = OFN_ENABLESIZING | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST +|OFN_EXPLORER | OFN_HIDEREADONLY; + + //allow multiple files to be loaded if the user says so + //if(multi) ofn->Flags = ofn->Flags | OFN_ALLOWMULTISELECT; + + BOOL success = GetOpenFileNameA(ofn); + //DWORD myfoo = CommDlgExtendedError(); + GlobalFree(ofn); + return success; +} + +bool rtsSaveFileDialog( char *filename, int filenameSize, const char *filetypes="All Files (*.*)\0*.*;" ) +{ + OPENFILENAME *ofn = (OPENFILENAME*)GlobalAlloc(GMEM_FIXED,sizeof(OPENFILENAME)); + ZeroMemory(ofn, sizeof(OPENFILENAME)); + ofn->lStructSize = sizeof(OPENFILENAME); + ofn->hwndOwner = NULL; + ofn->lpstrFile = filename; + ofn->nMaxFile = filenameSize; + ofn->lpstrFilter = filetypes ? filetypes : "All Files (*.*)\0*.*;"; + ofn->nFilterIndex = 0; + ofn->lpstrFileTitle = NULL; + ofn->nMaxFileTitle = 0; + ofn->lpstrInitialDir = NULL; + ofn->Flags = OFN_ENABLESIZING | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST +|OFN_EXPLORER | OFN_HIDEREADONLY; + BOOL success = GetSaveFileNameA(ofn); + //DWORD myfoo = CommDlgExtendedError(); + GlobalFree(ofn); + return success; +} + +bool rts_winBrowseFolderDialog(char* title, char* foldername) +{ + BROWSEINFO* bi = (BROWSEINFO*)GlobalAlloc(GMEM_FIXED,sizeof(BROWSEINFO)); + ZeroMemory(bi, sizeof(BROWSEINFO)); + char directory[MAX_PATH] = ""; + + bi->pszDisplayName = directory; + bi->lpszTitle = title; + bi->pidlRoot = NULL; + bi->lpfn = NULL; + bi->ulFlags = 0; + PIDLIST_ABSOLUTE pID = SHBrowseForFolder(bi); + + SHGetPathFromIDList(pID, foldername); + + return true; + +} \ No newline at end of file diff --git a/rts_winFileDialog.h b/rts_winFileDialog.h new file mode 100755 index 0000000..0e4f5db --- /dev/null +++ b/rts_winFileDialog.h @@ -0,0 +1,18 @@ +/* +1) Make sure to not use Unicode characters. Using the Unicode character set does some +strange stuff involving LPWSTR and LPWCHAR. +2) Make sure an empty string is passed: + char filename[255] = ""; + rtsOpenFileDialog(filename, 255); +*/ + +#pragma comment( lib, "comctl32" ) + +#include +#include +#include +#include + +bool rtsOpenFileDialog( char *filename, int filenameSize, const char *filetypes); +bool rtsSaveFileDialog( char *filename, int filenameSize, const char *filetypes); +bool rts_winBrowseFolderDialog( char* title, char* foldername); diff --git a/rts_winFiles.h b/rts_winFiles.h new file mode 100755 index 0000000..9fabeaa --- /dev/null +++ b/rts_winFiles.h @@ -0,0 +1,41 @@ +#include "rtsFilename.h" + +#include +#include + + +vector rts_winGetFileList(const char* mask) +{ + /*This function returns a list of file names based on the mask passed by + the user. The value returned is the number of rtsFilename elements in the + file_list parameter.*/ + + //create a temporary vector to store the file names + vector result; + //create a handle for the search + HANDLE search_handle; + WIN32_FIND_DATA found_data; + + //start the search + search_handle = FindFirstFile((LPCSTR)mask, &found_data); + + //loop through the rest of the data + rtsFilename new_file; + if(search_handle != INVALID_HANDLE_VALUE) + { + //save the first filename + new_file = found_data.cFileName; + result.push_back(new_file); + + //now loop through the rest of the files + while(FindNextFile(search_handle, &found_data)) + { + new_file = found_data.cFileName; + result.push_back(new_file); + } + } + + return result; +} + + diff --git a/rtsf_LoadTexture.h b/rtsf_LoadTexture.h new file mode 100755 index 0000000..24bc0fc --- /dev/null +++ b/rtsf_LoadTexture.h @@ -0,0 +1,77 @@ +#include "cimg/cimg.h" +#include "rtsFunction3D.h" +#include "rtspoint3D.h" + +using namespace cimg_library; + +typedef point3D RGB; + +rtsFunction3D rtsf_LoadTexture(const char* filename) +{ + + CImg image(filename); + + unsigned int max_x = image.dimx(); + unsigned int max_y = image.dimy(); + unsigned int max_z = image.dimz(); + + rtsFunction3D bits(max_x, max_y, max_z); + + unsigned int x, y, z; + for(x = 0; x rtsf_LoadGrayTexture(const char* filename) +{ + + CImg image(filename); + + //CImgDisplay main_disp(image); + //while(true); + + unsigned int dim_x = image.dimx(); + unsigned int dim_y = image.dimy(); + unsigned int dim_z = image.dimz(); + + rtsFunction3D bits(dim_x, dim_y, dim_z); + + + float r, g, b; + float greyscale; + float max_length = sqrt(3.0f); + + unsigned int x, y, z; + for(x = 0; x + +template +class rtsAABB +{ +public: + point3D minimum; + point3D maximum; + + //overloaded operators + rtsAABB operator+(rtsAABB param); + rtsAABB getGridAlignedAABB(); + inline bool isIn(T x, T y, T z); +}; + +template +class rtsBoundingSphere +{ +public: + point3D center; + T radius; + + inline bool isIn(T x, T y, T z); +}; + +template +class rtsTGC +{ +public: + point3D posA; + point3D posB; + vector3D normA; + vector3D normB; + T radA; + T radB; + + rtsAABB BoundAABB(); +}; + +template +rtsAABB rtsAABB::operator+(rtsAABB param) +{ +/* This function creates an AABB by finding the minimum bound + of two other AABBs. +*/ + + rtsAABB result; + + result.minimum.x = min(minimum.x, param.minimum.x); + result.minimum.y = min(minimum.y, param.minimum.y); + result.minimum.z = min(minimum.z, param.minimum.z); + + result.maximum.x = max(maximum.x, param.maximum.x); + result.maximum.y = max(maximum.y, param.maximum.y); + result.maximum.z = max(maximum.z, param.maximum.z); + return result; +} + +template +inline bool rtsAABB::isIn(T x, T y, T z) +{ + if(x >= minimum.x && x <= maximum.x && + y >= minimum.y && y <= maximum.y && + z >= minimum.z && z <= maximum.z) + return true; + else + return false; +} + +template +inline bool rtsBoundingSphere::isIn(T x, T y, T z) +{ + vector3D to_point = center - point3D(x, y, z); + T length_squared = to_point*to_point; + if(length_squared < radius*radius) + return true; + else + return false; +} + +template +rtsAABB rtsAABB::getGridAlignedAABB() +{ +/* This function returns a version of the current AABB that is snapped + to a grid (ie the floor of the position and the ceiling of the size). +*/ + rtsAABB result; + result.minimum.x = floor(minimum.x); + result.minimum.y = floor(minimum.y); + result.minimum.z = floor(minimum.z); + result.maximum.x = ceil(maximum.x); + result.maximum.y = ceil(maximum.y); + result.maximum.z = ceil(maximum.z); + return result; +} + +template +rtsAABB rtsTGC::BoundAABB() +{ +/* This function returns an axis-aligned bounding box + that is the minimum bound for the given truncated-generalized cone. +*/ + //create a vector representing each axis + vector3D x(1.0, 0.0, 0.0); + vector3D y(0.0, 1.0, 0.0); + vector3D z(0.0, 0.0, 1.0); + + //store the extents + point3D a_extents(radA*(1.0 - fabs(normA*x)), + radA*(1.0 - fabs(normA*y)), + radA*(1.0 - fabs(normA*z))); + point3D b_extents(radB*(1.0 - fabs(normB*x)), + radB*(1.0 - fabs(normB*y)), + radB*(1.0 - fabs(normB*z))); + + //create the AABB + rtsAABB result; + + //calculate the bounding box information + //calculate bounding box position as the minima of all extents and positions + result.minimum.x = min(posA.x - a_extents.x, posB.x - b_extents.x); + result.minimum.y = min(posA.y - a_extents.y, posB.y - b_extents.y); + result.minimum.z = min(posA.z - a_extents.z, posB.z - b_extents.z); + + //now find the size of the block + result.maximum.x = max(posA.x + a_extents.x, posB.x + b_extents.x); + result.maximum.y = max(posA.y + a_extents.y, posB.y + b_extents.y); + result.maximum.z = max(posA.z + a_extents.z, posB.z + b_extents.z); + + return result; +} + + + + + + + + +#endif \ No newline at end of file diff --git a/temp_rtsSignedDistance.h b/temp_rtsSignedDistance.h new file mode 100755 index 0000000..ea17d37 --- /dev/null +++ b/temp_rtsSignedDistance.h @@ -0,0 +1,321 @@ +#include "rtsImplicit3D.h" +#include +using namespace std; + +#define DIST_MAX 255 +#define DIST_UNSIGNED 0 +#define DIST_SIGNED 1 + +float ComputeSurfaceDistance(point3D p0, point3D p1, float val0, float val1, float s) +{ + /*This function computes the distance from p0 to the surface, given two points p0 and p1 + on either side of the surface (with values v0 and v1 respectively). surface specifies + the value at the surface. + */ + + //compute the normalized position of the surface between p0 and p1 + float s_norm_pos = (s - val0) / (val1 - val0); + //compute the actual position of the surface + point3D s_pos = p0 + s_norm_pos * (p1 - p0); + //compute the distance from p0 to the surface + float result = (s_pos - p0).Length(); + //cout<<"distance: "<* function, float threshold, + rtsImplicit3D* &result, rtsImplicit3D* &mask) +{ + /*This function creates an initial signed distance function from a threshold image. + All voxels adjacent to the surface specified by the threshold are initialized with a + distance value. Low values are inside, high values are outside. + */ + //current and neighboring voxel flags (false = inside, true = outside) + bool c, x_p, x_n, y_p, y_n, z_p, z_n; + float d_xp, d_xn, d_yp, d_yn, d_zp, d_zn; + float in_out = 1; + + //boundary condition function and the mask + result = new rtsImplicit3D(function->DimX(), function->DimY(), function->DimZ()); + //get the parameterization + point3D min_domain= function->getMinDomain(); + point3D max_domain = function->getMaxDomain(); + result->Parameterize(min_domain.x, max_domain.x, min_domain.y, max_domain.y, min_domain.z, max_domain.z); + (*result) = DIST_MAX; + //create a mask + mask = new rtsImplicit3D(function->DimX(), function->DimY(), function->DimZ()); + (*mask) = false; + + cout<<"done making boundary condition function"< size(function->DimX(), function->DimY(), function->DimZ()); //get the function size + int x, y, z; + for(x=0; x= size.x) x_p = c; + else if((*function)(x+1, y, z) < threshold) x_p = false; + if(y-1 < 0) y_n = c; //Y + else if((*function)(x, y-1, z) < threshold) y_n = false; + if(y+1 >= size.y) y_p = c; + else if((*function)(x, y+1, z) < threshold) y_p = false; + if(z-1 < 0) z_n = c; //Z + else if((*function)(x, y, z-1) < threshold) z_n = false; + if(z+1 >= size.z) z_p = c; + else if((*function)(x, y, z+1) < threshold) z_p = false; + + //set the distance from the isosurface + if(c == false) + in_out = -1.0; + if(x_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x-1, y, z), + (*function)(x, y, z), + (*function)(x-1, y, z), + threshold) * in_out); + if(x_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x+1, y, z), + (*function)(x, y, z), + (*function)(x+1, y, z), + threshold) * in_out); + if(y_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x, y-1, z), + (*function)(x, y, z), + (*function)(x, y-1, z), + threshold) * in_out); + if(y_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x, y+1, z), + (*function)(x, y, z), + (*function)(x, y+1, z), + threshold) * in_out); + if(z_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z-1), + (*function).getParameter(x, y, z), + (*function)(x, y, z), + (*function)(x, y, z-1), + threshold) * in_out); + if(z_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x, y, z+1), + (*function)(x, y, z), + (*function)(x, y, z+1), + threshold) * in_out); + + //set the mask to 1 if the voxel is on an edge node + if(x_n != c || x_p != c || y_n != c || y_p != c || z_n != c || z_p != c) + (*mask)(x, y, z) = true; + } + + + //if a line between the two voxels crosses the surface + //find the distance between the voxel center and the surface + + + cout<<"done computing boundary conditions"<* function, + point3D point, + vector3D voxelsize, + int type = DIST_UNSIGNED) +{ + /*This function updates the manhattan distance from a surface using the manhattan + distance of its neighboring points. + */ + indextype x, y, z; + x=point.x; y=point.y, z=point.z; + int sign = 1; + float result = DIST_MAX; + float near_value; //the value of the neighbor being considered + float possible_value; + if(x!=0) + { + near_value = (*function)(x-1, y, z); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.x); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.x); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + + } + if(x!=function->DimX()-1) + { + near_value = (*function)(x+1, y, z); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.x); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.x); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(y!=0) + { + near_value = (*function)(x, y-1, z); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.y); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.y); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(y!=function->DimY()-1) + { + near_value = (*function)(x, y+1, z); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.y); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.y); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(z!=0) + { + near_value = (*function)(x, y, z-1); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.z); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.z); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(z!=function->DimZ()-1) + { + near_value = (*function)(x, y, z+1); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.z); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.z); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + return result; + +} +void Eikonal_Manhattan(rtsImplicit3D* &function, + rtsImplicit3D* mask, + int type = DIST_UNSIGNED) +{ + /*This function estimates the Eikonal equation based on the manhattan distance. The + function constantly increases values outwards from the boundary conditions. + */ + + //compute the distance between two voxels + vector3D voxel_size; + voxel_size.x = fabs(function->getParameter(0, 0, 0).x - function->getParameter(1, 0, 0).x); + voxel_size.y = fabs(function->getParameter(0, 0, 0).y - function->getParameter(0, 1, 0).y); + voxel_size.z = fabs(function->getParameter(0, 0, 0).z - function->getParameter(0, 0, 1).z); + + //use fast sweeping to compute the manhattan distance + //0:X 0:Y 0:Z + cout<<"first iteration..."<DimX(); x++) + for(y=0; yDimY(); y++) + for(z=0; zDimZ(); z++) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX(); x++) + for(y=0; yDimY(); y++) + for(z=function->DimZ()-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX(); x++) + for(y=function->DimY()-1; y>=0; y--) + for(z=0; zDimZ(); z++) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX(); x++) + for(y=function->DimY()-1; y>=0; y--) + for(z=function->DimZ()-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX()-1; x>=0; x--) + for(y=0; yDimY(); y++) + for(z=0; zDimZ(); z++) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX()-1; x>=0; x--) + for(y=0; yDimY(); y++) + for(z=function->DimZ()-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX()-1; x>=0; x--) + for(y=function->DimY()-1; y>=0; y--) + for(z=0; zDimZ(); z++) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX()-1; x>=0; x--) + for(y=function->DimY()-1; y>=0; y--) + for(z=function->DimZ()-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<::iterator i; + int a, b; + point3D v_a, v_b; + glBegin(GL_LINES); //start rendering lines + for(i=m_edge_list.begin(); i!=m_edge_list.end(); i++) + { + v_a = (*i)->vertex_a->position; //get the positions of the two vertex edges + v_b = (*i)->vertex_b->position; + glVertex3f(v_a.x, v_a.y, v_a.z); //draw the vertices + glVertex3f(v_b.x, v_b.y, v_b.z); + } + glEnd(); //finish drawing +} + +void rts_glFilamentNetwork::RenderBranches() +{ + //for each vertex + vector::iterator i; + point3D v; + glBegin(GL_POINTS); + for(i=m_vertex_list.begin(); i!=m_vertex_list.end(); i++) + { + if((*i)->v_neighbors.size() > 2) + { + v = (*i)->position; + glVertex3f(v.x, v.y, v.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderFilaments() +{ + vector::iterator i; + int num_edges; + point3D v_a, v_b; + int e; + glBegin(GL_LINES); + for(i=m_filament_list.begin(); i!=m_filament_list.end(); i++) //for each filament + { + num_edges = (*i)->edges.size(); + for(e=0; eedges[e]->vertex_a->position; + v_b = (*i)->edges[e]->vertex_b->position; + glVertex3f(v_a.x, v_a.y, v_a.z); + glVertex3f(v_b.x, v_b.y, v_b.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderSelectedFilaments() +{ + vector::iterator f; + int num_edges; + point3D v_a, v_b; + int e; + glBegin(GL_LINES); + for(f=m_selected_list.begin(); f!=m_selected_list.end(); f++) + { + num_edges = m_filament_list[(*f)]->edges.size(); + for(e=0; eedges[e]->vertex_a->position; + v_b = m_filament_list[(*f)]->edges[e]->vertex_b->position; + glVertex3f(v_a.x, v_a.y, v_a.z); + glVertex3f(v_b.x, v_b.y, v_b.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderOrientationColor(double x, double y, double z, double r, double g, double b) +{ + vector::iterator i; + int num_edges; + point3D v_a, v_b; + + //orientation variables + vector3D orientation; + double cos_a; + vector3D A(x, y, z); + A.Normalize(); + + int e; + glBegin(GL_LINES); + for(i=m_filament_list.begin(); i!=m_filament_list.end(); i++) //for each filament + { + //set the color of the filament based on orientation + v_a = (*i)->vertex_a->position; + v_b = (*i)->vertex_b->position; + + + num_edges = (*i)->edges.size(); + for(e=0; eedges[e]->vertex_a->position; + v_b = (*i)->edges[e]->vertex_b->position; + + //determine color + orientation = (v_a - v_b).Normalize(); + cos_a = fabs(orientation*A); + glColor3f(r*cos_a, g*cos_a, b*cos_a); + + glVertex3f(v_a.x, v_a.y, v_a.z); + glVertex3f(v_b.x, v_b.y, v_b.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderEdgeDistanceColor(float r, float g, float b, float cutoff) +{ + vector::iterator e; + glBegin(GL_LINES); + point3D p; + double d; + double exp = 3; + for(e=m_edge_list.begin(); e!=m_edge_list.end(); e++) + { + d = (*e)->distance; + if(d1.0) d=1.0; + + glColor3f(pow((1.0-d),exp)*r, pow((1.0-d),exp)*g, pow((1.0-d),exp)*b); + p = (*e)->vertex_a->position; + glVertex3f(p.x, p.y, p.z); + p = (*e)->vertex_b->position; + glVertex3f(p.x, p.y, p.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderFilamentDistanceColor(float r, float g, float b, float cutoff) +{ + vector::iterator f; + unsigned int e; + unsigned int num_edges; + double d; + point3D v; + double exp = 3.0; + for(f = m_filament_list.begin(); f!=m_filament_list.end(); f++) + { + d = (*f)->distance; + if(d1.0) d=1.0; + if(d<0.0) d=0.0; + //cout<<"d: "<edges.size(); + glColor3f(pow((1.0-d), exp)*r, pow((1.0-d), exp)*g, pow((1.0-d), exp)*b); + glBegin(GL_LINES); + for(e=0; eedges[e]->vertex_a->position; + glVertex3f(v.x, v.y, v.z); + v = (*f)->edges[e]->vertex_b->position; + glVertex3f(v.x, v.y, v.z); + } + glEnd(); + } + } + +} + + +void rts_glFilamentNetwork::RenderRadiusColor(float min_r, float min_g, float min_b, + float max_r, float max_g, float max_b, + float min_radius, float max_radius) +{ + /*Render each segment with a color based on the radius of the filament + */ + + vector::iterator i; + int e; + int num_edges; + point3D v; + vector3D color_min(min_r, min_g, min_b); + vector3D color_max(max_r, max_g, max_b); + max_radius /= m_data_scale; + min_radius /= m_data_scale; + float diff = max_radius - min_radius; + float p; //parameter value (position between min and max radii) + vector3D color_p; + + for(i=m_filament_list.begin(); i!=m_filament_list.end(); i++) + { + glBegin(GL_LINES); + num_edges = (*i)->edges.size(); + for(e=0; eedges[e]->vertex_a->radius - min_radius)/diff; + //cout<<"p: "<edges[e]->vertex_a->position; + glVertex3f(v.x, v.y, v.z); + //determine the second color + p = ((*i)->edges[e]->vertex_b->radius - min_radius)/diff; + color_p = (1.0 - p)*color_min + (p)*color_max; + glColor3f(color_p.x, color_p.y, color_p.z); + //determine the vertex position + v = (*i)->edges[e]->vertex_b->position; + glVertex3f(v.x, v.y, v.z); + } + glEnd(); + } +} + +void rts_glFilamentNetwork::RenderEdgeBoundingBoxes() +{ + glMatrixMode(GL_MODELVIEW); //switch to the modelview matrix and store it + + vector::iterator e; + point3D center; + vector3D size; + for(e=m_edge_list.begin(); e!=m_edge_list.end(); e++) + { + glPushMatrix(); + size = (*e)->bounding_box.maximum - (*e)->bounding_box.minimum; + center = (*e)->bounding_box.minimum + 0.5*(size); + glTranslatef(center.x, center.y, center.z); + glScalef(size.x, + size.y, + size.z); + glutWireCube(1.0); + glPopMatrix(); + } + +} + +void rts_glFilamentNetwork::RenderFilamentBoundingBoxes() +{ + glMatrixMode(GL_MODELVIEW); //switch to the modelview matrix and store it + + vector::iterator f; + point3D center; + vector3D size; + for(f=m_filament_list.begin(); f!=m_filament_list.end(); f++) + { + glPushMatrix(); + size = (*f)->bounding_box.maximum - (*f)->bounding_box.minimum; + center = (*f)->bounding_box.minimum + 0.5*size; + glTranslatef(center.x, center.y, center.z); + glScalef(size.x, + size.y, + size.z); + glutWireCube(1.0); + glPopMatrix(); + } +} + +void rts_glFilamentNetwork::RenderCellSpheres() +{ + glMatrixMode(GL_MODELVIEW); + + vector::iterator c; + for(c=m_cell_list.begin(); c!=m_cell_list.end(); c++) + { + glPushMatrix(); + glTranslatef((*c)->position.x, (*c)->position.y, (*c)->position.z); + glutSolidSphere((*c)->radius, 10, 10); + glPopMatrix(); + } +} +void rts_glFilamentNetwork::RenderSelectedCells() +{ + glMatrixMode(GL_MODELVIEW); + + vector::iterator f; + vector::iterator c; + for(f = m_selected_list.begin(); f!=m_selected_list.end(); f++) + { + for(c=m_filament_list[(*f)]->cells.begin(); c!=m_filament_list[(*f)]->cells.end(); c++) + { + glPushMatrix(); + glTranslatef((*c)->position.x, (*c)->position.y, (*c)->position.z); + glutSolidSphere((*c)->radius, 10, 10); + glPopMatrix(); + } + } +} + +void rts_glFilamentNetwork::p_ProcessPickHits(GLuint num_hits, GLuint* buffer, + unsigned int start_filament, bool append, int max) +{ + //cout<<"hits "< max) + num_hits = max; + unsigned int h, n; + unsigned int num_names; + unsigned int name; + GLuint* ptr = buffer; //index into buffer array + for(h=0; h v_a, v_b; + int name = 0; + unsigned int total_hits = 0; + for(f=0; fedges.size(); + for(e = 0; eedges[e]->vertex_a->position; + v_b = m_filament_list[f]->edges[e]->vertex_b->position; + glVertex3f(v_a.x, v_a.y, v_a.z); + glVertex3f(v_b.x, v_b.y, v_b.z); + } + glEnd(); + name++; //increment the name + //We have to make sure that the name count doesn't exceed 64 + if(name == 64) //if the name hits 64, check for and store hits, then reset the name + { + hits = glRenderMode(GL_RENDER); + p_ProcessPickHits(hits, selection_buffer, f-63, append, max - total_hits); //process the hits (store selected fibers) + total_hits += hits; + if(total_hits >= max) //if we've reached the max, return + { + glPopMatrix(); + return; + } + name = 0; //reset the selection queue + glRenderMode(GL_SELECT); //change to selection mode + glInitNames(); //start naming objects + glPushName(0); //insert the first name + } + } + glFlush(); //finish rendering + hits = glRenderMode(GL_RENDER); //switch back to normal mode, get the number of hits + p_ProcessPickHits(hits, selection_buffer, f/64, append, max - total_hits); //get any left-over hits + total_hits += hits; + + glPopMatrix(); +} diff --git a/temp_rts_glFilamentNetwork.h b/temp_rts_glFilamentNetwork.h new file mode 100755 index 0000000..3d360d9 --- /dev/null +++ b/temp_rts_glFilamentNetwork.h @@ -0,0 +1,37 @@ +#ifndef RTS_GLFILAMENTNETWORK_H +#define RTS_GLFILAMENTNETWORK_H + +#include "temp_rtsFilamentNetwork.h" +#include +#include +#include + +class rts_glFilamentNetwork:public rtsFilamentNetwork +{ +private: + void p_ProcessPickHits(GLuint num_hits, GLuint* buffer, unsigned int start_filament, + bool append = false, int max = 1); +public: + + void RenderEdges(); + void RenderBranches(); + void RenderFilaments(); + void RenderOrientationColor(double x, double y, double z, double r, double g, double b); + void RenderSelectedFilaments(); + void RenderRadiusColor(float min_r, float min_g, float min_b, + float max_r, float max_g, float max_b, + float min_radius, float max_radius); + void RenderEdgeDistanceColor(float r, float g, float b, float cutoff); + void RenderFilamentDistanceColor(float r, float g, float b, float cutoff); + void RenderEdgeBoundingBoxes(); + void RenderFilamentBoundingBoxes(); + void RenderCellSpheres(); + void RenderSelectedCells(); + + //pick filaments based on the current projection + void PickFilaments(int x_center, int y_center, int width, int height, bool append = false, int max = 1); + +}; + + +#endif \ No newline at end of file diff --git a/validate/CMakeLists.txt b/validate/CMakeLists.txt new file mode 100755 index 0000000..2d54c3d --- /dev/null +++ b/validate/CMakeLists.txt @@ -0,0 +1,52 @@ +#Specify the version being used aswell as the language +cmake_minimum_required(VERSION 2.8) +#Name your project here +project(rts-validate) + +#set the module directory +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}") + +#set up CUDA +find_package(CUDA) + +#find OpenGL +find_package(OpenGL REQUIRED) + +#find GLUT +set(GLUT_ROOT_PATH $ENV{GLUT_ROOT_PATH}) +find_package(GLUT REQUIRED) + +#find GLEW +find_package(GLEW REQUIRED) + +#ask the user for the RTS location +set(RTS_ROOT_PATH $ENV{RTS_ROOT_PATH}) +find_package(RTS REQUIRED) + +#set the include directories +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${OPENGL_INCLUDE_DIR} + ${GLEW_INCLUDE_PATH} + ${GLUT_INCLUDE_DIR} + ${RTS_INCLUDE_DIR} +) + +#enable warnings +if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + add_definitions(-Wall) +endif() + +#Assign source files to the appropriate variables +file(GLOB SRC_CPP "*.cpp") +file(GLOB SRC_H "*.h") +file(GLOB SRC_CU "*.cu") + +#create an executable +cuda_add_executable(rts-validate ${SRC_CPP} ${SRC_H} ${UI_H} ${SRC_CU}) + +#set the link libraries +target_link_libraries(rts-validate ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ${GLEW_LIBRARY} ${CUDA_cufft_LIBRARY} ${GLUT_glut_LIBRARY}) + + + diff --git a/validate/FindRTS.cmake b/validate/FindRTS.cmake new file mode 100755 index 0000000..fbfcc44 --- /dev/null +++ b/validate/FindRTS.cmake @@ -0,0 +1,14 @@ +# Tries to find the RTS include directory + + FIND_PATH( RTS_INCLUDE_DIR NAMES rts_glShaderProgram.h + PATHS + ${CMAKE_CURRENT_SOURCE_DIR}/rts + ${RTS_ROOT_PATH} +) + +IF (RTS_FOUND) + #The following deprecated settings are for backwards compatibility with CMake1.4 + SET (RTS_INCLUDE_PATH ${RTS_INCLUDE_DIR}) +ENDIF(RTS_FOUND) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(RTS REQUIRED_VARS TRUE RTS_INCLUDE_DIR) diff --git a/validate/compare.h b/validate/compare.h new file mode 100644 index 0000000..3d4f4e6 --- /dev/null +++ b/validate/compare.h @@ -0,0 +1,27 @@ +#ifndef RTS_VALIDATE_COMPARE_H +#define RTS_VALIDATE_COMPARE_H + +#define N 5000 +#define epsilon 0.00001 + +#include +#include +#include +#include "rts/complex.h" + +template +static void compare(std::complex a, rts::complex b, std::string testName) +{ + T diffx = std::abs(a.real() - b.r); + T diffy = std::abs(a.imag() - b.i); + + if(diffx > epsilon || diffy > epsilon) + { + std::cout<<"Failed "< +#include +#include +#include +#include "rts/complex.h" +#include "rts/sbessel.h" + +#include "compare.h" + +typedef float precision; + +//typedef std::complex ptype; +typedef rts::complex ptype; + +void cpuValidateBessel() +{ + + //order + precision v = 5; + precision vm; + + //parameter + precision max_z = 5; + int nz = 20; + precision dz = max_z / nz; + + //bessel function results (first and second kind) + int S = sizeof(ptype) * (v + 1); + + ptype* jv = (ptype*)malloc(S); + ptype* yv = (ptype*)malloc(S); + ptype* hv = (ptype*)malloc(S); + + + std::cout<<"---------j_v(x)-------------"< z; + for(int iz = 0; iz < nz; iz++) + { + z = iz * dz; + + rts::sbesselj(v, z, jv); + + std::cout<(v, z, yv); + + std::cout<(v, z, hv); + + std::cout< +#include +#include "rts/complex.h" + +#include "compare.h" + +#define N 5 +#define epsilon 0.000001 + +template +void validateOperators() +{ + int precision = sizeof(T) * 8; + std::stringstream ss; + ss<<" ("< stdComplex0(x0, y0); + rts::complex rtsComplex0(x0, y0); + + std::complex stdComplex1(x1, y1); + rts::complex rtsComplex1(x1, y1); + + std::complex stdResult; + rts::complex rtsResult; + + //test addition + stdResult = stdComplex0 + stdComplex1; + rtsResult = rtsComplex0 + rtsComplex1; + compare(stdResult, rtsResult, std::string("Binary Addition") + bitString); + //test addition with real value + stdResult = stdComplex1.real() + stdComplex0; + rtsResult = rtsComplex1.r + rtsComplex0; + compare(stdResult, rtsResult, std::string("Addition with Real Value") + bitString); + + //test subtraction + stdResult = stdComplex0 - stdComplex1; + rtsResult = rtsComplex0 - rtsComplex1; + compare(stdResult, rtsResult, std::string("Binary Subtraction") + bitString); + //test subtraction with real value + stdResult = stdComplex1.real() - stdComplex0; + rtsResult = rtsComplex1.r - rtsComplex0; + compare(stdResult, rtsResult, std::string("Subtraction with Real Value") + bitString); + + //test multiplication + stdResult = stdComplex0 * stdComplex1; + rtsResult = rtsComplex0 * rtsComplex1; + compare(stdResult, rtsResult, std::string("Binary Multiplication") + bitString); + //test multiplication with real value + stdResult = stdComplex1.real() * stdComplex0; + rtsResult = rtsComplex1.r * rtsComplex0; + compare(stdResult, rtsResult, std::string("Multiplication with Real Value") + bitString); + + //test division + stdResult = stdComplex0 / stdComplex1; + rtsResult = rtsComplex0 / rtsComplex1; + compare(stdResult, rtsResult, std::string("Binary Division") + bitString); + //test division with real value + stdResult = stdComplex1.real() / stdComplex0; + rtsResult = rtsComplex1.r / rtsComplex0; + compare(stdResult, rtsResult, std::string("Division with Real Value") + bitString); + + //test abs() + stdResult = abs(stdComplex0); + rtsResult = abs(rtsComplex0); + compare(stdResult, rtsResult, std::string("abs()") + bitString); + + //test log() + stdResult = log(stdComplex0); + rtsResult = log(rtsComplex0); + compare(stdResult, rtsResult, std::string("log()") + bitString); + + //test exp() + stdResult = exp(stdComplex0); + rtsResult = exp(rtsComplex0); + compare(stdResult, rtsResult, std::string("exp()") + bitString); + + //test pow() + stdResult = pow(stdComplex0, (T)2.0); + rtsResult = pow(rtsComplex0, (T)2.0); + compare(stdResult, rtsResult, std::string("pow()") + bitString); + + //test sqrt() + stdResult = sqrt(stdComplex0); + rtsResult = rts::sqrt(rtsComplex0); + compare(stdResult, rtsResult, std::string("sqrt()") + bitString); + + //trigonometric functions + stdResult = sin(stdComplex0); + rtsResult = rts::sin(rtsComplex0); + compare(stdResult, rtsResult, std::string("sin()") + bitString); + + //trigonometric functions + stdResult = cos(stdComplex0); + rtsResult = rts::cos(rtsComplex0); + compare(stdResult, rtsResult, std::string("cos()") + bitString); + + //ASSIGNMENT OPERATORS + + // += + stdResult = stdComplex0; + stdResult += stdComplex1; + rtsResult = rtsComplex0; + rtsResult += rtsComplex1; + compare(stdResult, rtsResult, std::string("operator +=") + bitString); + + // *= + stdResult = stdComplex0; + stdResult *= stdComplex1; + rtsResult = rtsComplex0; + rtsResult *= rtsComplex1; + compare(stdResult, rtsResult, std::string("operator *=") + bitString); + + // /= + stdResult = stdComplex0; + stdResult /= stdComplex1; + rtsResult = rtsComplex0; + rtsResult /= rtsComplex1; + compare(stdResult, rtsResult, std::string("operator /=") + bitString); + + } +} + +void cpuValidateComplex() +{ + //validate both floating point and double precision + validateOperators(); + validateOperators(); + +} diff --git a/validate/validate-complex.cu b/validate/validate-complex.cu new file mode 100644 index 0000000..9e21509 --- /dev/null +++ b/validate/validate-complex.cu @@ -0,0 +1,172 @@ +#include +#include +#include "rts/complex.h" + +#include "compare.h" + + +template +__global__ void add(rts::complex a, rts::complex b, rts::complex* c) +{ + *c = a + b; +} + +template +__global__ void multiply(rts::complex a, rts::complex b, rts::complex* c) +{ + *c = a * b; +} + +template +__global__ void multiply(rts::complex a, T b, rts::complex* c) +{ + *c = a * b; +} + +template +__global__ void divide(rts::complex a, rts::complex b, rts::complex* c) +{ + *c = a / b; +} + +template +__global__ void log(rts::complex a, rts::complex* c) +{ + *c = rts::log(a); +} + +template +__global__ void sqrt(rts::complex a, rts::complex* c) +{ + *c = rts::sqrt(a); +} + +template +__global__ void exp(rts::complex a, rts::complex* c) +{ + *c = rts::exp(a); +} + +template +__global__ void pow(rts::complex a, rts::complex* c) +{ + *c = rts::pow(a, (T)2.0); +} + +template +__global__ void sin(rts::complex a, rts::complex* c) +{ + *c = rts::sin(a); +} + +template +__global__ void cos(rts::complex a, rts::complex* c) +{ + *c = rts::cos(a); +} + +template +void gpuValidateOperators() +{ + int precision = sizeof(T) * 8; + std::stringstream ss; + ss<<" ("<* gpuResult; + cudaMalloc((void**)&gpuResult, sizeof(rts::complex)); + + //validate complex binary functions + T x0, x1, y0, y1; + for(int i = 0; i stdComplex0(x0, y0); + rts::complex rtsComplex0(x0, y0); + + std::complex stdComplex1(x1, y1); + rts::complex rtsComplex1(x1, y1); + + std::complex stdResult; + rts::complex rtsResult; + + + //test addition + stdResult = stdComplex0 + stdComplex1; + add<<<1, 1>>>(rtsComplex0, rtsComplex1, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("Binary Addition") + bitString); + //std::cout<>>(rtsComplex0, rtsComplex1, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("Binary Multiplication") + bitString); + + //test multiplication with constant + stdResult = stdComplex0 * stdComplex1.real(); + multiply<<<1, 1>>>(rtsComplex0, rtsComplex1.r, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("Multiplication with Real Value") + bitString); + + //test division + stdResult = stdComplex0 / stdComplex1; + divide<<<1, 1>>>(rtsComplex0, rtsComplex1, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("Binary Division") + bitString); + + //test log() + stdResult = log(stdComplex0); + log<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("log()") + bitString); + + //test exp() + stdResult = exp(stdComplex0); + exp<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("exp()") + bitString); + + //test pow() + stdResult = pow(stdComplex0, 2); + pow<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("pow()") + bitString); + + //test sqrt() + stdResult = sqrt(stdComplex0); + sqrt<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("sqrt()") + bitString); + + //trigonometric functions + stdResult = sin(stdComplex0); + sin<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("sin()") + bitString); + + //trigonometric functions + stdResult = cos(stdComplex0); + cos<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("cos()") + bitString); + + + } + cudaFree(gpuResult); + +} + +void gpuValidateComplex() +{ + + gpuValidateOperators(); + //gpuValidateOperators(); +} diff --git a/validate/validate-legendre.cpp b/validate/validate-legendre.cpp new file mode 100644 index 0000000..3ef7ea7 --- /dev/null +++ b/validate/validate-legendre.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include "rts/legendre.h" + +#include "compare.h" + +typedef float precision; +int l = 0; + + +void cpuValidateLegendre() +{ + + //order + precision v = 5; + precision vm; + + //parameter + precision max_z = 2; + int nz = 20; + precision dz = max_z / nz; + + //bessel function results (first and second kind) + int S = sizeof(precision) * (v + 1); + + precision* P = (precision*)malloc(S); + + + std::cout<<"---------j_v(x)-------------"<(v, z, P); + + std::cout<