72 |
|
/* all incident angles in-plane so far? */ |
73 |
|
static int single_plane_incident = -1; |
74 |
|
|
75 |
+ |
/* represented incident quadrants */ |
76 |
+ |
#define INP_QUAD1 1 /* 0-90 degree quadrant */ |
77 |
+ |
#define INP_QUAD2 2 /* 90-180 degree quadrant */ |
78 |
+ |
#define INP_QUAD3 4 /* 180-270 degree quadrant */ |
79 |
+ |
#define INP_QUAD4 8 /* 270-360 degree quadrant */ |
80 |
+ |
|
81 |
+ |
static int inp_coverage = 0; |
82 |
+ |
|
83 |
+ |
/* symmetry operations */ |
84 |
+ |
#define MIRROR_X 1 /* mirror(ed) x-coordinate */ |
85 |
+ |
#define MIRROR_Y 2 /* mirror(ed) y-coordinate */ |
86 |
+ |
|
87 |
|
/* input/output orientations */ |
88 |
|
static int input_orient = 0; |
89 |
|
static int output_orient = 0; |
120 |
|
/* sampling order (set by data density) */ |
121 |
|
int samp_order = 0; |
122 |
|
|
123 |
+ |
/* get phi value in degrees, [0,360) range */ |
124 |
+ |
#define get_phi360(v) ((180./M_PI)*atan2((v)[1],(v)[0]) + 180.) |
125 |
+ |
|
126 |
+ |
/* Apply symmetry to the given vector based on distribution */ |
127 |
+ |
static int |
128 |
+ |
use_symmetry(FVECT vec) |
129 |
+ |
{ |
130 |
+ |
double phi = get_phi360(vec); |
131 |
+ |
|
132 |
+ |
switch (inp_coverage) { |
133 |
+ |
case INP_QUAD1|INP_QUAD2|INP_QUAD3|INP_QUAD4: |
134 |
+ |
break; |
135 |
+ |
case INP_QUAD1|INP_QUAD2: |
136 |
+ |
if ((-FTINY > phi) | (phi > 180.+FTINY)) |
137 |
+ |
goto mir_y; |
138 |
+ |
break; |
139 |
+ |
case INP_QUAD2|INP_QUAD3: |
140 |
+ |
if ((90.-FTINY > phi) | (phi > 270.+FTINY)) |
141 |
+ |
goto mir_x; |
142 |
+ |
break; |
143 |
+ |
case INP_QUAD3|INP_QUAD4: |
144 |
+ |
if ((180.-FTINY > phi) | (phi > 360.+FTINY)) |
145 |
+ |
goto mir_y; |
146 |
+ |
break; |
147 |
+ |
case INP_QUAD4|INP_QUAD1: |
148 |
+ |
if ((270.-FTINY > phi) & (phi > 90.+FTINY)) |
149 |
+ |
goto mir_x; |
150 |
+ |
break; |
151 |
+ |
case INP_QUAD1: |
152 |
+ |
if ((-FTINY > phi) | (phi > 90.+FTINY)) |
153 |
+ |
switch ((int)(phi*(1./90.))) { |
154 |
+ |
case 1: goto mir_x; |
155 |
+ |
case 2: goto mir_xy; |
156 |
+ |
case 3: goto mir_y; |
157 |
+ |
} |
158 |
+ |
break; |
159 |
+ |
case INP_QUAD2: |
160 |
+ |
if ((90.-FTINY > phi) | (phi > 180.+FTINY)) |
161 |
+ |
switch ((int)(phi*(1./90.))) { |
162 |
+ |
case 0: goto mir_x; |
163 |
+ |
case 2: goto mir_y; |
164 |
+ |
case 3: goto mir_xy; |
165 |
+ |
} |
166 |
+ |
break; |
167 |
+ |
case INP_QUAD3: |
168 |
+ |
if ((180.-FTINY > phi) | (phi > 270.+FTINY)) |
169 |
+ |
switch ((int)(phi*(1./90.))) { |
170 |
+ |
case 0: goto mir_xy; |
171 |
+ |
case 1: goto mir_y; |
172 |
+ |
case 3: goto mir_x; |
173 |
+ |
} |
174 |
+ |
break; |
175 |
+ |
case INP_QUAD4: |
176 |
+ |
if ((270.-FTINY > phi) | (phi > 360.+FTINY)) |
177 |
+ |
switch ((int)(phi*(1./90.))) { |
178 |
+ |
case 0: goto mir_y; |
179 |
+ |
case 1: goto mir_xy; |
180 |
+ |
case 2: goto mir_x; |
181 |
+ |
} |
182 |
+ |
break; |
183 |
+ |
default: |
184 |
+ |
fprintf(stderr, "%s: Illegal input coverage (%d)\n", |
185 |
+ |
progname, inp_coverage); |
186 |
+ |
exit(1); |
187 |
+ |
} |
188 |
+ |
return(0); /* in range */ |
189 |
+ |
mir_x: |
190 |
+ |
vec[0] = -vec[0]; |
191 |
+ |
return(MIRROR_X); |
192 |
+ |
mir_y: |
193 |
+ |
vec[1] = -vec[1]; |
194 |
+ |
return(MIRROR_Y); |
195 |
+ |
mir_xy: |
196 |
+ |
vec[0] = -vec[0]; |
197 |
+ |
vec[1] = -vec[1]; |
198 |
+ |
return(MIRROR_X|MIRROR_Y); |
199 |
+ |
} |
200 |
+ |
|
201 |
+ |
/* Reverse symmetry based on what was done before */ |
202 |
+ |
static void |
203 |
+ |
rev_symmetry(FVECT vec, int sym) |
204 |
+ |
{ |
205 |
+ |
if (sym & MIRROR_X) |
206 |
+ |
vec[0] = -vec[0]; |
207 |
+ |
if (sym & MIRROR_Y) |
208 |
+ |
vec[1] = -vec[1]; |
209 |
+ |
} |
210 |
+ |
|
211 |
+ |
/* Reverse symmetry for an RBF distribution */ |
212 |
+ |
static void |
213 |
+ |
rev_rbf_symmetry(RBFNODE *rbf, int sym) |
214 |
+ |
{ |
215 |
+ |
int n; |
216 |
+ |
|
217 |
+ |
rev_symmetry(rbf->invec, sym); |
218 |
+ |
if (sym & MIRROR_X) |
219 |
+ |
for (n = rbf->nrbf; n-- > 0; ) |
220 |
+ |
rbf->rbfa[n].gx = GRIDRES-1 - rbf->rbfa[n].gx; |
221 |
+ |
if (sym & MIRROR_Y) |
222 |
+ |
for (n = rbf->nrbf; n-- > 0; ) |
223 |
+ |
rbf->rbfa[n].gy = GRIDRES-1 - rbf->rbfa[n].gy; |
224 |
+ |
} |
225 |
+ |
|
226 |
|
/* Compute volume associated with Gaussian lobe */ |
227 |
|
static double |
228 |
|
rbf_volume(const RBFVAL *rbfp) |
292 |
|
/* check for redundant meas. */ |
293 |
|
for (rbf = dsf_list; rbf != NULL; rbf = rbf->next) |
294 |
|
if (DOT(rbf->invec, newrbf->invec) >= 1.-FTINY) { |
295 |
< |
fputs("Duplicate incident measurement (ignored)\n", stderr); |
295 |
> |
fprintf(stderr, |
296 |
> |
"%s: Duplicate incident measurement (ignored)\n", |
297 |
> |
progname); |
298 |
|
free(newrbf); |
299 |
|
return; |
300 |
|
} |
331 |
|
/* allocate RBF array */ |
332 |
|
newnode = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(nn-1)); |
333 |
|
if (newnode == NULL) { |
334 |
< |
fputs("Out of memory in make_rbfrep()\n", stderr); |
334 |
> |
fprintf(stderr, "%s: Out of memory in make_rbfrep()\n", progname); |
335 |
|
exit(1); |
336 |
|
} |
337 |
|
newnode->next = NULL; |
448 |
|
stderr); |
449 |
|
exit(1); |
450 |
|
} |
451 |
< |
if (single_plane_incident > 0) /* check if still in plane */ |
451 |
> |
if (single_plane_incident > 0) /* check input coverage */ |
452 |
|
single_plane_incident = (round(new_phi) == round(phi_in_deg)); |
453 |
|
else if (single_plane_incident < 0) |
454 |
|
single_plane_incident = 1; |
455 |
|
phi_in_deg = new_phi; |
456 |
+ |
new_phi += 360.*(new_phi < -FTINY); |
457 |
+ |
if ((1. < new_phi) & (new_phi < 89.)) |
458 |
+ |
inp_coverage |= INP_QUAD1; |
459 |
+ |
else if ((91. < new_phi) & (new_phi < 179.)) |
460 |
+ |
inp_coverage |= INP_QUAD2; |
461 |
+ |
else if ((181. < new_phi) & (new_phi < 269.)) |
462 |
+ |
inp_coverage |= INP_QUAD3; |
463 |
+ |
else if ((271. < new_phi) & (new_phi < 359.)) |
464 |
+ |
inp_coverage |= INP_QUAD4; |
465 |
|
ungetc(c, fp); /* read actual data */ |
466 |
|
while (fscanf(fp, "%lf %lf %lf\n", &theta_out, &phi_out, &val) == 3) { |
467 |
|
FVECT ovec; |
535 |
|
} |
536 |
|
} |
537 |
|
if (inear < 0) { |
538 |
< |
fputs("Could not find non-empty neighbor!\n", stderr); |
538 |
> |
fprintf(stderr, |
539 |
> |
"%s: Could not find non-empty neighbor!\n", |
540 |
> |
progname); |
541 |
|
exit(1); |
542 |
|
} |
543 |
|
ang2 = sqrt(lastang2); |
636 |
|
int i, j; |
637 |
|
|
638 |
|
if ((pmtx == NULL) | (vto == NULL)) { |
639 |
< |
fputs("Out of memory in migration_costs()\n", stderr); |
639 |
> |
fprintf(stderr, "%s: Out of memory in migration_costs()\n", |
640 |
> |
progname); |
641 |
|
exit(1); |
642 |
|
} |
643 |
|
for (j = to_rbf->nrbf; j--; ) /* save repetitive ops. */ |
683 |
|
if (n_alloc) free(price_sort); |
684 |
|
price_sort = (int *)malloc(sizeof(int)*n); |
685 |
|
if (price_sort == NULL) { |
686 |
< |
fputs("Out of memory in min_cost()\n", stderr); |
686 |
> |
fprintf(stderr, "%s: Out of memory in min_cost()\n", |
687 |
> |
progname); |
688 |
|
exit(1); |
689 |
|
} |
690 |
|
n_alloc = n; |
709 |
|
migration_step(MIGRATION *mig, double *src_rem, double *dst_rem, const float *pmtx) |
710 |
|
{ |
711 |
|
const double maxamt = .1; |
712 |
+ |
const double minamt = maxamt*.0001; |
713 |
|
static double *src_cost = NULL; |
714 |
|
static int n_alloc = 0; |
715 |
|
struct { |
724 |
|
free(src_cost); |
725 |
|
src_cost = (double *)malloc(sizeof(double)*mtx_nrows(mig)); |
726 |
|
if (src_cost == NULL) { |
727 |
< |
fputs("Out of memory in migration_step()\n", stderr); |
727 |
> |
fprintf(stderr, "%s: Out of memory in migration_step()\n", |
728 |
> |
progname); |
729 |
|
exit(1); |
730 |
|
} |
731 |
|
n_alloc = mtx_nrows(mig); |
739 |
|
for (cur.s = mtx_nrows(mig); cur.s--; ) { |
740 |
|
const float *price = pmtx + cur.s*mtx_ncols(mig); |
741 |
|
double cost_others = 0; |
742 |
< |
if (src_rem[cur.s] <= FTINY) |
742 |
> |
if (src_rem[cur.s] < minamt) |
743 |
|
continue; |
744 |
|
cur.d = -1; /* examine cheapest dest. */ |
745 |
|
for (i = mtx_ncols(mig); i--; ) |
746 |
< |
if (dst_rem[i] > FTINY && |
746 |
> |
if (dst_rem[i] > minamt && |
747 |
|
(cur.d < 0 || price[i] < price[cur.d])) |
748 |
|
cur.d = i; |
749 |
|
if (cur.d < 0) |
890 |
|
create_migration(RBFNODE *from_rbf, RBFNODE *to_rbf) |
891 |
|
{ |
892 |
|
const double end_thresh = 0.1/(from_rbf->nrbf*to_rbf->nrbf); |
893 |
< |
const double rel_thresh = 0.0001; |
893 |
> |
const double check_thresh = 0.01; |
894 |
> |
const double rel_thresh = 5e-6; |
895 |
|
float *pmtx; |
896 |
|
MIGRATION *newmig; |
897 |
|
double *src_rem, *dst_rem; |
910 |
|
src_rem = (double *)malloc(sizeof(double)*from_rbf->nrbf); |
911 |
|
dst_rem = (double *)malloc(sizeof(double)*to_rbf->nrbf); |
912 |
|
if ((src_rem == NULL) | (dst_rem == NULL)) { |
913 |
< |
fputs("Out of memory in create_migration()\n", stderr); |
913 |
> |
fprintf(stderr, "%s: Out of memory in create_migration()\n", |
914 |
> |
progname); |
915 |
|
exit(1); |
916 |
|
} |
917 |
|
#ifdef DEBUG |
934 |
|
/* fputc('.', stderr); */ |
935 |
|
fprintf(stderr, "%.9f remaining...\r", total_rem); |
936 |
|
#endif |
937 |
< |
} while ((total_rem > end_thresh) & (move_amt > rel_thresh*total_rem)); |
937 |
> |
} while (total_rem > end_thresh && (total_rem > check_thresh) | |
938 |
> |
(move_amt > rel_thresh*total_rem)); |
939 |
|
#ifdef DEBUG |
940 |
|
if (!nchild) fputs("\ndone.\n", stderr); |
941 |
+ |
else fprintf(stderr, "finished with %.9f remaining\n", total_rem); |
942 |
|
#endif |
943 |
|
for (i = from_rbf->nrbf; i--; ) { /* normalize final matrix */ |
944 |
|
float nf = rbf_volume(&from_rbf->rbfa[i]); |
1218 |
|
await_children(nchild); |
1219 |
|
return; |
1220 |
|
} |
1221 |
< |
/* start w/ shortest edge */ |
1086 |
< |
shrt_edj[0] = shrt_edj[1] = NULL; |
1221 |
> |
shrt_edj[0] = shrt_edj[1] = NULL; /* start w/ shortest edge */ |
1222 |
|
for (rbf0 = dsf_list; rbf0 != NULL; rbf0 = rbf0->next) |
1223 |
|
for (rbf1 = rbf0->next; rbf1 != NULL; rbf1 = rbf1->next) { |
1224 |
|
double dist2 = 2. - 2.*DOT(rbf0->invec,rbf1->invec); |
1229 |
|
} |
1230 |
|
} |
1231 |
|
if (shrt_edj[0] == NULL) { |
1232 |
< |
fputs("Cannot find shortest edge\n", stderr); |
1232 |
> |
fprintf(stderr, "%s: Cannot find shortest edge\n", progname); |
1233 |
|
exit(1); |
1234 |
|
} |
1235 |
|
/* build mesh from this edge */ |
1350 |
|
return(1); |
1351 |
|
} |
1352 |
|
|
1353 |
< |
/* Find edge(s) for interpolating the given incident vector */ |
1353 |
> |
/* Find edge(s) for interpolating the given vector, applying symmetry */ |
1354 |
|
static int |
1355 |
< |
get_interp(MIGRATION *miga[3], const FVECT invec) |
1355 |
> |
get_interp(MIGRATION *miga[3], FVECT invec) |
1356 |
|
{ |
1357 |
|
miga[0] = miga[1] = miga[2] = NULL; |
1358 |
|
if (single_plane_incident) { /* isotropic BSDF? */ |
1366 |
|
for (miga[0] = rbf->ejl; miga[0] != NULL; |
1367 |
|
miga[0] = nextedge(rbf,miga[0])) |
1368 |
|
if (opp_rbf(rbf,miga[0]) == rbf->next) |
1369 |
< |
return(1); |
1369 |
> |
return(0); |
1370 |
|
break; |
1371 |
|
} |
1372 |
|
} |
1373 |
< |
return(0); /* outside range! */ |
1373 |
> |
return(-1); /* outside range! */ |
1374 |
|
} |
1375 |
|
{ /* else use triangle mesh */ |
1376 |
+ |
const int sym = use_symmetry(invec); |
1377 |
|
unsigned char floodmap[GRIDRES][(GRIDRES+7)/8]; |
1378 |
|
int pstart[2]; |
1379 |
|
RBFNODE *vother; |
1384 |
|
memset(floodmap, 0, sizeof(floodmap)); |
1385 |
|
/* call flooding function */ |
1386 |
|
if (!identify_tri(miga, floodmap, pstart[0], pstart[1])) |
1387 |
< |
return(0); /* outside mesh */ |
1387 |
> |
return(-1); /* outside mesh */ |
1388 |
|
if ((miga[0] == NULL) | (miga[2] == NULL)) |
1389 |
< |
return(0); /* should never happen */ |
1389 |
> |
return(-1); /* should never happen */ |
1390 |
|
if (miga[1] == NULL) |
1391 |
< |
return(1); /* on edge */ |
1391 |
> |
return(sym); /* on edge */ |
1392 |
|
/* verify triangle */ |
1393 |
|
if (!order_triangle(miga)) { |
1394 |
|
#ifdef DEBUG |
1408 |
|
#ifdef DEBUG |
1409 |
|
fputs("No triangle in get_interp()\n", stderr); |
1410 |
|
#endif |
1411 |
< |
return(0); |
1411 |
> |
return(-1); |
1412 |
|
} |
1413 |
|
/* reassign other two edges */ |
1414 |
|
for (ej = vother->ejl; ej != NULL; |
1423 |
|
#ifdef DEBUG |
1424 |
|
fputs("Bad triangle in get_interp()\n", stderr); |
1425 |
|
#endif |
1426 |
< |
return(0); |
1426 |
> |
return(-1); |
1427 |
|
} |
1428 |
|
} |
1429 |
< |
return(3); /* return in standard order */ |
1429 |
> |
return(sym); /* return in standard order */ |
1430 |
|
} |
1431 |
|
} |
1432 |
|
|
1500 |
|
rbf->vtotal *= mig->rbfv[0]->vtotal; /* turn ratio into actual */ |
1501 |
|
return(rbf); |
1502 |
|
memerr: |
1503 |
< |
fputs("Out of memory in e_advect_rbf()\n", stderr); |
1503 |
> |
fprintf(stderr, "%s: Out of memory in e_advect_rbf()\n", progname); |
1504 |
|
exit(1); |
1505 |
|
return(NULL); /* pro forma return */ |
1506 |
|
} |
1509 |
|
static RBFNODE * |
1510 |
|
advect_rbf(const FVECT invec) |
1511 |
|
{ |
1512 |
+ |
FVECT sivec; |
1513 |
|
MIGRATION *miga[3]; |
1514 |
|
RBFNODE *rbf; |
1515 |
+ |
int sym; |
1516 |
|
float mbfact, mcfact; |
1517 |
|
int n, i, j, k; |
1518 |
|
FVECT v0, v1, v2; |
1519 |
|
double s, t; |
1520 |
|
|
1521 |
< |
if (!get_interp(miga, invec)) /* can't interpolate? */ |
1521 |
> |
VCOPY(sivec, invec); /* find triangle/edge */ |
1522 |
> |
sym = get_interp(miga, sivec); |
1523 |
> |
if (sym < 0) /* can't interpolate? */ |
1524 |
|
return(NULL); |
1525 |
< |
if (miga[1] == NULL) /* advect along edge? */ |
1526 |
< |
return(e_advect_rbf(miga[0], invec)); |
1525 |
> |
if (miga[1] == NULL) { /* advect along edge? */ |
1526 |
> |
rbf = e_advect_rbf(miga[0], sivec); |
1527 |
> |
rev_rbf_symmetry(rbf, sym); |
1528 |
> |
return(rbf); |
1529 |
> |
} |
1530 |
|
#ifdef DEBUG |
1531 |
|
if (miga[0]->rbfv[0] != miga[2]->rbfv[0] | |
1532 |
|
miga[0]->rbfv[1] != miga[1]->rbfv[0] | |
1533 |
|
miga[1]->rbfv[1] != miga[2]->rbfv[1]) { |
1534 |
< |
fputs("Triangle vertex screw-up!\n", stderr); |
1534 |
> |
fprintf(stderr, "%s: Triangle vertex screw-up!\n", progname); |
1535 |
|
exit(1); |
1536 |
|
} |
1537 |
|
#endif |
1540 |
|
normalize(v0); |
1541 |
|
fcross(v2, miga[1]->rbfv[0]->invec, miga[1]->rbfv[1]->invec); |
1542 |
|
normalize(v2); |
1543 |
< |
fcross(v1, invec, miga[1]->rbfv[1]->invec); |
1543 |
> |
fcross(v1, sivec, miga[1]->rbfv[1]->invec); |
1544 |
|
normalize(v1); |
1545 |
|
s = acos(DOT(v0,v1)) / acos(DOT(v0,v2)); |
1546 |
|
geodesic(v1, miga[0]->rbfv[0]->invec, miga[0]->rbfv[1]->invec, |
1547 |
|
s, GEOD_REL); |
1548 |
< |
t = acos(DOT(v1,invec)) / acos(DOT(v1,miga[1]->rbfv[1]->invec)); |
1548 |
> |
t = acos(DOT(v1,sivec)) / acos(DOT(v1,miga[1]->rbfv[1]->invec)); |
1549 |
|
n = 0; /* count migrating particles */ |
1550 |
|
for (i = 0; i < mtx_nrows(miga[0]); i++) |
1551 |
|
for (j = 0; j < mtx_ncols(miga[0]); j++) |
1560 |
|
#endif |
1561 |
|
rbf = (RBFNODE *)malloc(sizeof(RBFNODE) + sizeof(RBFVAL)*(n-1)); |
1562 |
|
if (rbf == NULL) { |
1563 |
< |
fputs("Out of memory in advect_rbf()\n", stderr); |
1563 |
> |
fprintf(stderr, "%s: Out of memory in advect_rbf()\n", progname); |
1564 |
|
exit(1); |
1565 |
|
} |
1566 |
|
rbf->next = NULL; rbf->ejl = NULL; |
1567 |
< |
VCOPY(rbf->invec, invec); |
1567 |
> |
VCOPY(rbf->invec, sivec); |
1568 |
|
rbf->nrbf = n; |
1569 |
|
n = 0; /* compute RBF lobes */ |
1570 |
|
mbfact = s * miga[0]->rbfv[1]->vtotal/miga[0]->rbfv[0]->vtotal * |
1610 |
|
} |
1611 |
|
} |
1612 |
|
rbf->vtotal = miga[0]->rbfv[0]->vtotal * (mbfact + mcfact); |
1613 |
+ |
rev_rbf_symmetry(rbf, sym); |
1614 |
|
return(rbf); |
1615 |
|
} |
1616 |
|
|