1
#include "makelevelset2.h"
3
// find distance x0 is from segment x1-x2
4
static double point_segment_distance(const Vec2d &x0, const Vec2d &x1, const Vec2d &x2)
8
// find parameter value of closest point on segment
9
double s12=(double)( dot(x2-x0, dx)/m2 );
15
// and find the distance
16
return mag(s12*x1+(1-s12)*x2 - x0);
19
static void check_neighbour(const std::vector<Vec2ui> &edge, const std::vector<Vec2d> &x,
20
Array2d &phi, Array2i &closest_edge,
21
const Vec2d &gx, int i0, int j0, int i1, int j1)
23
if(closest_edge(i0,j0)==closest_edge(i1,j1))
25
if(closest_edge(i1,j1)>=0){
26
unsigned int p, q; assign(edge[closest_edge(i1,j1)], p, q);
27
double d=point_segment_distance(gx, x[p], x[q]);
30
closest_edge(i0,j0)=closest_edge(i1,j1);
35
void make_level_set2(const std::vector<Vec2ui> &edge, const std::vector<Vec2d> &x,
36
const Vec2d &origin, double dx, int nx, int ny,
40
phi.assign((nx+ny)*dx); // upper bound on distance
41
Array2i closest_edge(nx, ny, -1);
42
Array2i intersection_count(nx, ny, 0); // intersection_count(i,j) is # of edge intersections in (i-1,i]x{j}
43
// we begin by initializing distances near the mesh, and figuring out intersection counts
45
for(unsigned int e=0; e<edge.size(); ++e){
46
unsigned int p, q; assign(edge[e], p, q);
47
minmax((x[p]-origin)/dx, (x[q]-origin)/dx, ijmin, ijmax);
49
int i0=clamp(int(ijmin[0])-1, 0, nx-1), i1=clamp(int(ijmax[0])+2, 0, nx-1);
50
int j0=clamp(int(ijmin[1])-1, 0, ny-1), j1=clamp(int(ijmax[1])+2, 0, ny-1);
51
for(int j=j0; j<=j1; ++j) for(int i=i0; i<=i1; ++i){
52
Vec2d gx(i*dx+origin[0], j*dx+origin[1]);
53
double d=point_segment_distance(gx, x[p], x[q]);
59
// and do intersection counts
60
if(x[p][1]!=x[q][1]){ // if it's not a horizontal edge
61
double fi0, fj0, fi1, fj1;
63
fi0=((double)x[p][0]-origin[0])/dx;
64
fj0=((double)x[p][1]-origin[1])/dx;
65
fi1=((double)x[q][0]-origin[0])/dx;
66
fj1=((double)x[q][1]-origin[1])/dx;
68
fi0=((double)x[q][0]-origin[0])/dx;
69
fj0=((double)x[q][1]-origin[1])/dx;
70
fi1=((double)x[p][0]-origin[0])/dx;
71
fj1=((double)x[p][1]-origin[1])/dx;
73
j0=clamp(int(std::floor(fj0)), 0, ny-1)+1;
74
j1=clamp(int(std::floor(fj1)), 0, ny-1);
75
for(int j=j0; j<=j1; ++j){
76
double alpha=(j-fj0)/(fj1-fj0);
77
double fi=(1-alpha)*fi0 + alpha*fi1; // where the edge intersects the j'th grid line
78
int i_interval=int(std::ceil(fi)); // intersection is in (i_interval-1,i_interval]
79
if(i_interval<0) i_interval=0; // we enlarge the first interval to include everything to the left
81
++intersection_count(i_interval,j);
82
} // we ignore intersections that are beyond the right edge of the grid
86
// and now we fill in the rest of the distances with fast sweeping
87
for(unsigned int pass=0; pass<2; ++pass){
88
for(int j=1; j<ny; ++j) for(int i=1; i<nx; ++i){
89
Vec2d gx(i*dx+origin[0], j*dx+origin[1]);
90
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i-1, j-1);
91
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i-1, j);
92
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i, j-1);
94
for(int j=ny-2; j>=0; --j) for(int i=nx-2; i>=0; --i){
95
Vec2d gx(i*dx+origin[0], j*dx+origin[1]);
96
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i+1, j+1);
97
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i+1, j);
98
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i, j+1);
100
for(int j=ny-2; j>=0; --j) for(int i=1; i<nx; ++i){
101
Vec2d gx(i*dx+origin[0], j*dx+origin[1]);
102
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i-1, j+1);
103
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i-1, j);
104
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i, j+1);
106
for(int j=1; j<ny; ++j) for(int i=nx-2; i>=0; --i){
107
Vec2d gx(i*dx+origin[0], j*dx+origin[1]);
108
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i+1, j-1);
109
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i+1, j);
110
check_neighbour(edge, x, phi, closest_edge, gx, i, j, i, j-1);
113
// then figure out signs (inside/outside) from intersection counts
114
for(int j=0; j<ny; ++j){
116
for(int i=0; i<nx; ++i){
117
total_count+=intersection_count(i,j);
118
if(total_count%2==1){ // if parity of intersections so far is odd,
119
phi(i,j)=-phi(i,j); // we are inside the mesh