4
#include "array2_utils.h"
5
#include "array3_utils.h"
7
float interpolate_phi(const Vec2f& point, const Array2f& grid, const Vec2f& origin, const float dx) {
9
Vec2f temp = (point-origin)*inv_dx;
10
return interpolate_value(temp, grid);
13
float interpolate_phi(const Vec3f& point, const Array3f& grid, const Vec3f& origin, const float dx) {
15
Vec3f temp = (point-origin)*inv_dx;
16
return interpolate_value(temp, grid);
19
float interpolate_normal(Vec2f& normal, const Vec2f& point, const Array2f& grid, const Vec2f& origin, const float dx) {
21
Vec2f temp = (point-origin)*inv_dx;
22
float value = interpolate_gradient(normal, temp, grid);
28
float interpolate_normal(Vec3f& normal, const Vec3f& point, const Array3f& grid, const Vec3f& origin, const float dx) {
30
Vec3f temp = (point-origin)*inv_dx;
31
float value = interpolate_gradient(normal, temp, grid);
37
void project_to_isosurface(Vec2f& point, const float target_value, const Array2f& grid, const Vec2f& origin, const float dx) {
38
float tol = 0.01f*dx; //some fraction of a grid cell;
43
float phi = interpolate_normal(normal, point, grid, origin, dx);
44
while(fabs(phi - target_value) > tol && iter++ < max_iter) {
45
point -= (phi - target_value) * normal;
46
phi = interpolate_normal(normal, point, grid, origin, dx);
50
void project_to_isosurface(Vec3f& point, const float target_value, const Array3f& grid, const Vec3f& origin, const float dx) {
51
float tol = 0.01f*dx; //some fraction of a grid cell;
56
float phi = interpolate_normal(normal, point, grid, origin, dx);
57
while(fabs(phi - target_value) > tol && iter++ < max_iter) {
58
point -= (phi - target_value) * normal;
59
phi = interpolate_normal(normal, point, grid, origin, dx);
64
//On a signed distance field, compute the fraction inside the (negative) isosurface
65
//along the 1D line segment joining phi_left and phi_right sample points.
66
float fraction_inside(float phi_left, float phi_right)
68
//Note: should not generate divide by zero, because if
69
//signs are different, and both values are != 0,
70
//abs(left - right) is necessarily >= left, or right, alone, ie. not 0
73
(phi_left >= 0 && phi_right >= 0)? //all empty
75
( (phi_left < 0 && phi_right < 0)? //all full
79
(1 - phi_left / (phi_left - phi_right)): //right inside
80
(phi_left / (phi_left - phi_right)) //left inside
85
//On a signed distance field, compute the fraction inside the (negative) isosurface
86
//along the 1D line segment joining phi_left and phi_right sample points.
87
//Except now there are two level sets, and we want the fraction that is the union
89
float fraction_inside_either(float phi_left0, float phi_right0, float phi_left1, float phi_right1)
93
//entirely inside solid0 [-/-][?]
96
else { //phi_right0 > 0
99
//entirely inside solid1 -> [-/+][-/-]
102
else {//both left sides are inside, neither right side [-/+][-/+]
103
return max( fraction_inside(phi_left0, phi_right0),
104
fraction_inside(phi_left1, phi_right1) );
107
else { //phi_left1 > 0
108
if(phi_right1 <= 0) { //opposite sides are interior [-/+][+/-]
109
float frac0 = fraction_inside(phi_left0, phi_right0);
110
float frac1 = fraction_inside(phi_left1, phi_right1);
111
float total = frac0+frac1;
118
else {//phi_right1 > 0
119
//phi1 plays no role, both outside [-/+][+/+]
120
return fraction_inside(phi_left0, phi_right0);
126
if(phi_right0 <= 0) {
128
if(phi_right1 <= 0) {
129
//entirely inside solid1[+/-][-/-]
133
//coming in from opposing sides [+/-][-/+]
134
float frac0 = fraction_inside(phi_left0, phi_right0);
135
float frac1 = fraction_inside(phi_left1, phi_right1);
136
float total = frac0+frac1;
143
else { //phi_left1 > 0
144
if(phi_right1 <= 0) {
145
//coming from the same side, take the larger one [+/-][+/-]
146
return max( fraction_inside(phi_left0, phi_right0),
147
fraction_inside(phi_left1, phi_right1) );
149
else { //phi_right > 0
150
//Only have to worry about phi_0 [+/-][+/+]
151
return fraction_inside(phi_left0, phi_right0);
157
//Only have to worry about phi_1 [+/+][?]
158
return fraction_inside(phi_left1, phi_right1);
163
void compute_volume_fractions(const Array2f& levelset, const Vec2f& ls_origin, float ls_dx, Array2f& volumes, const Vec2f& v_origin, float v_dx, int subdivisions) {
165
float sub_dx = v_dx / (float)(subdivisions+1);
167
for(int j = 0; j < volumes.nj; ++j) for(int i = 0; i < volumes.ni; ++i) {
168
//centre of the volume cells
169
Vec2f bottom_left = v_origin + Vec2f(i*v_dx, j*v_dx);
170
int inside_samples = 0;
171
for(int subj = 0; subj < subdivisions+1; ++subj) for(int subi = 0; subi < subdivisions+1; ++subi) {
172
Vec2f point = bottom_left + Vec2f( (subi+0.5f)*sub_dx, (subj+0.5f)*sub_dx);
173
float data = interpolate_phi(point, levelset, ls_origin, ls_dx);
174
inside_samples += (data < 0)?1:0;
176
volumes(i,j) = (float)inside_samples / (float)sqr(subdivisions+1);
180
void compute_volume_fractions(const Array3f& levelset, const Vec3f& ls_origin, float ls_dx, Array3f& volumes, const Vec3f& v_origin, float v_dx, int subdivisions) {
182
float sub_dx = v_dx / (float)(subdivisions+1);
184
for(int k = 0; k < volumes.nk; ++k) for(int j = 0; j < volumes.nj; ++j) for(int i = 0; i < volumes.ni; ++i) {
185
//centre of the volume cells
186
Vec3f bottom_left = v_origin + Vec3f((i-0.5f)*v_dx, (j-0.5f)*v_dx, (k-0.5f)*v_dx);
187
int inside_samples = 0;
189
//Speedup! Test the centre point, and if it's more than a grid cell away from the interface, we can assume
190
//the cell is either totally full or totally empty
191
float estimate = interpolate_phi(bottom_left + 0.5f*v_dx*Vec3f(1,1,1), levelset, ls_origin, ls_dx);
192
if(estimate > v_dx) {
196
else if(estimate < -v_dx) {
201
for(int subk = 0; subk < subdivisions+1; ++subk) for(int subj = 0; subj < subdivisions+1; ++subj) for(int subi = 0; subi < subdivisions+1; ++subi) {
202
Vec3f point = bottom_left + Vec3f( (subi+0.5f)*sub_dx, (subj+0.5f)*sub_dx, (subk+0.5f)*sub_dx);
203
float data = interpolate_phi(point, levelset, ls_origin, ls_dx);
204
inside_samples += (data < 0)?1:0;
206
volumes(i,j,k) = (float)inside_samples / (float)cube(subdivisions+1);