/* This is a central procedure for the Natural Neighbours interpolation. It * uses the Watson's algorithm for the required areas calculation and implies * that the vertices of the delaunay triangulation are listed in uniform * (clockwise or counterclockwise) order. */ static void nnpi_triangle_process(nnpi* nn, point* p, int i) { delaunay* d = nn->d; triangle* t = &d->triangles[i]; circle* c = &d->circles[i]; circle cs[3]; int j; /* * There used to be a useful assertion here: * * assert(circle_contains(c, p)); * * I removed it after introducing flag `contains' to * delaunay_circles_find(). It looks like the code is robust enough to * run without this assertion. */ /* * Sibson interpolation by using Watson's algorithm */ for (j = 0; j < 3; ++j) { int j1 = (j + 1) % 3; int j2 = (j + 2) % 3; int v1 = t->vids[j1]; int v2 = t->vids[j2]; if (!circle_build2(&cs[j], &d->points[v1], &d->points[v2], p)) { point* p1 = &d->points[v1]; point* p2 = &d->points[v2]; if ((fabs(p1->x - p->x) + fabs(p1->y - p->y)) / c->r < EPS_SAME) { /* * if (p1->x == p->x && p1->y == p->y) { */ nnpi_add_weight(nn, v1, BIGNUMBER); return; } else if ((fabs(p2->x - p->x) + fabs(p2->y - p->y)) / c->r < EPS_SAME) { /* * } else if (p2->x == p->x && p2->y == p->y) { */ nnpi_add_weight(nn, v2, BIGNUMBER); return; } } } for (j = 0; j < 3; ++j) { int j1 = (j + 1) % 3; int j2 = (j + 2) % 3; double det = ((cs[j1].x - c->x) * (cs[j2].y - c->y) - (cs[j2].x - c->x) * (cs[j1].y - c->y)); if (isnan(det)) { /* * If the determinant is NaN, then the interpolation point lies * almost in between two data points. This case is difficult to * handle robustly because the areas calculated are obtained as a * diference between two big numbers. * * Here this is handles in the following way. If a circle is * recognised as very large in circle_build2(), then it parameters * are replaced by NaNs, which results in det above being NaN. * The resulting area to be calculated for a vertex does not * change if the circle center is moved along some line. The closer * it is moved to the actual data point positions, the more * numerically robust the calculation of areas becomes. In * particular, it can be moved to coincide with one of the other * circle centers. When this is done, it is ticked by placing the * edge parameters into the hash table, so that when the * "cancelling" would be about to be done, this new position is * used instead. * * One complicated circumstance is that sometimes a circle is * recognised as very large in cases when it is actually not, * when the interpolated point is close to a data point. This is * handled by a special treatment in _nnpi_calculate_weights(). */ int remove = 1; circle* cc = NULL; int key[2]; key[0] = t->vids[j]; if (nn->bad == NULL) nn->bad = ht_create_i2(HT_SIZE); if (isnan(cs[j1].x)) { key[1] = t->vids[j2]; cc = ht_find(nn->bad, &key); if (cc == NULL) { remove = 0; cc = malloc(sizeof(circle)); cc->x = cs[j2].x; cc->y = cs[j2].y; assert(ht_insert(nn->bad, &key, cc) == NULL); } det = ((cc->x - c->x) * (cs[j2].y - c->y) - (cs[j2].x - c->x) * (cc->y - c->y)); } else { /* j2 */ key[1] = t->vids[j1]; cc = ht_find(nn->bad, &key); if (cc == NULL) { remove = 0; cc = malloc(sizeof(circle)); cc->x = cs[j1].x; cc->y = cs[j1].y; assert(ht_insert(nn->bad, &key, cc) == NULL); } det = ((cs[j1].x - c->x) * (cc->y - c->y) - (cc->x - c->x) * (cs[j1].y - c->y)); } if (remove) assert(ht_delete(nn->bad, &key) != NULL); } nnpi_add_weight(nn, t->vids[j], det); } }
/* This is a central procedure for the Natural Neighbours interpolation. It * uses the Watson's algorithm for the required areas calculation and implies * that the vertices of the delaunay triangulation are listed in uniform * (clockwise or counterclockwise) order. */ static void nnpi_triangle_process(nnpi* nn, point* p, int i) { delaunay* d = nn->d; triangle* t = &d->triangles[i]; circle* c = &d->circles[i]; circle cs[3]; int j; /* * There used to be a useful assertion here: * * assert(circle_contains(c, p)); * * I removed it after introducing flag `contains' to * delaunay_circles_find(). It looks like the code is robust enough to * run without this assertion. */ /* * Sibson interpolation by using Watson's algorithm */ for (j = 0; j < 3; ++j) { int j1 = (j + 1) % 3; int j2 = (j + 2) % 3; int v1 = t->vids[j1]; int v2 = t->vids[j2]; if (!circle_build2(&cs[j], &d->points[v1], &d->points[v2], p)) { point* p1 = &d->points[v1]; point* p2 = &d->points[v2]; if ((fabs(p1->x - p->x) + fabs(p1->y - p->y)) / c->r < EPS_SAME) { /* * if (p1->x == p->x && p1->y == p->y) { */ nnpi_add_weight(nn, v1, BIGNUMBER); return; } else if ((fabs(p2->x - p->x) + fabs(p2->y - p->y)) / c->r < EPS_SAME) { /* * } else if (p2->x == p->x && p2->y == p->y) { */ nnpi_add_weight(nn, v2, BIGNUMBER); return; } } } for (j = 0; j < 3; ++j) { int j1 = (j + 1) % 3; int j2 = (j + 2) % 3; double det = ((cs[j1].x - c->x) * (cs[j2].y - c->y) - (cs[j2].x - c->x) * (cs[j1].y - c->y)); if (isnan(det)) { /* * Here, if the determinant is NaN, then the interpolation point * lies almost in between two data points. This case is difficult to * handle robustly because the areas (determinants) calculated by * Watson's algorithm are obtained as a diference between two big * numbers. This case is handled here in the following way. * * If a circle is recognised as very large in circle_build2(), then * its parameters are replaced by NaNs, which results in the * variable `det' above being NaN. * * When this happens inside convex hall of the data, there is * always a triangle on another side of the edge, processing of * which also produces an invalid circle. Processing of this edge * yields two pairs of infinite determinants, with singularities * of each pair cancelling if the point moves slightly off the edge. * * Each of the determinants corresponds to the (signed) area of a * triangle, and an inifinite determinant corresponds to the area of * a triangle with one vertex moved to infinity. "Subtracting" one * triangle from another within each pair yields a valid * quadrilateral (in fact, a trapezoid). The doubled area of these * quadrilaterals is calculated in the cycle over ii below. */ int j1bad = isnan(cs[j1].x); int key[2]; double* v = NULL; key[0] = t->vids[j]; if (nn->bad == NULL) nn->bad = ht_create_i2(HT_SIZE); key[1] = (j1bad) ? t->vids[j2] : t->vids[j1]; v = ht_find(nn->bad, &key); if (v == NULL) { v = malloc(8 * sizeof(double)); if (j1bad) { v[0] = cs[j2].x; v[1] = cs[j2].y; } else { v[0] = cs[j1].x; v[1] = cs[j1].y; } v[2] = c->x; v[3] = c->y; (void) ht_insert(nn->bad, &key, v); det = 0.0; } else { int ii; if (j1bad) { v[6] = cs[j2].x; v[7] = cs[j2].y; } else { v[6] = cs[j1].x; v[7] = cs[j1].y; } v[4] = c->x; v[5] = c->y; det = 0; for (ii = 0; ii < 4; ++ii) { int ii1 = (ii + 1) % 4; det += (v[ii * 2] + v[ii1 * 2]) * (v[ii * 2 + 1] - v[ii1 * 2 + 1]); } det = fabs(det); free(v); ht_delete(nn->bad, &key); } } nnpi_add_weight(nn, t->vids[j], det); } }