Commit e4667cee90ab54837ae9450fcd788539c0a4aa0f
0 parents
first commit
Showing
7 changed files
with
902 additions
and
0 deletions
Show diff stats
1 | +++ a/CMakeLists.txt | ||
1 | +#Specify the version being used aswell as the language | ||
2 | +cmake_minimum_required(VERSION 3.12) | ||
3 | + | ||
4 | +#Name your project here | ||
5 | +project(tensorview) | ||
6 | + | ||
7 | +#set the module directory | ||
8 | +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}") | ||
9 | + | ||
10 | +#default to release mode | ||
11 | +if(NOT CMAKE_BUILD_TYPE) | ||
12 | + set(CMAKE_BUILD_TYPE Release) | ||
13 | +endif(NOT CMAKE_BUILD_TYPE) | ||
14 | + | ||
15 | +#build the executable in the binary directory on MS Visual Studio | ||
16 | +if ( MSVC ) | ||
17 | + SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${OUTPUT_DIRECTORY}") | ||
18 | + SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${OUTPUT_DIRECTORY}") | ||
19 | + SET( LIBRARY_OUTPUT_DIRECTORY_DEBUG "${OUTPUT_DIRECTORY}") | ||
20 | + SET( LIBRARY_OUTPUT_DIRECTORY_RELEASE "${OUTPUT_DIRECTORY}") | ||
21 | + add_definitions(-D_CRT_SECURE_NO_WARNINGS) | ||
22 | + add_definitions(-D_SCL_SECURE_NO_WARNINGS) | ||
23 | +endif ( MSVC ) | ||
24 | +#MAYBE REMOVE----------------- | ||
25 | +#set C++11 flags if using GCC | ||
26 | +if( CMAKE_COMPILER_IS_GNUCC ) | ||
27 | + SET( CMAKE_CXX_FLAGS "-std=c++11") | ||
28 | + SET( CUDA_NVCC_FLAGS "-std=c++11") | ||
29 | +endif( CMAKE_COMPILER_IS_GNUCC ) | ||
30 | +#----------------------------- | ||
31 | + | ||
32 | +#find packages----------------------------------- | ||
33 | + | ||
34 | +#find the pthreads package | ||
35 | +find_package(Threads) | ||
36 | + | ||
37 | +#find the X11 package | ||
38 | +find_package(X11) | ||
39 | + | ||
40 | +find_package(GLFW REQUIRED) | ||
41 | +if(WIN32) | ||
42 | + find_package(GLEW REQUIRED) | ||
43 | + include_directories(${GLEW_INCLUDE_DIR}) | ||
44 | +endif(WIN32) | ||
45 | + | ||
46 | +#find and set up OpenGL | ||
47 | +find_package(OpenGL REQUIRED) | ||
48 | + | ||
49 | +find_package(STIM REQUIRED) | ||
50 | + | ||
51 | +add_executable(tensorview | ||
52 | + main.cpp | ||
53 | + tensorfield.h | ||
54 | +) | ||
55 | + | ||
56 | +#include include directories | ||
57 | +include_directories(${GLFW_INCLUDE_DIRS} | ||
58 | + ${OpenGL_INCLUDE_DIRS} | ||
59 | + ${STIM_INCLUDE_DIRS} | ||
60 | +) | ||
61 | + | ||
62 | +target_link_libraries(tensorview | ||
63 | + ${GLFW_LIBRARIES} | ||
64 | + ${OPENGL_gl_LIBRARY} | ||
65 | + ${OPENGL_glu_LIBRARY} | ||
66 | +) | ||
67 | +if(WIN32) | ||
68 | + target_link_libraries(tensorview ${GLEW_GLEW_LIBRARY}) | ||
69 | +endif(WIN32) | ||
0 | \ No newline at end of file | 70 | \ No newline at end of file |
1 | +++ a/FindGLEW.cmake | ||
1 | +# Copyright (c) 2012-2016 DreamWorks Animation LLC | ||
2 | +# | ||
3 | +# All rights reserved. This software is distributed under the | ||
4 | +# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) | ||
5 | +# | ||
6 | +# Redistributions of source code must retain the above copyright | ||
7 | +# and license notice and the following restrictions and disclaimer. | ||
8 | +# | ||
9 | +# * Neither the name of DreamWorks Animation nor the names of | ||
10 | +# its contributors may be used to endorse or promote products derived | ||
11 | +# from this software without specific prior written permission. | ||
12 | +# | ||
13 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
14 | +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
15 | +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
16 | +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
17 | +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, | ||
18 | +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
19 | +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
20 | +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
21 | +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
22 | +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
23 | +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
24 | +# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE | ||
25 | +# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. | ||
26 | +# | ||
27 | + | ||
28 | +#-*-cmake-*- | ||
29 | +# - Find GLEW | ||
30 | +# | ||
31 | +# Author : Nicholas Yue yue.nicholas@gmail.com | ||
32 | +# | ||
33 | +# This auxiliary CMake file helps in find the GLEW headers and libraries | ||
34 | +# | ||
35 | +# GLEW_FOUND set if Glew is found. | ||
36 | +# GLEW_INCLUDE_DIR GLEW's include directory | ||
37 | +# GLEW_GLEW_LIBRARY GLEW libraries | ||
38 | +# GLEW_glewmx_LIBRARY GLEWmx libraries (Mulitple Rendering Context) | ||
39 | + | ||
40 | +FIND_PACKAGE ( PackageHandleStandardArgs ) | ||
41 | + | ||
42 | +FIND_PATH( GLEW_LOCATION include/GL/glew.h | ||
43 | + "$ENV{GLEW_ROOT}" | ||
44 | + NO_DEFAULT_PATH | ||
45 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
46 | + ) | ||
47 | + | ||
48 | +FIND_PACKAGE_HANDLE_STANDARD_ARGS ( GLEW | ||
49 | + REQUIRED_VARS GLEW_LOCATION | ||
50 | + ) | ||
51 | + | ||
52 | +IF ( GLEW_LOCATION ) | ||
53 | + | ||
54 | + SET( GLEW_INCLUDE_DIR "${GLEW_LOCATION}/include" CACHE STRING "GLEW include path") | ||
55 | + | ||
56 | + SET ( ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) | ||
57 | + IF (GLEW_USE_STATIC_LIBS) | ||
58 | + IF (APPLE) | ||
59 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") | ||
60 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | ||
61 | + NO_DEFAULT_PATH | ||
62 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
63 | + ) | ||
64 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | ||
65 | + NO_DEFAULT_PATH | ||
66 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
67 | + ) | ||
68 | + # MESSAGE ( "APPLE STATIC" ) | ||
69 | + # MESSAGE ( "GLEW_LIBRARY_PATH = " ${GLEW_LIBRARY_PATH} ) | ||
70 | + ELSEIF (WIN32) | ||
71 | + # Link library | ||
72 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") | ||
73 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW32S PATHS ${GLEW_LOCATION}/lib ) | ||
74 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEW32MXS PATHS ${GLEW_LOCATION}/lib ) | ||
75 | + ELSE (APPLE) | ||
76 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a") | ||
77 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | ||
78 | + NO_DEFAULT_PATH | ||
79 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
80 | + ) | ||
81 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | ||
82 | + NO_DEFAULT_PATH | ||
83 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
84 | + ) | ||
85 | + # MESSAGE ( "LINUX STATIC" ) | ||
86 | + # MESSAGE ( "GLEW_LIBRARY_PATH = " ${GLEW_LIBRARY_PATH} ) | ||
87 | + ENDIF (APPLE) | ||
88 | + ELSE () | ||
89 | + IF (APPLE) | ||
90 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib") | ||
91 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib ) | ||
92 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib ) | ||
93 | + ELSEIF (WIN32) | ||
94 | + # Link library | ||
95 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") | ||
96 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW32 PATHS ${GLEW_LOCATION}/lib ) | ||
97 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEW32mx PATHS ${GLEW_LOCATION}/lib ) | ||
98 | + # Load library | ||
99 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dll") | ||
100 | + FIND_LIBRARY ( GLEW_DLL_PATH GLEW32 PATHS ${GLEW_LOCATION}/bin | ||
101 | + NO_DEFAULT_PATH | ||
102 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
103 | + ) | ||
104 | + FIND_LIBRARY ( GLEWmx_DLL_PATH GLEW32mx PATHS ${GLEW_LOCATION}/bin | ||
105 | + NO_DEFAULT_PATH | ||
106 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
107 | + ) | ||
108 | + ELSE (APPLE) | ||
109 | + # Unices | ||
110 | + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib | ||
111 | + NO_DEFAULT_PATH | ||
112 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
113 | + ) | ||
114 | + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib | ||
115 | + NO_DEFAULT_PATH | ||
116 | + NO_SYSTEM_ENVIRONMENT_PATH | ||
117 | + ) | ||
118 | + ENDIF (APPLE) | ||
119 | + ENDIF () | ||
120 | + # MUST reset | ||
121 | + SET(CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES}) | ||
122 | + | ||
123 | + SET( GLEW_GLEW_LIBRARY ${GLEW_LIBRARY_PATH} CACHE STRING "GLEW library") | ||
124 | + SET( GLEW_GLEWmx_LIBRARY ${GLEWmx_LIBRARY_PATH} CACHE STRING "GLEWmx library") | ||
125 | + | ||
126 | +ENDIF () |
1 | +++ a/FindGLFW.cmake | ||
1 | +# Find GLFW 3 | ||
2 | +# | ||
3 | +# GLFW_LIBRARIES | ||
4 | +# GLFW_INCLUDE_DIRS. | ||
5 | +# GLFW_FOUND | ||
6 | +set(GLFW_ROOT $ENV{GLFW_ROOT}) | ||
7 | +IF(NOT UNIX) | ||
8 | + IF(NOT GLFW_ROOT) | ||
9 | + MESSAGE("ERROR: GLFW_ROOT must be set!") | ||
10 | + ENDIF(NOT GLFW_ROOT) | ||
11 | + | ||
12 | + FIND_PATH(GLFW_INCLUDE_DIRS DOC "Path to GLFW include directory." | ||
13 | + NAMES GLFW/glfw3.h | ||
14 | + PATHS ${GLFW_ROOT}/include) | ||
15 | + IF(MSVC15) | ||
16 | + FIND_LIBRARY(GLFW_LIBRARIES DOC "Absolute path to GLFW library." | ||
17 | + NAMES glfw3.lib | ||
18 | + PATHS ${GLFW_ROOT}/lib-vc2015) | ||
19 | + ELSEIF(MSVC13) | ||
20 | + FIND_LIBRARY(GLFW_LIBRARIES DOC "Absolute path to GLFW library." | ||
21 | + NAMES glfw3.lib | ||
22 | + PATHS ${GLFW_ROOT}/lib-vc2013) | ||
23 | + ELSEIF(MSVC12) | ||
24 | + FIND_LIBRARY(GLFW_LIBRARIES DOC "Absolute path to GLFW library." | ||
25 | + NAMES glfw3.lib | ||
26 | + PATHS ${GLFW_ROOT}/lib-vc2012) | ||
27 | + ELSEIF(MSVC10) | ||
28 | + FIND_LIBRARY(GLFW_LIBRARIES DOC "Absolute path to GLFW library." | ||
29 | + NAMES glfw3.lib | ||
30 | + PATHS ${GLFW_ROOT}/lib-vc2010) | ||
31 | + ELSEIF(MINGW) | ||
32 | + IF(CMAKE_CL_64) | ||
33 | + FIND_LIBRARY(GLFW_LIBRARIES DOC "Absolute path to GLFW library." | ||
34 | + NAMES glfw3.dll | ||
35 | + PATHS ${GLFW_ROOT}/lib-mingw-w64) | ||
36 | + ELSE(CMAKE_CL_64) | ||
37 | + FIND_LIBRARY(GLFW_LIBRARIES DOC "Absolute path to GLFW library." | ||
38 | + NAMES glfw3.dll | ||
39 | + PATHS ${GLFW_ROOT}/lib-mingw) | ||
40 | + ENDIF(CMAKE_CL_64) | ||
41 | + ELSE(MINGW) | ||
42 | + # Default to latest version of VC libs | ||
43 | + FIND_LIBRARY(GLFW_LIBRARIES DOC "Absolute path to GLFW library." | ||
44 | + NAMES glfw3.lib | ||
45 | + PATHS ${GLFW_ROOT}/lib-vc2015) | ||
46 | + ENDIF(MSVC15) | ||
47 | +ELSE(NOT UNIX) | ||
48 | + FIND_PATH(GLFW_INCLUDE_DIRS DOC "Path to GLFW include directory." | ||
49 | + NAMES GLFW/glfw3.h | ||
50 | + PATHS | ||
51 | + /usr/include | ||
52 | + /usr/local/include | ||
53 | + /usr/target/include | ||
54 | + /sw/include | ||
55 | + /opt/local/include) | ||
56 | + | ||
57 | + FIND_LIBRARY(GLFW_LIBRARIES DOC "Absolute path to GLFW library." | ||
58 | + NAMES glfw3.dll | ||
59 | + PATHS | ||
60 | + /usr/local/lib | ||
61 | + /usr/lib | ||
62 | + /lib) | ||
63 | +ENDIF(NOT UNIX) | ||
64 | + | ||
65 | +include(FindPackageHandleStandardArgs) | ||
66 | +find_package_handle_standard_args(GLFW DEFAULT_MSG GLFW_LIBRARIES GLFW_INCLUDE_DIRS) | ||
67 | + | ||
68 | +mark_as_advanced(GLFW_INCLUDE_DIRS GLFW_LIBRARIES) |
1 | +++ a/FindSTIM.cmake | ||
1 | +# finds the STIM library (downloads it if it isn't present) | ||
2 | +# set STIMLIB_PATH to the directory containing the stim subdirectory (the stim repository) | ||
3 | + | ||
4 | +include(FindPackageHandleStandardArgs) | ||
5 | + | ||
6 | +set(STIM_ROOT $ENV{STIM_ROOT}) | ||
7 | + | ||
8 | +IF(NOT UNIX) | ||
9 | + IF(NOT STIM_ROOT) | ||
10 | + MESSAGE("ERROR: STIM_ROOT environment variable must be set!") | ||
11 | + ENDIF(NOT STIM_ROOT) | ||
12 | + | ||
13 | + FIND_PATH(STIM_INCLUDE_DIRS DOC "Path to GLFW include directory." | ||
14 | + NAMES stim/image/image.h | ||
15 | + PATHS ${STIM_ROOT}) | ||
16 | +ENDIF(NOT UNIX) | ||
17 | + | ||
18 | +find_package_handle_standard_args(STIM DEFAULT_MSG STIM_INCLUDE_DIRS) | ||
19 | + | ||
20 | +if(STIM_FOUND) | ||
21 | + set(STIM_INCLUDE_DIRS ${STIM_INCLUDE_DIRS}) | ||
22 | +elseif(STIM_FOUND) | ||
23 | + message("STIM library not found. Set the STIM_ROOT environment variable to the STIM location.") | ||
24 | + message("STIMLIB can be found here: https://git.stim.ee.uh.edu/codebase/stimlib") | ||
25 | +endif(STIM_FOUND) | ||
26 | + | ||
27 | +find_package_handle_standard_args(STIM DEFAULT_MSG STIM_INCLUDE_DIRS) |
1 | +++ a/main.cpp | ||
1 | +#include <GL/glew.h> | ||
2 | +#include <GLFW/glfw3.h> | ||
3 | + | ||
4 | +#include <iostream> | ||
5 | +#include <vector> | ||
6 | +const double PI = 3.14159265358979323846; | ||
7 | + | ||
8 | +#include "tensorfield.h" | ||
9 | +#include <stim/math/quaternion.h> | ||
10 | +//#include <stim/> | ||
11 | + | ||
12 | +// Global variable to store the GLFW window | ||
13 | +GLFWwindow* window; | ||
14 | +tensorfield<float> T; | ||
15 | +size_t z_slice = 0; | ||
16 | +bool cout_frame = false; | ||
17 | + | ||
18 | +float diffuse_intensity = 0.7f; | ||
19 | +float ambient_intensity = 0.3f; | ||
20 | + | ||
21 | +int glyph_type = 1; | ||
22 | +float gamma = 3; | ||
23 | +int glyph_resolution = 10; | ||
24 | +float glyph_scale = 0.5; | ||
25 | + | ||
26 | +//glyph vertices | ||
27 | +bool glyph_calculated = false; | ||
28 | + | ||
29 | +struct float3 { | ||
30 | + float x; | ||
31 | + float y; | ||
32 | + float z; | ||
33 | +}; | ||
34 | + | ||
35 | +struct float2 { | ||
36 | + float u; | ||
37 | + float v; | ||
38 | +}; | ||
39 | + | ||
40 | +std::vector<float3> vertices; | ||
41 | +std::vector<float3> normals; | ||
42 | +std::vector<float2> texcoords; | ||
43 | +std::vector<float> sin_theta; | ||
44 | +std::vector<float> cos_theta; | ||
45 | +std::vector<float> sin_phi; | ||
46 | +std::vector<float> cos_phi; | ||
47 | + | ||
48 | +struct eigendecomposition { | ||
49 | + | ||
50 | + stim::vec3<float> v0; | ||
51 | + stim::vec3<float> v2; | ||
52 | + stim::vec3<float> lambda; | ||
53 | +}; | ||
54 | + | ||
55 | +inline float sgn(float x) { | ||
56 | + if (x < 0) | ||
57 | + return -1; | ||
58 | + else if (x > 0) | ||
59 | + return 1; | ||
60 | + return 0; | ||
61 | +} | ||
62 | + | ||
63 | +stim::vec3<float> triangle_norm(stim::vec3<float> p0, stim::vec3<float> p1, stim::vec3<float> p2) { | ||
64 | + stim::vec3<float> a = p1 - p0; | ||
65 | + stim::vec3<float> b = p2 - p0; | ||
66 | + stim::vec3<float> n = a.cross(b); | ||
67 | + return n; | ||
68 | +} | ||
69 | + | ||
70 | + | ||
71 | +// returns the fractional anisotropy and stores the spherical, linear, and planar components in cs, cl, and cp | ||
72 | +float get_anisotropy(stim::vec3<float> lambda, float& cs, float& cl, float& cp) { | ||
73 | + | ||
74 | + //calculate the denominator for each specific anisotropy | ||
75 | + float denom = lambda[0] + lambda[1] + lambda[2]; | ||
76 | + | ||
77 | + cl = (lambda[2] - lambda[1]) / denom; | ||
78 | + cp = 2 * (lambda[1] - lambda[0]) / denom; | ||
79 | + cs = 3 * lambda[0] / denom; | ||
80 | + | ||
81 | + return 0; | ||
82 | +} | ||
83 | + | ||
84 | +//calculate the eigenvectors and eigenvalues for the input pixel (x, y, z) | ||
85 | +// eigenvalues are embedded in the length of the eigenvector | ||
86 | +void get_pixel_eigen(eigendecomposition* e, size_t x, size_t y, size_t z) { | ||
87 | + | ||
88 | + e->v0[0] = T(x, y, z, 0, 0); | ||
89 | + e->v0[1] = T(x, y, z, 1, 0); | ||
90 | + e->v0[2] = T(x, y, z, 2, 0); | ||
91 | + | ||
92 | + //temporarily store v1 in order to get the eigenvalue | ||
93 | + // (the eigenvector is redundant because it's the cross product of v0 and v1) | ||
94 | + stim::vec3<float> v1; | ||
95 | + v1[0] = T(x, y, z, 0, 1); | ||
96 | + v1[1] = T(x, y, z, 1, 1); | ||
97 | + v1[2] = T(x, y, z, 2, 1); | ||
98 | + | ||
99 | + e->v2[0] = T(x, y, z, 0, 2); | ||
100 | + e->v2[1] = T(x, y, z, 1, 2); | ||
101 | + e->v2[2] = T(x, y, z, 2, 2); | ||
102 | + | ||
103 | + e->lambda[0] = e->v0.len(); | ||
104 | + e->lambda[1] = v1.len(); | ||
105 | + e->lambda[2] = e->v2.len(); | ||
106 | + e->v0 = e->v0 / e->lambda[0]; | ||
107 | + e->v2 = e->v2 / e->lambda[2]; | ||
108 | +} | ||
109 | + | ||
110 | +/// Create a rotation matrix to orient a glyph along the tensor direction. Orientations are based on the input vectors | ||
111 | +/// v0, v1, and v2 | ||
112 | +void get_glyph_rotation_matrix(float* R, stim::vec3<float> v0, stim::vec3<float> v2) { | ||
113 | + | ||
114 | + stim::matrix_sq<float, 4> M; | ||
115 | + M(0, 0) = v0[0]; | ||
116 | + M(1, 0) = v0[1]; | ||
117 | + M(2, 0) = v0[2]; | ||
118 | + M(3, 0) = 0; | ||
119 | + | ||
120 | + M(0, 2) = v2[0]; | ||
121 | + M(1, 2) = v2[1]; | ||
122 | + M(2, 2) = v2[2]; | ||
123 | + M(3, 2) = 0; | ||
124 | + | ||
125 | + stim::vec3<float> a(v0[0], v0[1], v0[2]); | ||
126 | + stim::vec3<float> b(v2[0], v2[1], v2[2]); | ||
127 | + stim::vec3<float> c = a.cross(b); | ||
128 | + | ||
129 | + M(0, 1) = c[0]; | ||
130 | + M(1, 1) = c[1]; | ||
131 | + M(2, 1) = c[2]; | ||
132 | + M(3, 1) = 0; | ||
133 | + | ||
134 | + M(0, 3) = 0; | ||
135 | + M(1, 3) = 0; | ||
136 | + M(2, 3) = 0; | ||
137 | + M(3, 3) = 1; | ||
138 | + | ||
139 | + memcpy(R, M.M, 16 * sizeof(float)); | ||
140 | + return; | ||
141 | +} | ||
142 | + | ||
143 | + | ||
144 | +// Perform the necessary updates when the user reshapes the window | ||
145 | +void window_reshape() { | ||
146 | + int width, height; | ||
147 | + | ||
148 | + //get the context size | ||
149 | + glfwGetFramebufferSize(window, &width, &height); | ||
150 | + | ||
151 | + | ||
152 | + //create an OpenGL viewport | ||
153 | + glViewport(0, 0, width, height); | ||
154 | + | ||
155 | + //set the default orthographic view (assuming that the window and image aspect ratio are identical) | ||
156 | + float left = 0.0f; | ||
157 | + float right = (float)T.shape[2]; | ||
158 | + float bottom = 0.0f; | ||
159 | + float top = (float)T.shape[1]; | ||
160 | + | ||
161 | + //create an orthographic projection | ||
162 | + glMatrixMode(GL_PROJECTION); | ||
163 | + glLoadIdentity(); | ||
164 | + gluOrtho2D(left, right, bottom, top); | ||
165 | + | ||
166 | + glMatrixMode(GL_MODELVIEW); | ||
167 | + glLoadIdentity(); | ||
168 | +} | ||
169 | + | ||
170 | +void init() { | ||
171 | + glEnable(GL_DEPTH_TEST); | ||
172 | + glEnable(GL_CULL_FACE); | ||
173 | + glFrontFace(GL_CCW); | ||
174 | +} | ||
175 | + | ||
176 | +void generate_glyph_points(int resolution = 5) { | ||
177 | + int sectorCount = 2 * resolution; | ||
178 | + int stackCount = resolution; | ||
179 | + | ||
180 | + int num_vertices = (sectorCount + 1) * (stackCount + 1); | ||
181 | + sin_theta.resize(num_vertices); | ||
182 | + sin_phi.resize(num_vertices); | ||
183 | + cos_theta.resize(num_vertices); | ||
184 | + cos_phi.resize(num_vertices); | ||
185 | + | ||
186 | + float theta, phi; // vertex texCoord | ||
187 | + | ||
188 | + float sectorStep = 2 * (float)PI / sectorCount; | ||
189 | + float stackStep = (float)PI / stackCount; | ||
190 | + | ||
191 | + size_t i = 0; | ||
192 | + //calculate the vertex positions | ||
193 | + for (int phi_i = 0; phi_i <= stackCount; ++phi_i) | ||
194 | + { | ||
195 | + | ||
196 | + // add (sectorCount+1) vertices per stack | ||
197 | + // the first and last vertices have same position and normal, but different tex coords | ||
198 | + for (int theta_i = 0; theta_i <= sectorCount; ++theta_i) | ||
199 | + { | ||
200 | + | ||
201 | + // calculate the spherical coordinates of the vertex | ||
202 | + theta = (float)theta_i / sectorCount * 2 * (float)PI; | ||
203 | + phi = (float)phi_i / stackCount * (float)PI; | ||
204 | + | ||
205 | + //pre-compute the sine and cosine values used to create the superquadric | ||
206 | + sin_theta[i] = sinf(theta); | ||
207 | + sin_phi[i] = sinf(phi); | ||
208 | + cos_theta[i] = cosf(theta); | ||
209 | + cos_phi[i] = cosf(phi); | ||
210 | + i++; | ||
211 | + } | ||
212 | + } | ||
213 | +} | ||
214 | + | ||
215 | +inline float weird_exp(float x, float e) { | ||
216 | + return sgn(x) * powf(fabs(x), e); | ||
217 | +} | ||
218 | + | ||
219 | +stim::vec3<float> qx(size_t i, float alpha = 1, float beta = 1) { | ||
220 | + | ||
221 | + float sin_phi_beta = weird_exp(sin_phi[i], beta); | ||
222 | + float sin_theta_alpha = weird_exp(sin_theta[i], alpha); | ||
223 | + float cos_theta_alpha = weird_exp(cos_theta[i], alpha); | ||
224 | + float cos_phi_beta = weird_exp(cos_phi[i], beta); | ||
225 | + | ||
226 | + stim::vec3<float> p; | ||
227 | + p[0] = cos_phi_beta; | ||
228 | + p[1] = -sin_theta_alpha * sin_phi_beta; | ||
229 | + p[2] = cos_theta_alpha * sin_phi_beta; | ||
230 | + return p; | ||
231 | +} | ||
232 | + | ||
233 | +void render_triangle(stim::vec3<float> p0, stim::vec3<float> p1, stim::vec3<float> p2) { | ||
234 | + stim::vec3<float> n = triangle_norm(p0, p1, p2); | ||
235 | + | ||
236 | + glNormal3f(n[0], n[1], n[2]); | ||
237 | + glVertex3f(p0[0], p0[1], p0[2]); | ||
238 | + glVertex3f(p1[0], p1[1], p1[2]); | ||
239 | + glVertex3f(p2[0], p2[1], p2[2]); | ||
240 | +} | ||
241 | + | ||
242 | +//render a glyph (0 = ellipsoid, 1 = superquadric) | ||
243 | +void render_glyph(eigendecomposition* e, int glyph_type = 0, int resolution = 5) { | ||
244 | + glMatrixMode(GL_MODELVIEW); | ||
245 | + glPushMatrix(); | ||
246 | + | ||
247 | + stim::vec3<float> norm_lambda = e->lambda.norm(); | ||
248 | + glScalef(glyph_scale, glyph_scale, glyph_scale); | ||
249 | + glScalef(norm_lambda[2], norm_lambda[1], norm_lambda[0]); | ||
250 | + | ||
251 | + if (glyph_type == 0) { | ||
252 | + GLUquadric* q = gluNewQuadric(); | ||
253 | + gluSphere(q, 1, 2 * resolution, resolution); | ||
254 | + } | ||
255 | + else if (glyph_type == 1) { | ||
256 | + float radius = 0.5; | ||
257 | + int sectorCount = 2 * resolution; | ||
258 | + int stackCount = resolution; | ||
259 | + | ||
260 | + if (!glyph_calculated) { | ||
261 | + generate_glyph_points(resolution); | ||
262 | + glyph_calculated = true; | ||
263 | + } | ||
264 | + | ||
265 | + //get the anisotropy values | ||
266 | + float fa, cs, cl, cp, alpha, beta; | ||
267 | + fa = get_anisotropy(e->lambda, cs, cl, cp); | ||
268 | + | ||
269 | + if (cl >= cp) { | ||
270 | + alpha = powf(1 - cp, gamma); | ||
271 | + beta = powf(1 - cl, gamma); | ||
272 | + } | ||
273 | + else { | ||
274 | + alpha = powf(1 - cl, gamma); | ||
275 | + beta = powf(1 - cp, gamma); | ||
276 | + } | ||
277 | + | ||
278 | + //draw the sphere | ||
279 | + int k1, k2; | ||
280 | + float3 p[3]; | ||
281 | + float2 s[3]; | ||
282 | + float3 n; | ||
283 | + | ||
284 | + //draw the glyph | ||
285 | + glBegin(GL_TRIANGLES); | ||
286 | + for (int i = 0; i < stackCount; ++i) | ||
287 | + { | ||
288 | + k1 = i * (sectorCount + 1); // beginning of current stack | ||
289 | + k2 = k1 + sectorCount + 1; // beginning of next stack | ||
290 | + | ||
291 | + for (int j = 0; j < sectorCount; ++j, ++k1, ++k2) | ||
292 | + { | ||
293 | + // 2 triangles per sector excluding first and last stacks | ||
294 | + // k1 => k2 => k1+1 | ||
295 | + if (i != 0) | ||
296 | + { | ||
297 | + | ||
298 | + stim::vec3<float> p0 = qx(k1, alpha, beta); | ||
299 | + stim::vec3<float> p1 = qx(k2, alpha, beta); | ||
300 | + stim::vec3<float> p2 = qx(k1 + 1, alpha, beta); | ||
301 | + | ||
302 | + render_triangle(p0, p1, p2); | ||
303 | + } | ||
304 | + | ||
305 | + // k1+1 => k2 => k2+1 | ||
306 | + if (i != (stackCount - 1)) | ||
307 | + { | ||
308 | + stim::vec3<float> p0 = qx(k1 + 1, alpha, beta); | ||
309 | + stim::vec3<float> p1 = qx(k2, alpha, beta); | ||
310 | + stim::vec3<float> p2 = qx(k2 + 1, alpha, beta); | ||
311 | + | ||
312 | + render_triangle(p0, p1, p2); | ||
313 | + } | ||
314 | + } | ||
315 | + } | ||
316 | + glEnd(); | ||
317 | + } | ||
318 | + glPopMatrix(); | ||
319 | +} | ||
320 | + | ||
321 | +void lighting() { | ||
322 | + | ||
323 | + GLfloat light_position[] = { 1, 1, -1.0, 0.0 }; | ||
324 | + GLfloat light_ambient[] = { ambient_intensity, ambient_intensity, ambient_intensity, 1.0 }; | ||
325 | + GLfloat light_diffuse[] = { diffuse_intensity, diffuse_intensity, diffuse_intensity, 1.0 }; | ||
326 | + glShadeModel(GL_SMOOTH); | ||
327 | + | ||
328 | + glLightfv(GL_LIGHT0, GL_POSITION, light_position); | ||
329 | + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); | ||
330 | + glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); | ||
331 | + | ||
332 | + glEnable(GL_LIGHTING); | ||
333 | + glEnable(GL_LIGHT0); | ||
334 | + | ||
335 | + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); | ||
336 | + glEnable(GL_COLOR_MATERIAL); | ||
337 | + glEnable(GL_NORMALIZE); | ||
338 | + | ||
339 | +} | ||
340 | +void render() { | ||
341 | + size_t zi = z_slice; | ||
342 | + | ||
343 | + float dc = 1.0f / T.shape[1]; | ||
344 | + float c[3]; | ||
345 | + eigendecomposition e; | ||
346 | + float R[16]; | ||
347 | + | ||
348 | + | ||
349 | + glMatrixMode(GL_MODELVIEW_MATRIX); | ||
350 | + | ||
351 | + lighting(); | ||
352 | + | ||
353 | + for (size_t yi = 0; yi < T.shape[1]; yi++) { | ||
354 | + for (size_t xi = 0; xi < T.shape[2]; xi++) { | ||
355 | + get_pixel_eigen(&e, xi, yi, zi); | ||
356 | + | ||
357 | + c[0] = abs(e.v0[0]); | ||
358 | + c[1] = abs(e.v0[1]); | ||
359 | + c[2] = abs(e.v0[2]); | ||
360 | + | ||
361 | + glPushMatrix(); | ||
362 | + | ||
363 | + | ||
364 | + glTranslatef((float)xi + 0.5f, (float)yi + 0.5f, 0); | ||
365 | + | ||
366 | + stim::vec3<float> v0(e.v0[0], e.v0[1], e.v0[2]); | ||
367 | + stim::vec3<float> v2(e.v2[0], e.v2[1], e.v2[2]); | ||
368 | + get_glyph_rotation_matrix(R, v0,v2); | ||
369 | + glMultMatrixf((GLfloat*)R); | ||
370 | + | ||
371 | + glColor3f(c[0], c[1], c[2]); | ||
372 | + render_glyph(&e, glyph_type, glyph_resolution); | ||
373 | + | ||
374 | + | ||
375 | + glPopMatrix(); | ||
376 | + } | ||
377 | + } | ||
378 | + cout_frame = false; | ||
379 | + | ||
380 | +} | ||
381 | + | ||
382 | +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) | ||
383 | +{ | ||
384 | + if (key == GLFW_KEY_RIGHT && action != GLFW_RELEASE) | ||
385 | + z_slice++; | ||
386 | + else if (key == GLFW_KEY_LEFT && action != GLFW_RELEASE) | ||
387 | + z_slice--; | ||
388 | + if (z_slice >= T.shape[0]) z_slice = 0; | ||
389 | + if (z_slice < 0) z_slice = T.shape[0] - 1; | ||
390 | +} | ||
391 | + | ||
392 | +void display_rotation_matrix(eigendecomposition* e) { | ||
393 | + float R[16]; | ||
394 | + stim::vec3<float> v0(e->v0[0], e->v0[1], e->v0[2]); | ||
395 | + stim::vec3<float> v2(e->v2[0], e->v2[1], e->v2[2]); | ||
396 | + get_glyph_rotation_matrix(R, v0, v2); | ||
397 | + for (int r = 0; r < 4; r++) { | ||
398 | + for (int c = 0; c < 4; c++) { | ||
399 | + std::cout << R[r * 4 + c] << " "; | ||
400 | + } | ||
401 | + std::cout << std::endl; | ||
402 | + } | ||
403 | +} | ||
404 | + | ||
405 | + | ||
406 | +void display_eigen(eigendecomposition* e) { | ||
407 | + std::cout << "v0 = (" << e->v0[0] << ", " << e->v0[1] << ", " << e->v0[2] << ")" << std::endl; | ||
408 | +} | ||
409 | + | ||
410 | +void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { | ||
411 | + //if the user clicks inside the window, display information about the tensor field | ||
412 | + if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) { | ||
413 | + double xpos, ypos; | ||
414 | + glfwGetCursorPos(window, &xpos, &ypos); //get the position of the mouse pointer | ||
415 | + int width, height; | ||
416 | + glfwGetFramebufferSize(window, &width, &height); | ||
417 | + int pixel_x = (int)(xpos / width * T.shape[2]); | ||
418 | + int pixel_y = T.shape[1] - (int)(ypos / height * (int)T.shape[1]) - 1; | ||
419 | + std::cout << "----------------------------" << std::endl; | ||
420 | + std::cout << "x: " << pixel_x << " y: " << pixel_y << std::endl; | ||
421 | + std::cout << "----------------------------" << std::endl; | ||
422 | + eigendecomposition e; | ||
423 | + get_pixel_eigen(&e, pixel_x, pixel_y, z_slice); | ||
424 | + display_eigen(&e); | ||
425 | + std::cout << "===========" << std::endl; | ||
426 | + display_rotation_matrix(&e); | ||
427 | + } | ||
428 | +} | ||
429 | + | ||
430 | +void reshape_callback(GLFWwindow* window, int width, int height) { | ||
431 | + window_reshape(); | ||
432 | + render(); | ||
433 | +} | ||
434 | + | ||
435 | + | ||
436 | +int main(int argc, char** argv) { | ||
437 | + std::string filename(argv[1]); | ||
438 | + if (T.load_tira(filename) != TIRA_SUCCESS) { | ||
439 | + return -1; | ||
440 | + } | ||
441 | + | ||
442 | + /* Initialize the library */ | ||
443 | + if (!glfwInit()) | ||
444 | + return -1; | ||
445 | + | ||
446 | + | ||
447 | + /* Create a windowed mode window and its OpenGL context */ | ||
448 | + window = glfwCreateWindow(700, 700, "Hello World", NULL, NULL); | ||
449 | + if (!window) | ||
450 | + { | ||
451 | + glfwTerminate(); | ||
452 | + return -1; | ||
453 | + } | ||
454 | + | ||
455 | + /* Make the window's context current */ | ||
456 | + glfwMakeContextCurrent(window); | ||
457 | + | ||
458 | + glfwSetKeyCallback(window, key_callback); | ||
459 | + glfwSetFramebufferSizeCallback(window, reshape_callback); | ||
460 | + glfwSetMouseButtonCallback(window, mouse_button_callback); | ||
461 | + | ||
462 | + GLenum err = glewInit(); | ||
463 | + //deal with a GLEW initialization failure | ||
464 | + if (GLEW_OK != err) | ||
465 | + std::cout << "GLEW Error: " << glewGetErrorString(err) << std::endl; | ||
466 | + | ||
467 | + //set up the window viewport | ||
468 | + window_reshape(); | ||
469 | + | ||
470 | + //initialize the OpenGL render details | ||
471 | + init(); | ||
472 | + | ||
473 | + /* Loop until the user closes the window */ | ||
474 | + while (!glfwWindowShouldClose(window)) | ||
475 | + { | ||
476 | + /* Render here */ | ||
477 | + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
478 | + | ||
479 | + render(); | ||
480 | + | ||
481 | + /* Swap front and back buffers */ | ||
482 | + glfwSwapBuffers(window); | ||
483 | + | ||
484 | + /* Poll for and process events */ | ||
485 | + glfwPollEvents(); | ||
486 | + } | ||
487 | + | ||
488 | + glfwTerminate(); | ||
489 | + return 0; | ||
490 | +} | ||
0 | \ No newline at end of file | 491 | \ No newline at end of file |
1 | +++ a/tensorfield.cpp |
1 | +++ a/tensorfield.h | ||
1 | +#ifndef TIRA_TENSORFIELD | ||
2 | +#define TIRA_TENSORFIELD | ||
3 | + | ||
4 | +#include <valarray> | ||
5 | +#include <string> | ||
6 | +#include <fstream> | ||
7 | +#include <initializer_list> | ||
8 | + | ||
9 | +enum tira_floattype {unused0, unused1, float16, unused3, float32, unused4, unused5, unused6, unused7, float64}; | ||
10 | +enum tira_error {TIRA_SUCCESS, TIRA_UNDEFINED, TIRA_FILE_OPEN_ERROR, TIRA_UNKNOWN_FILE_TYPE}; | ||
11 | +enum tira_filetype {unused, spectrum, tensor2}; | ||
12 | +struct tira_header { | ||
13 | + std::valarray<size_t> shape; //stores the resolution of the tensor field along each dimension | ||
14 | + tira_filetype filetype; //stores the file type | ||
15 | + tira_floattype datatype; //stores the data type of the tensor field | ||
16 | + float version; //file version | ||
17 | +}; | ||
18 | + | ||
19 | +tira_error tira_load_header(std::ifstream &infile, tira_header &header) { | ||
20 | + | ||
21 | + //see if the file represents a TIRA structure | ||
22 | + unsigned char TIRA[5]; | ||
23 | + TIRA[4] = 0; | ||
24 | + infile.read((char*)TIRA, 4); | ||
25 | + if (strcmp((char*)TIRA, "TIRA") != 0) | ||
26 | + return TIRA_UNKNOWN_FILE_TYPE; | ||
27 | + | ||
28 | + //get the file type | ||
29 | + infile.read((char*)&(header.filetype), sizeof(tira_filetype)); | ||
30 | + | ||
31 | + //get the version | ||
32 | + infile.read((char*)&(header.version), sizeof(float)); | ||
33 | + | ||
34 | + //get the number of dimensions in the field | ||
35 | + size_t ndim; | ||
36 | + infile.read((char*)&ndim, sizeof(size_t)); | ||
37 | + header.shape.resize(ndim); | ||
38 | + | ||
39 | + //read each dimension | ||
40 | + for (int d = 0; d < ndim; d++) | ||
41 | + infile.read((char*)&(header.shape[d]), sizeof(size_t)); | ||
42 | + | ||
43 | + //read the data type | ||
44 | + infile.read((char*)&(header.datatype), sizeof(tira_floattype)); | ||
45 | + | ||
46 | + return TIRA_SUCCESS; | ||
47 | +} | ||
48 | + | ||
49 | +template <typename T> | ||
50 | +class tensorfield { | ||
51 | +public: | ||
52 | + | ||
53 | + std::valarray<size_t> shape; //number of samples in each dimension | ||
54 | + std::valarray<size_t> cum_offsets; //cumulative factors for fast array accesses | ||
55 | + tira_filetype filetype; //stores the file type | ||
56 | + tira_floattype datatype; //stores the data type of the tensor field | ||
57 | + T* ptr; //pointer to the raw tensor data | ||
58 | + | ||
59 | + void init() { | ||
60 | + size_t ndims = shape.size(); //get the number of dimensions | ||
61 | + cum_offsets.resize(ndims); //allocate space for the cumulative offsets | ||
62 | + size_t cum = 1; | ||
63 | + for (int i = 0; i < ndims; i++) { | ||
64 | + cum_offsets[ndims - 1 - i] = cum; | ||
65 | + cum *= shape[ndims - 1 - i]; | ||
66 | + } | ||
67 | + } | ||
68 | + | ||
69 | + size_t bytes() { | ||
70 | + size_t product = 1; | ||
71 | + for (size_t i = 0; i < shape.size(); i++) | ||
72 | + product *= shape[i]; | ||
73 | + return product * (size_t)datatype; | ||
74 | + } | ||
75 | + | ||
76 | + // Function turns a series of array indices into a 1D index to the corresponding element | ||
77 | + inline size_t idx(std::initializer_list<size_t> coords) { | ||
78 | + size_t index = 0; | ||
79 | + size_t i = 0; | ||
80 | + for (auto c : coords) { | ||
81 | + index += c * cum_offsets[i]; | ||
82 | + i++; | ||
83 | + } | ||
84 | + return index; | ||
85 | + } | ||
86 | + | ||
87 | + tira_error load_tira(std::string filename) { | ||
88 | + | ||
89 | + //open the file for binary reading | ||
90 | + std::ifstream infile(filename, std::ios::binary); | ||
91 | + if (!infile) return TIRA_FILE_OPEN_ERROR; | ||
92 | + | ||
93 | + tira_header header; | ||
94 | + tira_load_header(infile, header); | ||
95 | + shape = header.shape; | ||
96 | + filetype = header.filetype; | ||
97 | + datatype = header.datatype; | ||
98 | + | ||
99 | + //allocate space in memory for the tensor field | ||
100 | + size_t size_bytes = bytes(); | ||
101 | + ptr = (T*)malloc(size_bytes); | ||
102 | + | ||
103 | + //copy data from the file to memory | ||
104 | + infile.read((char*)ptr, bytes()); | ||
105 | + | ||
106 | + //close the file | ||
107 | + infile.close(); | ||
108 | + | ||
109 | + //initialize all internal variables | ||
110 | + init(); | ||
111 | + | ||
112 | + return TIRA_SUCCESS; | ||
113 | + } | ||
114 | + | ||
115 | + T& operator()(size_t x, size_t y, size_t z, size_t r, size_t c) { | ||
116 | + size_t i = idx({ z, y, x, r, c }); | ||
117 | + return ptr[i]; | ||
118 | + } | ||
119 | + | ||
120 | +}; | ||
121 | + | ||
122 | +#endif | ||
0 | \ No newline at end of file | 123 | \ No newline at end of file |