glviewvol

annotate src/volume.cc @ 1:cc9e0d8590e2

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 27 Dec 2014 06:32:28 +0200
parents
children 701507c8238f
rev   line source
nuclear@1 1 #include <stdio.h>
nuclear@1 2 #include <string.h>
nuclear@1 3 #include <ctype.h>
nuclear@1 4 #include <errno.h>
nuclear@1 5 #include <math.h>
nuclear@1 6 #include "volume.h"
nuclear@1 7
nuclear@1 8 static char *strip_space(char *s);
nuclear@1 9
nuclear@1 10
nuclear@1 11 Volume::~Volume()
nuclear@1 12 {
nuclear@1 13 }
nuclear@1 14
nuclear@1 15 int Volume::num_samples(int dim) const
nuclear@1 16 {
nuclear@1 17 return 0;
nuclear@1 18 }
nuclear@1 19
nuclear@1 20 void Volume::normalf(float *norm, float x, float y, float z, float delta)
nuclear@1 21 {
nuclear@1 22 float dx, dy, dz;
nuclear@1 23 dx = dy = dz = delta;
nuclear@1 24
nuclear@1 25 if(num_samples(0) > 0) {
nuclear@1 26 // discrete volume
nuclear@1 27 dx /= (float)num_samples(0);
nuclear@1 28 dy /= (float)num_samples(1);
nuclear@1 29 dz /= (float)num_samples(2);
nuclear@1 30 }
nuclear@1 31
nuclear@1 32 norm[0] = valuef(x + dx, y, z) - valuef(x - dx, y, z);
nuclear@1 33 norm[1] = valuef(x, y + dy, z) - valuef(x, y - dy, z);
nuclear@1 34 norm[2] = valuef(x, y, z + dz) - valuef(x, y, z - dz);
nuclear@1 35
nuclear@1 36 float len = sqrt(norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
nuclear@1 37 if(len != 0.0) {
nuclear@1 38 norm[0] /= len;
nuclear@1 39 norm[1] /= len;
nuclear@1 40 norm[2] /= len;
nuclear@1 41 }
nuclear@1 42 }
nuclear@1 43
nuclear@1 44 void Volume::normali(float *norm, int x, int y, int z)
nuclear@1 45 {
nuclear@1 46 int sz[3];
nuclear@1 47
nuclear@1 48 if((sz[0] = num_samples(0)) <= 0) {
nuclear@1 49 // if it's a continuous volume, just call normalf
nuclear@1 50 normalf(norm, x, y, z);
nuclear@1 51 return;
nuclear@1 52 }
nuclear@1 53 sz[1] = num_samples(1);
nuclear@1 54 sz[2] = num_samples(2);
nuclear@1 55
nuclear@1 56 int prevx = x <= 0 ? 0 : x;
nuclear@1 57 int nextx = x >= sz[0] - 1 ? sz[0] - 1 : x;
nuclear@1 58 int prevy = y <= 0 ? 0 : y;
nuclear@1 59 int nexty = y >= sz[1] - 1 ? sz[1] - 1 : y;
nuclear@1 60 int prevz = z <= 0 ? 0 : z;
nuclear@1 61 int nextz = z >= sz[2] - 1 ? sz[2] - 1 : z;
nuclear@1 62
nuclear@1 63 norm[0] = valuei(nextx, y, z) - valuei(prevx, y, z);
nuclear@1 64 norm[1] = valuei(x, nexty, z) - valuei(x, prevy, z);
nuclear@1 65 norm[2] = valuei(x, y, nextz) - valuei(x, y, prevz);
nuclear@1 66
nuclear@1 67 float len = sqrt(norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]);
nuclear@1 68 if(len != 0.0) {
nuclear@1 69 norm[0] /= len;
nuclear@1 70 norm[1] /= len;
nuclear@1 71 norm[2] /= len;
nuclear@1 72 }
nuclear@1 73 }
nuclear@1 74
nuclear@1 75 // ---- VoxelVolume (discrete) implementation ----
nuclear@1 76 VoxelVolume::VoxelVolume()
nuclear@1 77 {
nuclear@1 78 size[0] = size[1] = size[2] = 0;
nuclear@1 79 }
nuclear@1 80
nuclear@1 81 bool VoxelVolume::load(const char *fname)
nuclear@1 82 {
nuclear@1 83 FILE *fp = fopen(fname, "r");
nuclear@1 84 if(!fp) {
nuclear@1 85 fprintf(stderr, "failed to open file: %s: %s\n", fname, strerror(errno));
nuclear@1 86 return false;
nuclear@1 87 }
nuclear@1 88
nuclear@1 89 char buf[512];
nuclear@1 90 while(fgets(buf, sizeof buf, fp)) {
nuclear@1 91 char *line = strip_space(buf);
nuclear@1 92
nuclear@1 93 Image img;
nuclear@1 94 if(!img.load(line)) {
nuclear@1 95 slices.clear();
nuclear@1 96 return false;
nuclear@1 97 }
nuclear@1 98
nuclear@1 99 if(slices.empty()) {
nuclear@1 100 size[0] = img.width;
nuclear@1 101 size[1] = img.height;
nuclear@1 102 } else {
nuclear@1 103 if(img.width != size[0] || img.height != size[1]) {
nuclear@1 104 fprintf(stderr, "slice %d \"%s\" size mismatch (%dx%d, %dx%d expected)\n",
nuclear@1 105 (int)slices.size(), line, img.width, img.height, size[0], size[1]);
nuclear@1 106 slices.clear();
nuclear@1 107 return false;
nuclear@1 108 }
nuclear@1 109 }
nuclear@1 110
nuclear@1 111 slices.push_back(img);
nuclear@1 112 img.pixels = 0; // otherwise the destructor will free it
nuclear@1 113 }
nuclear@1 114
nuclear@1 115 size[2] = slices.size();
nuclear@1 116 fclose(fp);
nuclear@1 117 return true;
nuclear@1 118 }
nuclear@1 119
nuclear@1 120 int VoxelVolume::num_samples(int dim) const
nuclear@1 121 {
nuclear@1 122 return size[dim];
nuclear@1 123 }
nuclear@1 124
nuclear@1 125 static inline int clamp(int x, int low, int high)
nuclear@1 126 {
nuclear@1 127 return x < low ? low : (x > high ? high : x);
nuclear@1 128 }
nuclear@1 129
nuclear@1 130 static inline float lookup(int x0, int y0, int x1, int y1, float tx, float ty,
nuclear@1 131 float *pixels, int width, int height)
nuclear@1 132 {
nuclear@1 133 float v00, v01, v10, v11;
nuclear@1 134
nuclear@1 135 v00 = pixels[y0 * width + x0];
nuclear@1 136 v01 = pixels[y1 * width + x0];
nuclear@1 137 v10 = pixels[y0 * width + x1];
nuclear@1 138 v11 = pixels[y1 * width + x1];
nuclear@1 139
nuclear@1 140 float v0 = v00 + (v01 - v00) * ty;
nuclear@1 141 float v1 = v10 + (v11 - v10) * ty;
nuclear@1 142
nuclear@1 143 return v0 + (v1 - v0) * tx;
nuclear@1 144 }
nuclear@1 145
nuclear@1 146 float VoxelVolume::valuef(float x, float y, float z) const
nuclear@1 147 {
nuclear@1 148 if(slices.empty()) {
nuclear@1 149 return 0.0f;
nuclear@1 150 }
nuclear@1 151
nuclear@1 152 float floor_x = floor(x);
nuclear@1 153 float ceil_x = ceil(x);
nuclear@1 154 float tx = x - floor_x;
nuclear@1 155
nuclear@1 156 float floor_y = floor(y);
nuclear@1 157 float ceil_y = ceil(y);
nuclear@1 158 float ty = y - floor_y;
nuclear@1 159
nuclear@1 160 float floor_z = floor(z);
nuclear@1 161 float ceil_z = ceil(z);
nuclear@1 162 float tz = z - floor_z;
nuclear@1 163
nuclear@1 164 int x0 = clamp(floor_x, 0, size[0] - 1);
nuclear@1 165 int x1 = clamp(ceil_x, 0, size[0] - 1);
nuclear@1 166
nuclear@1 167 int y0 = clamp(floor_y, 0, size[1] - 1);
nuclear@1 168 int y1 = clamp(ceil_y, 0, size[1] - 1);
nuclear@1 169
nuclear@1 170 int s0 = clamp(floor_z, 0, size[2] - 1);
nuclear@1 171 int s1 = clamp(ceil_z, 0, size[2] - 1);
nuclear@1 172
nuclear@1 173 float val_s0 = lookup(x0, y0, x1, y1, tx, ty, slices[s0].pixels, size[0], size[1]);
nuclear@1 174 float val_s1 = lookup(x0, y0, x1, y1, tx, ty, slices[s1].pixels, size[0], size[1]);
nuclear@1 175
nuclear@1 176 return val_s0 + (val_s1 - val_s0) * tz;
nuclear@1 177 }
nuclear@1 178
nuclear@1 179 float VoxelVolume::valuei(int x, int y, int z) const
nuclear@1 180 {
nuclear@1 181 x = clamp(x, 0, size[0] - 1);
nuclear@1 182 y = clamp(y, 0, size[1] - 1);
nuclear@1 183 z = clamp(z, 0, size[2] - 1);
nuclear@1 184
nuclear@1 185 return slices[z].pixels[y * size[0] + x];
nuclear@1 186 }
nuclear@1 187
nuclear@1 188 static char *strip_space(char *s)
nuclear@1 189 {
nuclear@1 190 while(*s && isspace(*s)) s++;
nuclear@1 191 if(!*s) return 0;
nuclear@1 192
nuclear@1 193 char *end = s + strlen(s) - 1;
nuclear@1 194 while(end > s && isspace(*end)) end--;
nuclear@1 195 end[1] = 0;
nuclear@1 196
nuclear@1 197 return s;
nuclear@1 198 }