void test_on_border_edge_case() { // Create an array of temperatures... double u[50]; fill_array(50, u, 0.0); // Create borders border_t a = {10.0, {0.0, 100.0}, {0.0}}, b = {20.0, {100.0, 0.0}, {0.0}}; // Run an iteration phase_update(&a, &b, u, &material); ASSERT( "Correct temperatures for near-border points", double_equal(u[11], 100.0) && double_equal(u[19], 100.0) ); // Try again with a slighly different position fill_array(50, u, 0.0); a.position = 10.0 - SMALL_VALUE / 100.0; a.u[1] = 100.0; b.u[0] = 100.0; phase_update(&a, &b, u, &material); ASSERT( "Temperatures have been updated correctly", double_approx_equal(u[11], 100.0, 0.01) && double_equal(u[19], 100.0) ); // Try again, but now with the other border. fill_array(50, u, 0.0); a.position = 10.0; b.position = 20.0 + SMALL_VALUE / 100.0; a.u[1] = 100.0; b.u[0] = 100.0; phase_update(&a, &b, u, &material); ASSERT( "Temperatures have been updated correctly", double_equal(u[11], 100.0) && double_approx_equal(u[19], 100.0, 0.01) ); }
/* DIFF: was gto_fit_rxyscale */ static int geo_fit_linear( geomap_fit_t* const fit, surface_t* const sx1, surface_t* const sy1, const size_t ncoord, const coord_t* const input, const coord_t* const ref, const double* const weights, double* const residual_x, double* const residual_y, stimage_error_t* error) { bbox_t bbox; double sw = 0.0; coord_t sr = {0.0, 0.0}; coord_t si = {0.0, 0.0}; coord_t r0 = {0.0, 0.0}; coord_t i0 = {0.0, 0.0}; double sxrxr = 0.0; double syryr = 0.0; double syrxi = 0.0; double sxryi = 0.0; double sxrxi = 0.0; double syryi = 0.0; double num = 0.0; double denom = 0.0; double theta = 0.0; double ctheta = 0.0; double stheta = 0.0; coord_t cthetac = {0.0, 0.0}; coord_t sthetac = {0.0, 0.0}; double xmag = 0.0; double ymag = 0.0; size_t i = 0; int status = 1; assert(fit); assert(sx1); assert(sy1); assert(input); assert(ref); assert(weights); assert(residual_x); assert(residual_y); surface_free(sx1); surface_free(sy1); bbox_copy(&fit->bbox, &bbox); bbox_make_nonsingular(&bbox); /* Compute the sums required to determine the offsets */ compute_sums(ncoord, input, ref, weights, &sw, &si, &sr); if (sw < 3.0) { if (fit->projection == geomap_proj_none) { stimage_error_set_message( error, "Too few data points for X and Y fits."); } else { stimage_error_set_message( error, "Too few data points for XI and ETA fits."); } goto exit; } r0.x = sr.x / sw; r0.y = sr.y / sw; i0.x = si.x / sw; i0.y = si.y / sw; for (i = 0; i < ncoord; ++i) { sxrxr += weights[i] * (ref[i].x - r0.x) * (ref[i].x - r0.x); syryr += weights[i] * (ref[i].y - r0.y) * (ref[i].y - r0.y); syrxi += weights[i] * (ref[i].y - r0.y) * (input[i].x - i0.x); sxryi += weights[i] * (ref[i].x - r0.x) * (input[i].y - i0.y); sxrxi += weights[i] * (ref[i].x - r0.x) * (input[i].x - i0.x); syryi += weights[i] * (ref[i].y - r0.y) * (input[i].y - i0.y); } /* Compute the rotation angle */ num = 2.0 * (sxrxr * syrxi * syryi - syryr * sxrxi * sxryi); denom = syryr * (sxrxi - sxryi) * (sxrxi + sxryi) - \ sxrxr * (syrxi + syryi) * (syrxi - syryi); if (double_approx_equal(num, 0.0) && double_approx_equal(denom, 0.0)) { theta = 0.0; } else { theta = atan2(num, denom) / 2.0; if (theta < 0.0) { theta += M_PI * 2.0; } } ctheta = cos(theta); stheta = sin(theta); /* Compute the X magnification factor */ num = sxrxi * ctheta - sxryi * stheta; denom = sxrxr; if (denom <= 0.0) { xmag = 1.0; } else { xmag = num / denom; } /* Compute the Y magnification factor */ num = syrxi * stheta + syryi * ctheta; denom = syryr; if (denom <= 0.0) { ymag = 1.0; } else { ymag = num / denom; } /* Compute the polynomial coefficients */ cthetac.x = xmag * ctheta; sthetac.x = ymag * stheta; sthetac.y = xmag * stheta; cthetac.x = ymag * ctheta; /* Compute the X and Y fit coefficients */ if (compute_surface_coefficients( fit->function, &bbox, &i0, &r0, &cthetac, &sthetac, sx1, sy1, error)) goto exit; /* Compute the residuals */ if (compute_residuals( sx1, sy1, ncoord, input, ref, residual_x, residual_y, error)) goto exit; /* Compute the number of zero-weighted points */ fit->n_zero_weighted = count_zero_weighted(ncoord, weights); /* Compute the rms of the x and y fits */ compute_rms( ncoord, weights, residual_x, residual_y, &fit->xrms, &fit->yrms); fit->ncoord = ncoord; status = 0; exit: return status; }
static int geo_get_coeff( const surface_t* const sx, const surface_t* const sy, /* Output */ coord_t* const shift, coord_t* const scale, coord_t* const rot, stimage_error_t* const error) { size_t nxxcoeff, nxycoeff, nyxcoeff, nyycoeff; double xxrange = 1.0; double xyrange = 1.0; double xxmaxmin = 1.0; double xymaxmin = 1.0; double yxrange = 1.0; double yyrange = 1.0; double yxmaxmin = 1.0; double yymaxmin = 1.0; double a, b, c, d; assert(sx); assert(sy); assert(shift); assert(scale); assert(rot); assert(sx->coeff); assert(sy->coeff); assert(sx->ncoeff >= 3); assert(sy->ncoeff >= 3); nxxcoeff = nyxcoeff = sx->nxcoeff; nxycoeff = nyycoeff = sy->nycoeff; /* Get the data range */ if (sx->type != surface_type_polynomial) { xxrange = (sx->bbox.max.x - sx->bbox.min.x) / 2.0; xxmaxmin = -(sx->bbox.max.x - sx->bbox.min.x) / 2.0; xyrange = (sx->bbox.max.y - sx->bbox.min.y) / 2.0; xymaxmin = (sx->bbox.max.y - sx->bbox.min.y) / 2.0; } if (sy->type != surface_type_polynomial) { yxrange = (sy->bbox.max.x - sy->bbox.min.x) / 2.0; yxmaxmin = (sy->bbox.max.x - sy->bbox.min.x) / 2.0; yyrange = (sy->bbox.max.y - sy->bbox.min.y) / 2.0; yymaxmin = (sy->bbox.max.y - sy->bbox.min.y) / 2.0; } /* Get the shifts */ shift->x = sx->coeff[0] + \ sx->coeff[1] * xxmaxmin / xxrange + \ sx->coeff[2] * xymaxmin / xyrange; shift->y = sy->coeff[0] + \ sy->coeff[1] * yxmaxmin / yxrange + sx->coeff[2] * yymaxmin / yyrange; /* Get the rotation and scaling parameters */ if (nxxcoeff > 1) { a = sx->coeff[1] / xxrange; } else { a = 0.0; } if (nxycoeff > 1) { b = sx->coeff[nxxcoeff] / xyrange; } else { b = 0.0; } if (nyxcoeff > 1) { c = sx->coeff[1] / yxrange; } else { c = 0.0; } if (nyycoeff > 1) { d = sy->coeff[nyxcoeff] / yyrange; } else { d = 0.0; } scale->x = sqrt(a*a + c*c); scale->y = sqrt(b*b + d*d); if (double_approx_equal(a, 0.0) && double_approx_equal(c, 0.0)) { rot->x = 0.0; } else { rot->x = RADTODEG(atan2(-c, a)); } if (rot->x < 0.0) { rot->x += 360.0; } if (double_approx_equal(b, 0.0) && double_approx_equal(d, 0.0)) { rot->y = 0.0; } else { rot->y = RADTODEG(atan2(b, d)); } if (rot->y < 0.0) { rot->y += 360.0; } return 0; }