26 const double tol = 1e-18;
33 double u01[3], u12[3], u20[3];
36 cell.
num_corners == 3,
"ERROR(yac_triangle_area): cell is not a triangle")
56 if ( fabs(s01) <
tol ||
65 for (
int m = 0; m < 3; m++ ) {
79 ca1 = -u01[0]*u20[0]-u01[1]*u20[1]-u01[2]*u20[2];
80 ca2 = -u12[0]*u01[0]-u12[1]*u01[1]-u12[2]*u01[2];
81 ca3 = -u20[0]*u12[0]-u20[1]*u12[1]-u20[2]*u12[2];
83 if ( ca1 < -1.0 ) ca1 = -1.0;
84 if ( ca1 > 1.0 ) ca1 = 1.0;
85 if ( ca2 < -1.0 ) ca2 = -1.0;
86 if ( ca2 > 1.0 ) ca2 = 1.0;
87 if ( ca3 < -1.0 ) ca3 = -1.0;
88 if ( ca3 > 1.0 ) ca3 = 1.0;
99 return MAX( (a1+a2+a3-M_PI) , 0.0 );
143 double sin_sin = angle_a.
sin * angle_b.
sin;
144 double sin_cos = angle_a.
sin * angle_b.
cos;
145 double cos_sin = angle_a.
cos * angle_b.
sin;
146 double cos_cos = angle_a.
cos * angle_b.
cos;
148 double sin_sin_sin = sin_sin * angle_c.
sin;
149 double sin_sin_cos = sin_sin * angle_c.
cos;
150 double sin_cos_sin = sin_cos * angle_c.
sin;
151 double sin_cos_cos = sin_cos * angle_c.
cos;
152 double cos_sin_sin = cos_sin * angle_c.
sin;
153 double cos_sin_cos = cos_sin * angle_c.
cos;
154 double cos_cos_sin = cos_cos * angle_c.
sin;
155 double cos_cos_cos = cos_cos * angle_c.
cos;
157 double t_sin_a = sin_sin_sin - sin_cos_cos;
158 double t_sin_b = cos_sin_cos + cos_cos_sin;
159 double t_sin_c = sin_sin_sin + sin_cos_cos;
160 double t_sin_d = cos_sin_cos - cos_cos_sin;
161 double t_cos_a = cos_cos_cos - cos_sin_sin;
162 double t_cos_b = sin_sin_cos + sin_cos_sin;
163 double t_cos_c = cos_cos_cos + cos_sin_sin;
164 double t_cos_d = sin_sin_cos - sin_cos_sin;
169 .cos = + t_cos_a - t_cos_b}),
172 .cos = + t_cos_a + t_cos_b}),
175 .cos = + t_cos_c + t_cos_d}),
178 .cos = + t_cos_c - t_cos_d})};
180 double t = (t_angle[0].
sin*t_angle[1].
sin*t_angle[2].
sin*t_angle[3].
sin) /
181 (t_angle[0].
cos*t_angle[1].
cos*t_angle[2].
cos*t_angle[3].
cos);
183 return 4.0 * atan(sqrt(fabs(t)));
186static double tri_area(
double u[3],
double v[3],
double w[3]) {
200 double scale = sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
214 return atan2(a[1] , a[0]);
218 double base_vec[3],
double a[3],
double b[3],
double * middle_lat) {
225 double const tol = 1e-8;
228 fabs(a[2]-b[2]) <=
tol,
229 "ERROR(lat_edge_correction_): "
230 "latitude of both corners is not identical")
232 double h = fabs(a[2]);
235 if (h <
tol || fabs(1.0 - h) <
tol)
return 0.0;
248 double pole[3] = {0, 0, (a[2] >= 0.0)?1.0:-1.0};
249 double gc_area =
tri_area(a, b, pole);
253 double correction =
MAX(lat_area - gc_area, 0.0);
261 middle_lat[0] = a[0]+b[0];
262 middle_lat[1] = a[1]+b[1];
263 middle_lat[2] = a[2];
264 double scale = sqrt(middle_lat[0]*middle_lat[0]+middle_lat[1]*middle_lat[1]);
265 YAC_ASSERT(fabs(scale) >= 1e-18,
"internal error")
266 scale = sqrt(1.0 - a[2]*a[2]) / scale;
267 middle_lat[0] *= scale;
268 middle_lat[1] *= scale;
274 int negative_correction_flag;
277 if (fabs(scalar_base) < 1e-11) {
283 double norm_middle[3];
287 negative_correction_flag = scalar_a <= 0;
294 negative_correction_flag = scalar_middle_lat >= 0;
297 return negative_correction_flag?-correction:correction;
301 double base_vec[3],
double a[3],
double b[3]) {
303 double middle_lat[3];
308 double base_vec[3],
double a[3],
double b[3],
309 double * barycenter,
double sign) {
311 double middle_lat[3];
314 if (correction == 0.0)
return 0.0;
316 double middle_gc[3] = {a[0] + b[0], a[1] + b[1], a[2] + b[2]};
319 double temp_barycenter[3] =
320 {middle_lat[0] + middle_gc[0],
321 middle_lat[1] + middle_gc[1],
322 middle_lat[2] + middle_gc[2]};
325 barycenter[0] += temp_barycenter[0] * correction * sign;
326 barycenter[1] += temp_barycenter[1] * correction * sign;
327 barycenter[2] += temp_barycenter[2] * correction * sign;
329 return correction * sign;
336 double coordinates_x[M];
337 double coordinates_y[M];
339 for (
size_t i = 0; i < M; ++i)
344 if (M < 2)
return 0.0;
346 int closer_to_south_pole = coordinates_y[0] < 0;
348 double pole_vec[3] = {0, 0, (closer_to_south_pole)?-1.0:1.0};
356 for (
size_t i = 0; i < M; ++i) {
359 if (fabs(fabs(coordinates_y[i]) - M_PI_2) < 1e-12)
continue;
360 if (fabs(fabs(coordinates_y[(i+1)%M]) - M_PI_2) < 1e-12) {
369 "ERROR: unsupported edge type")
385 double tmp_area =
tri_area(a, b, pole_vec);
389 else area += tmp_area;
399 double d_lon =
get_angle(coordinates_x[i], coordinates_x[(i+1)%M]);
400 double d_lat = M_PI_2;
402 if (closer_to_south_pole)
403 d_lat += coordinates_y[i];
405 d_lat -= coordinates_y[i];
407 double h = 1 -
cos(d_lat);
424 double norm[3] = {0,0,0};
427 if (M < 3)
return 0.0;
429 for (
size_t i0 = M - 1, i1 = 0; i1 < M; i0 = i1, ++i1) {
438 return 0.5 * sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
453 if (M < 2)
return 0.0;
457 for (
size_t i = 0; i < M; i++)
460 if (M == 3 && !lat_flag)
468 for (
size_t i = 2; i < M; ++i) {
481 if (scalar_base > 0) area += tmp_area;
482 else area -= tmp_area;
488 for (
size_t i = 0; i < M; ++i) {
505 double ref[3],
double a[3],
double b[3],
506 double * barycenter,
double sign) {
508 double * corners[3] = {b, ref, a};
511 int zero_angle_flag = 0;
512 for (
int i = 0, j = 2; i < 3; j = i++) {
516 cross[i][1]*cross[i][1] +
517 cross[i][2]*cross[i][2]),
519 zero_angle_flag |= angles[i].
sin == 0.0;
522 if (zero_angle_flag)
return 0.0;
524 double area =
tri_area_(angles[0], angles[1], angles[2]);
528 for (
int i = 0; i < 3; ++i) {
530 for (
int j = 0; j < 3; ++j)
531 barycenter[j] += cross[i][j] * scale;
540 struct yac_grid_cell cell,
double * barycenter,
double sign) {
544 if (M < 2)
return 0.0;
548 for (
size_t i = 0; i < M; i++)
551 if (M == 3 && !lat_flag)
560 for (
size_t i = 2; i < M; ++i) {
572 for (
size_t i = 0; i < M; ++i) {
593 return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
static int compute_norm_vector(double a[], double b[], double norm[])
static double tri_area_(struct sin_cos_angle angle_a, struct sin_cos_angle angle_b, struct sin_cos_angle angle_c)
static double scalar_product(double a[], double b[])
static double tri_area_info(double ref[3], double a[3], double b[3], double *barycenter, double sign)
static double lat_edge_correction_info(double base_vec[3], double a[3], double b[3], double *barycenter, double sign)
double yac_huiliers_area(struct yac_grid_cell cell)
Area calculation on a unit sphere taken from ESMF based on L'Huilier's Theorem.
static double tri_area(double u[3], double v[3], double w[3])
double yac_pole_area(struct yac_grid_cell cell)
Calculate the area of a cell in a 3d plane on a unit sphere.
static double XYZtoLon(double a[3])
double yac_planar_3dcell_area(struct yac_grid_cell cell)
Area calculation on a unit sphere of a planar polygon in 3D.
static double lat_edge_correction_(double base_vec[3], double a[3], double b[3], double *middle_lat)
static double lat_edge_correction(double base_vec[3], double a[3], double b[3])
static struct sin_cos_angle tri_area_quarter_angle(struct sin_cos_angle angle)
double yac_huiliers_area_info(struct yac_grid_cell cell, double *barycenter, double sign)
double yac_triangle_area(struct yac_grid_cell cell)
Calculate the area of a triangle on a unit sphere.
Structs and interfaces for area calculations.
static int edge_direction(double *a, double *b)
static struct sin_cos_angle get_vector_angle_2(double const a[3], double const b[3])
static const struct sin_cos_angle SIN_COS_LOW_TOL
static const struct sin_cos_angle SIN_COS_7_M_PI_4
static const struct sin_cos_angle SIN_COS_ZERO
static void crossproduct_kahan(double const a[], double const b[], double cross[])
static struct sin_cos_angle quarter_angle(struct sin_cos_angle angle)
static int compare_angles(struct sin_cos_angle a, struct sin_cos_angle b)
static double compute_angle(struct sin_cos_angle angle)
return angles in the range of [0;2PI[
static void normalise_vector(double v[])
static double get_angle(double a_lon, double b_lon)
static struct sin_cos_angle sin_cos_angle_new(double sin, double cos)
static void XYZtoLL(double const p_in[], double *lon, double *lat)
@ YAC_GREAT_CIRCLE_EDGE
great circle
@ YAC_LAT_CIRCLE_EDGE
latitude circle
@ YAC_LON_CIRCLE_EDGE
longitude circle
enum yac_edge_type * edge_type
double(* coordinates_xyz)[3]
#define YAC_ASSERT(exp, msg)