#include "c4d_general.h" #include "c4d_shader.h" #include "c4d_memory.h" #include "matrixrotate.h" #define MAX_POINTS 16 struct MPOINT { Float64 x; Float64 y; }; struct MPOINT_LE { MPOINT_LE* prev; MPOINT_LE* next; MPOINT p; }; struct MBOUNDS { Int32 no_pts; Float64 xmin; // bounding rectangle Float64 ymin; Float64 xmax; Float64 ymax; MPOINT pts[MAX_POINTS]; }; static void rotate_m90(WEIGHT_FMATRIX* m); static void rotate_m180(WEIGHT_FMATRIX* m); static void rotate_m270(WEIGHT_FMATRIX* m); static Float64 get_matrix_value(const WEIGHT_FMATRIX* m, Int32 x, Int32 y); static void add_to_matrix_value(WEIGHT_FMATRIX* m, Int32 x, Int32 y, Float64 value); static void distribute_source_element(Int32 x_src, Int32 y_src, Float64 src_value, Float64 r, WEIGHT_FMATRIX* output_matrix); static void matrix_entry_to_bounds(Int32 x, Int32 y, Float64 r, MBOUNDS* out); static void matrix_entries_to_bounds(Int32 x1, Int32 y1, Int32 x2, Int32 y2, Float64 r, MBOUNDS* out); static Float64 get_intersection_area(MBOUNDS* src_me, MBOUNDS* dst_me); static Bool sect_polygons(MBOUNDS* src_me, MBOUNDS* dst_me, MBOUNDS* sect_me); static Bool sect_lines(MPOINT* line_a, MPOINT* line_b, MPOINT* sect); static Int32 intersect_lines(MPOINT* s1, MPOINT* s2, MPOINT* out); static Bool test_inside(MPOINT* pts, Int32 no_pts, MPOINT* check_point); static Float64 get_simple_polygon_area(MBOUNDS* me); void rotate_matrix(const WEIGHT_FMATRIX* input_matrix, WEIGHT_FMATRIX* output_matrix, Float64 r) { Float32* dst_value; Int32 x_dst; Int32 y_dst; Int32 x_src; Int32 y_src; Int32 q; MBOUNDS mm; Int32 xmin; Int32 ymin; Int32 xmax; Int32 ymax; q = (Int32)floor(r / PI05); r = r - (q * PI05); q %= 4; // # of 90 degree rotations if (q < 0) q = 4 - q; matrix_entries_to_bounds(-input_matrix->x_origin, input_matrix->y_origin - (input_matrix->no_matrix_columns - 1), input_matrix->no_matrix_rows - input_matrix->x_origin - 1, input_matrix->y_origin, r, &mm); xmin = (Int32)floor(mm.xmin + 0.5); // x index of the first intersected destination element ymin = (Int32)floor(mm.ymin + 0.5); xmax = (Int32)ceil(mm.xmax + 0.5); // x index of the first destination element that's not intersected anymore ymax = (Int32)ceil(mm.ymax + 0.5); xmax--; // x index of the las element that's intersected ymax--; output_matrix->no_matrix_columns = xmax - xmin + 1; output_matrix->no_matrix_rows = ymax - ymin + 1; output_matrix->x_origin = -xmin; output_matrix->y_origin = ymax; if (output_matrix->no_matrix_columns > MAXTRIX_MAX_COLUMNS) { output_matrix->no_matrix_columns = MAXTRIX_MAX_COLUMNS; output_matrix->x_origin = MAXTRIX_MAX_COLUMNS >> 1; } if (output_matrix->no_matrix_rows > MAXTRIX_MAX_ROWS) { output_matrix->no_matrix_rows = MAXTRIX_MAX_ROWS; output_matrix->y_origin = MAXTRIX_MAX_ROWS >> 1; } if (r) { dst_value = output_matrix->matrix_values; for (y_dst = 0; y_dst < output_matrix->no_matrix_rows; y_dst++) { for (x_dst = 0; x_dst < output_matrix->no_matrix_columns; x_dst++) *dst_value++ = 0.0; } for (y_src = 0; y_src < input_matrix->no_matrix_rows; y_src++) { for (x_src = 0; x_src < input_matrix->no_matrix_columns; x_src++) { Int32 xc; Int32 yc; Float64 src_value; xc = x_src - input_matrix->x_origin; // negative x values are on the left in the matrix yc = input_matrix->y_origin - y_src; // negative y values are at the bottom of the matrix (not like on the screen) if (xc == yc) { if (xc == 0) yc = xc; } src_value = get_matrix_value(input_matrix, xc, yc); distribute_source_element(xc, yc, src_value, r, output_matrix); } } } else // simple rotation is sufficient { WEIGHT_FMATRIX_MAX* tmp; tmp = (WEIGHT_FMATRIX_MAX*) output_matrix; *tmp = *(WEIGHT_FMATRIX_MAX*) input_matrix; // just copy the input matrix } switch (q) { case 1: rotate_m90(output_matrix); break; case 2: rotate_m180(output_matrix); break; case 3: rotate_m270(output_matrix); break; } } //---------------------------------------------------------------------------------------- // Rotate a matrix by 90 degrees (counterclockwise) // Function result: - // m: matrix object //---------------------------------------------------------------------------------------- static void rotate_m90(WEIGHT_FMATRIX* m) { WEIGHT_FMATRIX_MAX tmp; Float32* src; Float32* dst; Int32 x; Int32 y; tmp = *(WEIGHT_FMATRIX_MAX*) m; src = tmp.matrix_values; m->no_matrix_columns = tmp.no_matrix_rows; m->no_matrix_rows = tmp.no_matrix_columns; m->x_origin = tmp.y_origin; m->y_origin = tmp.x_origin; for (x = 0; x < m->no_matrix_columns; x++) { dst = m->matrix_values + x; dst += m->no_matrix_rows * m->no_matrix_columns; for (y = m->no_matrix_rows; y > 0; y--) { dst -= m->no_matrix_columns; *dst = *src++; } } } //---------------------------------------------------------------------------------------- // Rotate a matrix by 180 degrees (counterclockwise) // Function result: - // m: matrix object //---------------------------------------------------------------------------------------- static void rotate_m180(WEIGHT_FMATRIX* m) { WEIGHT_FMATRIX_MAX tmp; Float32* src; Float32* dst; Int32 x; Int32 y; tmp = *(WEIGHT_FMATRIX_MAX*) m; src = tmp.matrix_values; m->no_matrix_columns = tmp.no_matrix_columns; m->no_matrix_rows = tmp.no_matrix_rows; m->x_origin = tmp.y_origin; m->y_origin = tmp.x_origin; dst = m->matrix_values; dst += m->no_matrix_rows * m->no_matrix_columns; for (x = 0; x < m->no_matrix_columns; x++) { for (y = m->no_matrix_rows; y > 0; y--) *(--dst) = *src++; } } //---------------------------------------------------------------------------------------- // Rotate a matrix by 270 degrees (counterclockwise) // Function result: - // m: matrix object //---------------------------------------------------------------------------------------- static void rotate_m270(WEIGHT_FMATRIX* m) { WEIGHT_FMATRIX_MAX tmp; Float32* src; Float32* dst; Int32 x; Int32 y; tmp = *(WEIGHT_FMATRIX_MAX*) m; src = tmp.matrix_values; m->no_matrix_columns = tmp.no_matrix_rows; m->no_matrix_rows = tmp.no_matrix_columns; m->x_origin = tmp.y_origin; m->y_origin = tmp.x_origin; for (x = m->no_matrix_columns - 1; x >= 0; x--) { dst = m->matrix_values + x; for (y = m->no_matrix_rows; y > 0; y--) { *dst = *src++; dst += m->no_matrix_columns; } } } //---------------------------------------------------------------------------------------- // Return a matrix value (positions outside the matrix are clipped) // Function result: matrix value // m: matrix object // x: x coordinate (relative to the matrix center, negative values are left) // y: y coordinate (relative to the matrix center, positive values are top) //---------------------------------------------------------------------------------------- static Float64 get_matrix_value(const WEIGHT_FMATRIX* m, Int32 x, Int32 y) { const Float32* v; x += m->x_origin; y = m->y_origin - y; if ((x < 0) || (x >= m->no_matrix_columns) || (y < 0) || (y >= m->no_matrix_rows)) return 0.0; v = m->matrix_values; v += y * m->no_matrix_columns; v += x; return *v; } //---------------------------------------------------------------------------------------- // Add a value to a matrix element's value // Function result: - // m: matrix object // x: x coordinate (relative to the matrix center, negative values are left) // y: y coordinate (relative to the matrix center, positive values are top) // value: value to add //---------------------------------------------------------------------------------------- static void add_to_matrix_value(WEIGHT_FMATRIX* m, Int32 x, Int32 y, Float64 value) { Float32* v; x += m->x_origin; y = m->y_origin - y; if ((x < 0) || (x >= m->no_matrix_columns) || (y < 0) || (y >= m->no_matrix_rows)) return; v = m->matrix_values; v += y * m->no_matrix_columns; v += x; *v += value; } //---------------------------------------------------------------------------------------- // Distribute the value of a rotated source matrix element over the intersected destination // matrix elements by weighting its value with the intersection area // Function result: - // x_src: x coordinate in the source matrix (relative to the matrix center) // y_src: y coordinate in the source matrix (relative to the matrix center) // src_value: value of the source matrix element // r: rotation angle for x_src and y_src // output_matrix: //---------------------------------------------------------------------------------------- static void distribute_source_element(Int32 x_src, Int32 y_src, Float64 src_value, Float64 r, WEIGHT_FMATRIX* output_matrix) { MBOUNDS src_me; Int32 xmin; Int32 ymin; Int32 xmax; Int32 ymax; Int32 x; Int32 y; Float64 ws; // Tab Size: 2 // Comments: *Column 60* matrix_entry_to_bounds(x_src, y_src, r, &src_me); // create a bounding polygon xmin = (Int32)floor(src_me.xmin + 0.5); // x index of the first intersected destination element ymin = (Int32)floor(src_me.ymin + 0.5); xmax = (Int32)ceil(src_me.xmax + 0.5); // x index of the first destination element that's not intersected anymore ymax = (Int32)ceil(src_me.ymax + 0.5); ws = 0; for (y = ymin; y < ymax; y++) { for (x = xmin; x < xmax; x++) { MBOUNDS dst_me; Float64 weight; matrix_entry_to_bounds(x, y, 0, &dst_me); // create a bounding polygon for the destination element weight = get_intersection_area(&src_me, &dst_me); ws += weight; if (weight) { add_to_matrix_value(output_matrix, x, y, src_value * weight); } } } } //---------------------------------------------------------------------------------------- // Create a bounding polygon for a matrix entry. Matrix Entry x/y = ( 0 /0 ) means that the // polygon will be ( -0.5/-0.5 ), ( 0.5/-0.5 ), ( 0.5/0.5 ), ( -0.5/0.5 ) and again ( -0.5/-0.5 ) // The polygon is counterclockwise. // Function result: - // x: x coordinate (relative to the matrix center) // y: y coordinate (relative to the matrix center) // r: rotation angle // out: used to return the polygon //---------------------------------------------------------------------------------------- static void matrix_entry_to_bounds(Int32 x, Int32 y, Float64 r, MBOUNDS* out) { Float64 cosa; Float64 sina; Float64 fx; Float64 fy; Int32 i; fx = (Float64) x - 0.5; fy = (Float64) y - 0.5; cosa = Cos(r); sina = Sin(r); if ((sina == 1.0) || (sina == -1.0)) // this litte extra checking is necessary because Cos( PI05 ) is not zero! cosa = 0.0; if ((cosa == 1.0) || (cosa == -1.0)) sina = 0.0; out->no_pts = 5; out->pts[0].x = (cosa * fx) - (sina * fy); out->pts[0].y = (sina * fx) + (cosa * fy); fx += 1.0; out->pts[1].x = (cosa * fx) - (sina * fy); out->pts[1].y = (sina * fx) + (cosa * fy); fy += 1.0; out->pts[2].x = (cosa * fx) - (sina * fy); out->pts[2].y = (sina * fx) + (cosa * fy); fx -= 1.0; out->pts[3].x = (cosa * fx) - (sina * fy); out->pts[3].y = (sina * fx) + (cosa * fy); out->pts[4].x = out->pts[0].x; out->pts[4].y = out->pts[0].y; out->xmin = out->pts[0].x; out->ymin = out->pts[0].y; out->xmax = out->pts[0].x; out->ymax = out->pts[0].y; for (i = 3; i > 0; i--) // find bounding rect { if (out->pts[i].x < out->xmin) out->xmin = out->pts[i].x; if (out->pts[i].x > out->xmax) out->xmax = out->pts[i].x; if (out->pts[i].y < out->ymin) out->ymin = out->pts[i].y; if (out->pts[i].y > out->ymax) out->ymax = out->pts[i].y; } } //---------------------------------------------------------------------------------------- // Create a bounding polygon for a matrix entry. Matrix Entry x/y = ( 0 /0 ) means that the // polygon will be ( -0.5/-0.5 ), ( 0.5/-0.5 ), ( 0.5/0.5 ), ( -0.5/0.5 ) and again ( -0.5/-0.5 ) // The polygon is counterclockwise. // Function result: - // x: x coordinate (relative to the matrix center) // y: y coordinate (relative to the matrix center) // r: rotation angle // out: used to return the polygon //---------------------------------------------------------------------------------------- static void matrix_entries_to_bounds(Int32 x1, Int32 y1, Int32 x2, Int32 y2, Float64 r, MBOUNDS* out) { Float64 cosa; Float64 sina; Float64 fx1; Float64 fy1; Float64 fx2; Float64 fy2; Int32 i; fx1 = (Float64) x1 - 0.5; fy1 = (Float64) y1 - 0.5; fx2 = (Float64) x2 + 0.5; fy2 = (Float64) y2 + 0.5; cosa = Cos(r); sina = Sin(r); if ((sina == 1.0) || (sina == -1.0)) // this litte extra checking is necessary because Cos( PI05 ) is not zero! cosa = 0.0; if ((cosa == 1.0) || (cosa == -1.0)) sina = 0.0; out->no_pts = 5; out->pts[0].x = (cosa * fx1) - (sina * fy1); out->pts[0].y = (sina * fx1) + (cosa * fy1); out->pts[1].x = (cosa * fx2) - (sina * fy1); out->pts[1].y = (sina * fx2) + (cosa * fy1); out->pts[2].x = (cosa * fx2) - (sina * fy2); out->pts[2].y = (sina * fx2) + (cosa * fy2); out->pts[3].x = (cosa * fx1) - (sina * fy2); out->pts[3].y = (sina * fx1) + (cosa * fy2); out->pts[4].x = out->pts[0].x; out->pts[4].y = out->pts[0].y; out->xmin = out->pts[0].x; out->ymin = out->pts[0].y; out->xmax = out->pts[0].x; out->ymax = out->pts[0].y; for (i = 3; i > 0; i--) // find bounding rect { if (out->pts[i].x < out->xmin) out->xmin = out->pts[i].x; if (out->pts[i].x > out->xmax) out->xmax = out->pts[i].x; if (out->pts[i].y < out->ymin) out->ymin = out->pts[i].y; if (out->pts[i].y > out->ymax) out->ymax = out->pts[i].y; } } static Float64 get_intersection_area(MBOUNDS* src_me, MBOUNDS* dst_me) { Float64 area; MBOUNDS sect_me; area = 0; if (sect_polygons(src_me, dst_me, §_me)) area = get_simple_polygon_area(§_me); if (area > 1.0) area = 1.0; return area; } static Bool sect_polygons(MBOUNDS* src_me, MBOUNDS* dst_me, MBOUNDS* sect_me) { Int32 i; Int32 j; Int32 k; MPOINT tmp; Bool add_pt; sect_me->no_pts = 0; for (i = 0; i < dst_me->no_pts - 1; i++) // intersect all source and destination lines and put the intersection points into sect_me { Int32 fi; fi = sect_me->no_pts; tmp = dst_me->pts[i]; if (test_inside(src_me->pts, src_me->no_pts - 1, &tmp)) // is a vertex of dst inside src? { add_pt = true; for (k = 0; k < sect_me->no_pts; k++) // check if this point is already present { if ((sect_me->pts[k].x == tmp.x) && (sect_me->pts[k].y == tmp.y)) { add_pt = false; break; } } if (add_pt) { sect_me->pts[sect_me->no_pts] = tmp; sect_me->no_pts++; } } for (j = 0; j < src_me->no_pts - 1; j++) { tmp = src_me->pts[i]; if (test_inside(dst_me->pts, dst_me->no_pts - 1, &tmp)) // is a vertex of src inside dst? { add_pt = true; for (k = 0; k < sect_me->no_pts; k++) // check if this point is already present { if ((sect_me->pts[k].x == tmp.x) && (sect_me->pts[k].y == tmp.y)) { add_pt = false; break; } } if (add_pt) { sect_me->pts[sect_me->no_pts] = tmp; sect_me->no_pts++; } } if (sect_lines(src_me->pts + j, dst_me->pts + i, &tmp)) { add_pt = true; for (k = 0; k < sect_me->no_pts; k++) // check if this point is already present { if ((sect_me->pts[k].x == tmp.x) && (sect_me->pts[k].y == tmp.y)) { add_pt = false; break; } } if (add_pt) { sect_me->pts[sect_me->no_pts] = tmp; sect_me->no_pts++; } } } { Int32 x_dir; Int32 y_dir; Int32 cnt; if (dst_me->pts[i].x <= dst_me->pts[i + 1].x) x_dir = 1; else x_dir = -1; if (dst_me->pts[i].y <= dst_me->pts[i + 1].y) y_dir = 1; else y_dir = -1; cnt = sect_me->no_pts - fi; if (cnt > 1) { MPOINT* p; MPOINT s; p = sect_me->pts + fi; for (j = cnt - 1; j > 0; j--) { for (k = 0; k < j; k++) { s = p[k]; if (x_dir > 0) { if (p[k].x > p[k + 1].x) { p[k] = p[k + 1]; p[k + 1] = s; } else if (p[k].x == p[k + 1].x) { if (y_dir > 0) { if (p[k].y > p[k + 1].y) { p[k] = p[k + 1]; p[k + 1] = s; } } else { if (p[k].y < p[k + 1].y) { p[k] = p[k + 1]; p[k + 1] = s; } } } } else { if (p[k].x < p[k + 1].x) { p[k] = p[k + 1]; p[k + 1] = s; } else if (p[k].x == p[k + 1].x) { if (y_dir > 0) { if (p[k].y > p[k + 1].y) { p[k] = p[k + 1]; p[k + 1] = s; } } else { if (p[k].y < p[k + 1].y) { p[k] = p[k + 1]; p[k + 1] = s; } } } } } } } } } if (sect_me->no_pts) { sect_me->xmin = sect_me->pts[0].x; sect_me->ymin = sect_me->pts[0].y; sect_me->xmax = sect_me->pts[0].x; sect_me->ymax = sect_me->pts[0].y; for (i = sect_me->no_pts - 1; i > 0; i--) // find bounding rect { if (sect_me->pts[i].x < sect_me->xmin) sect_me->xmin = sect_me->pts[i].x; if (sect_me->pts[i].x > sect_me->xmax) sect_me->xmax = sect_me->pts[i].x; if (sect_me->pts[i].y < sect_me->ymin) sect_me->ymin = sect_me->pts[i].y; if (sect_me->pts[i].y > sect_me->ymax) sect_me->ymax = sect_me->pts[i].y; } sect_me->pts[sect_me->no_pts] = sect_me->pts[0]; // close polygon sect_me->no_pts++; return true; } return false; } static Bool sect_lines(MPOINT* line_a, MPOINT* line_b, MPOINT* sect) { if ((line_a[0].x == line_b[0].x) && (line_a[0].y == line_b[0].y)) { *sect = line_a[0]; return true; } if (intersect_lines(line_a, line_b, sect) == 1) return true; return false; } //---------------------------------------------------------------------------------------- // Check wheter two lines intersect (or a colinear) // Function result: 0: no intersection 1: intersection 2: colinear (no or all points intersect) // s1: points of the first line // s2: points of the second line // out: if there's an intersection, the point is returned here //---------------------------------------------------------------------------------------- static Int32 intersect_lines(MPOINT* s1, MPOINT* s2, MPOINT* out) { #define SAME_SIGNS(a, b) (a < 0 ? (b < 0 ? 1 : 0) : (b < 0 ? 0 : 1)) #define maxmin(x1, x2, min) (x1 >= x2 ? (min = x2, x1) : (min = x1, x2)) Float64 a, b, c, d, tdet, sdet, det; Float64 max1, max2, min1, min2; MPOINT p1, p2, q1, q2; Float64 s; p1 = s1[0]; p2 = s1[1]; q1 = s2[0]; q2 = s2[1]; // First make the bounding box test. max1 = maxmin(p1.x, p2.x, min1); max2 = maxmin(q1.x, q2.x, min2); if ((max1 < min2) || (min1 > max2)) return 0; // no intersection max1 = maxmin(p1.y, p2.y, min1); max2 = maxmin(q1.y, q2.y, min2); if ((max1 < min2) || (min1 > max2)) return 0; // no intersection // See if the endpoints of the second segment lie on the opposite sides of the first. If not, return 0. a = ((q1.x - p1.x) * (p2.y - p1.y)) - ((q1.y - p1.y) * (p2.x - p1.x)); b = ((q2.x - p1.x) * (p2.y - p1.y)) - ((q2.y - p1.y) * (p2.x - p1.x)); if ((a != 0) && (b != 0) && SAME_SIGNS(a, b)) return 0; // See if the endpoints of the first segment lie on the opposite sides of the second. If not, return 0. c = ((p1.x - q1.x) * (q2.y - q1.y)) - ((p1.y - q1.y) * (q2.x - q1.x)); d = ((p2.x - q1.x) * (q2.y - q1.y)) - ((p2.y - q1.y) * (q2.x - q1.x)); if ((c != 0) && (d != 0) && SAME_SIGNS(c, d)) return 0; // At this point each segment meets the line of the other. det = a - b; if (det == 0) // are the lines colinear? return 2; // The segments intersect since each segment crosses the other's line; // however, since the lines are not parallel, either a or b is not // zero. Similarly either c or d is not zero. tdet = -c; sdet = a; if (det < 0) // The denominator of the parameter must be positive. { det = -det; sdet = -sdet; tdet = -tdet; } s = sdet / det; out->x = (q2.x - q1.x) * s + q1.x; out->y = (q2.y - q1.y) * s + q1.y; return 1; #undef SAME_SIGN #undef maxmin } //---------------------------------------------------------------------------------------- // Check wheter a point is inside a convex polygon (GGIV 1.4 Crossings) // Shoot a test ray along +X axis. The strategy, from MacMartin, is to // compare vertex Y values to the testing point's Y and quickly discard // edges which are entirely to one side of the test ray. // Function result: true: inside false: outside // pts: points of the polygon // no_pts: number of points in the polygon (polygon is not closed) // check_point: the test point //---------------------------------------------------------------------------------------- static Bool test_inside(MPOINT* pts, Int32 no_pts, MPOINT* check_point) { Bool inside_flag; Bool line_flag; Int32 i, yflag0, yflag1, xflag0; Float64 ty; Float64 tx; MPOINT* vtx0; MPOINT* vtx1; tx = check_point->x; ty = check_point->y; vtx0 = pts + no_pts - 1; yflag0 = (vtx0->y >= ty); // get test bit for above/below X axis vtx1 = pts; inside_flag = false; line_flag = false; for (i = no_pts + 1; --i; ) { yflag1 = (vtx1->y >= ty); // check if endpoints straddle (are on opposite sides) of X axis // (i.e. the Y's differ); if so, +X ray could intersect this edge. if (yflag0 != yflag1) { xflag0 = (vtx0->x >= tx); // check if endpoints are on same side of the Y axis (i.e. X's // are the same); if so, it's easy to test if edge hits or misses. if (xflag0 == (vtx1->x >= tx)) { if (xflag0) // if edge's X values both right of the point, must hit inside_flag = !inside_flag; } else { // compute intersection of pts segment with +X ray, note if >= point's X; if so, the ray hits it. if ((vtx1->x - (vtx1->y - ty) * (vtx0->x - vtx1->x) / (vtx0->y - vtx1->y)) >= tx) { inside_flag = !inside_flag; } } if (line_flag) // if this is second edge hit, that's it (convex polygon) break; line_flag = true; // note that one edge has been hit by the ray's line } yflag0 = yflag1; // move to next pair of vertices, retaining info as possible vtx0 = vtx1; vtx1++; } return inside_flag; } //---------------------------------------------------------------------------------------- // Calculate the area of a polygon (GGII 1.1). Point order should be counterclockwise. // Function result: Area // me: polygon //---------------------------------------------------------------------------------------- static Float64 get_simple_polygon_area(MBOUNDS* me) { Int32 i; Float64 area; area = 0; for (i = 1; i < me->no_pts; i++) { area += (me->pts[i - 1].x) * (me->pts[i].y); area -= (me->pts[i].x) * (me->pts[i - 1].y); } area /= 2; if (area < 0) // wrong point order? area = -area; return area; }