glviewvol
view src/volume.cc @ 12:773f89037a35
added copyright headers
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 31 Dec 2014 07:57:04 +0200 |
parents | 04330eb80b36 |
children | 0d2447b9c512 |
line source
1 /*
2 glviewvol is an OpenGL 3D volume data viewer
3 Copyright (C) 2014 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <alloca.h>
22 #include <errno.h>
23 #include <math.h>
24 #include "volume.h"
26 static char *strip_space(char *s);
29 Volume::~Volume()
30 {
31 }
33 int Volume::num_samples(int dim) const
34 {
35 return 0;
36 }
38 void Volume::normalf(float *norm, float x, float y, float z, float delta)
39 {
40 float dx, dy, dz;
41 dx = dy = dz = delta;
43 if(num_samples(0) > 0) {
44 // discrete volume
45 dx /= (float)num_samples(0);
46 dy /= (float)num_samples(1);
47 dz /= (float)num_samples(2);
48 }
50 norm[0] = valuef(x + dx, y, z) - valuef(x - dx, y, z);
51 norm[1] = valuef(x, y + dy, z) - valuef(x, y - dy, z);
52 norm[2] = valuef(x, y, z + dz) - valuef(x, y, z - dz);
54 float len = sqrt(norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
55 if(len != 0.0) {
56 norm[0] /= len;
57 norm[1] /= len;
58 norm[2] /= len;
59 }
60 }
62 void Volume::normali(float *norm, int x, int y, int z)
63 {
64 int sz[3];
66 if((sz[0] = num_samples(0)) <= 0) {
67 // if it's a continuous volume, just call normalf
68 normalf(norm, x, y, z);
69 return;
70 }
71 sz[1] = num_samples(1);
72 sz[2] = num_samples(2);
74 int prevx = x <= 0 ? 0 : x;
75 int nextx = x >= sz[0] - 1 ? sz[0] - 1 : x;
76 int prevy = y <= 0 ? 0 : y;
77 int nexty = y >= sz[1] - 1 ? sz[1] - 1 : y;
78 int prevz = z <= 0 ? 0 : z;
79 int nextz = z >= sz[2] - 1 ? sz[2] - 1 : z;
81 norm[0] = valuei(nextx, y, z) - valuei(prevx, y, z);
82 norm[1] = valuei(x, nexty, z) - valuei(x, prevy, z);
83 norm[2] = valuei(x, y, nextz) - valuei(x, y, prevz);
85 float len = sqrt(norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
86 if(len != 0.0) {
87 norm[0] /= len;
88 norm[1] /= len;
89 norm[2] /= len;
90 }
91 }
93 // ---- VoxelVolume (discrete) implementation ----
94 VoxelVolume::VoxelVolume()
95 {
96 size[0] = size[1] = size[2] = 0;
97 }
99 VoxelVolume::~VoxelVolume()
100 {
101 for(size_t i=0; i<slices.size(); i++) {
102 slices[i].destroy();
103 }
104 }
106 bool VoxelVolume::load(const char *fname)
107 {
108 if(!fname) return false;
110 char *prefix = (char*)alloca(strlen(fname) + 1);
111 strcpy(prefix, fname);
112 char *slash = strrchr(prefix, '/');
113 if(slash) {
114 *slash = 0;
115 } else {
116 prefix = 0;
117 }
119 printf("loading volume dataset: %s\n", fname);
120 FILE *fp = fopen(fname, "r");
121 if(!fp) {
122 fprintf(stderr, "failed to open file: %s: %s\n", fname, strerror(errno));
123 return false;
124 }
126 char buf[256], path[300];
127 while(fgets(buf, sizeof buf, fp)) {
128 char *line = strip_space(buf);
129 sprintf(path, "%s/%s", prefix, line);
131 printf(" loading slice %d: %s\n", (int)slices.size(), path);
132 Image img;
133 if(!img.load(path)) {
134 slices.clear();
135 return false;
136 }
138 if(slices.empty()) {
139 size[0] = img.width;
140 size[1] = img.height;
141 } else {
142 if(img.width != size[0] || img.height != size[1]) {
143 fprintf(stderr, "slice %d \"%s\" size mismatch (%dx%d, %dx%d expected)\n",
144 (int)slices.size(), line, img.width, img.height, size[0], size[1]);
145 slices.clear();
146 return false;
147 }
148 }
150 slices.push_back(img);
151 }
153 size[2] = slices.size();
154 fclose(fp);
155 return true;
156 }
158 int VoxelVolume::num_samples(int dim) const
159 {
160 return size[dim];
161 }
163 static inline int clamp(int x, int low, int high)
164 {
165 return x < low ? low : (x > high ? high : x);
166 }
168 static inline float lookup(int x0, int y0, int x1, int y1, float tx, float ty,
169 float *pixels, int width, int height)
170 {
171 float v00, v01, v10, v11;
173 v00 = pixels[y0 * width + x0];
174 v01 = pixels[y1 * width + x0];
175 v10 = pixels[y0 * width + x1];
176 v11 = pixels[y1 * width + x1];
178 float v0 = v00 + (v01 - v00) * ty;
179 float v1 = v10 + (v11 - v10) * ty;
181 return v0 + (v1 - v0) * tx;
182 }
184 float VoxelVolume::valuef(float x, float y, float z) const
185 {
186 if(slices.empty()) {
187 return 0.0f;
188 }
190 float floor_x = floor(x);
191 float ceil_x = ceil(x);
192 float tx = x - floor_x;
194 float floor_y = floor(y);
195 float ceil_y = ceil(y);
196 float ty = y - floor_y;
198 float floor_z = floor(z);
199 float ceil_z = ceil(z);
200 float tz = z - floor_z;
202 int x0 = clamp(floor_x, 0, size[0] - 1);
203 int x1 = clamp(ceil_x, 0, size[0] - 1);
205 int y0 = clamp(floor_y, 0, size[1] - 1);
206 int y1 = clamp(ceil_y, 0, size[1] - 1);
208 int s0 = clamp(floor_z, 0, size[2] - 1);
209 int s1 = clamp(ceil_z, 0, size[2] - 1);
211 float val_s0 = lookup(x0, y0, x1, y1, tx, ty, slices[s0].pixels, size[0], size[1]);
212 float val_s1 = lookup(x0, y0, x1, y1, tx, ty, slices[s1].pixels, size[0], size[1]);
214 return val_s0 + (val_s1 - val_s0) * tz;
215 }
217 float VoxelVolume::valuei(int x, int y, int z) const
218 {
219 x = clamp(x, 0, size[0] - 1);
220 y = clamp(y, 0, size[1] - 1);
221 z = clamp(z, 0, size[2] - 1);
223 return slices[z].pixels[y * size[0] + x];
224 }
226 static char *strip_space(char *s)
227 {
228 while(*s && isspace(*s)) s++;
229 if(!*s) return 0;
231 char *end = s + strlen(s) - 1;
232 while(end > s && isspace(*end)) end--;
233 end[1] = 0;
235 return s;
236 }