| 1 | // This file is part of SmallBASIC |
| 2 | // |
| 3 | // SmallBASIC LIBRARY - extra geometry algorithms |
| 4 | // |
| 5 | // This program is distributed under the terms of the GPL v2.0 or later |
| 6 | // Download the GNU Public License (GPL) from www.gnu.org |
| 7 | // |
| 8 | // Copyright(C) 2000 Nicholas Christopoulos |
| 9 | |
| 10 | #include "common/geom.h" |
| 11 | #include "common/kw.h" |
| 12 | |
| 13 | /** |
| 14 | * length of line segment A-B |
| 15 | */ |
| 16 | double geo_seglen(double Ax, double Ay, double Bx, double By) { |
| 17 | double dx = Bx - Ax; |
| 18 | double dy = By - Ay; |
| 19 | |
| 20 | return sqrt(dx * dx + dy * dy); |
| 21 | } |
| 22 | |
| 23 | /** |
| 24 | * distance of point C from line (A,B) |
| 25 | */ |
| 26 | double geo_distfromline(double Ax, double Ay, double Bx, double By, double Cx, double Cy) { |
| 27 | double L, s; |
| 28 | // double r; |
| 29 | // double Px, Py; // projection of C on AB |
| 30 | |
| 31 | L = geo_seglen(Ax, Ay, Bx, By); |
| 32 | |
| 33 | if (L == 0.0) // A,B are the same point, TODO: tolerance |
| 34 | return geo_seglen(Ax, Ay, Cx, Cy); |
| 35 | |
| 36 | // r = ((Ay-Cy) * (Ay-By) - (Ax-Cx) * (Bx-Ax)) / (L * L); |
| 37 | // Px = Ax + r * (Bx - Ax); |
| 38 | // Py = Ay + r * (By - Ay); |
| 39 | |
| 40 | s = ((Ay - Cy) * (Bx - Ax) - (Ax - Cx) * (By - Ay)) / (L * L); |
| 41 | return s * L; |
| 42 | } |
| 43 | |
| 44 | /** |
| 45 | * distance of point C from line segment (A->B) |
| 46 | */ |
| 47 | double geo_distfromseg(double Ax, double Ay, double Bx, double By, double Cx, double Cy) { |
| 48 | // double Px, Py; // projection of C on AB |
| 49 | double L, r, s; |
| 50 | double ca, cb; |
| 51 | |
| 52 | L = geo_seglen(Ax, Ay, Bx, By); |
| 53 | |
| 54 | if (L == 0.0) // A,B are the same point, TODO: tolerance |
| 55 | return geo_seglen(Ax, Ay, Cx, Cy); |
| 56 | |
| 57 | r = ((Ay - Cy) * (Ay - By) - (Ax - Cx) * (Bx - Ax)) / (L * L); |
| 58 | |
| 59 | if (r >= 0.0 && r <= 1.0) { // TODO: tolerance |
| 60 | // Px = Ax + r * (Bx - Ax); |
| 61 | // Py = Ay + r * (By - Ay); |
| 62 | |
| 63 | s = ((Ay - Cy) * (Bx - Ax) - (Ax - Cx) * (By - Ay)) / (L * L); |
| 64 | return s * L; |
| 65 | } |
| 66 | |
| 67 | // else the P is out of A-B |
| 68 | ca = geo_seglen(Ax, Ay, Cx, Cy); |
| 69 | cb = geo_seglen(Bx, By, Cx, Cy); |
| 70 | return (ca < cb) ? ca : cb; |
| 71 | } |
| 72 | |
| 73 | /* |
| 74 | * COS/SIN of two line segments |
| 75 | */ |
| 76 | double geo_segangle(int type, double Adx, double Ady, double Bdx, double Bdy) { |
| 77 | double la, lb; |
| 78 | double UAdx, UAdy, UBdx, UBdy; |
| 79 | |
| 80 | la = sqrt(Adx * Adx + Ady * Ady); |
| 81 | lb = sqrt(Bdx * Bdx + Bdy * Bdy); |
| 82 | |
| 83 | if (la != 0 && lb != 0) { |
| 84 | UAdx = Adx / la; |
| 85 | UAdy = Ady / la; |
| 86 | UBdx = Bdx / lb; |
| 87 | UBdy = Bdy / lb; |
| 88 | if (type == kwSEGCOS) |
| 89 | return UAdx * UBdx + UAdy * UBdy; |
| 90 | else |
| 91 | return UAdy * UBdx + UAdx * UBdy; |
| 92 | } |
| 93 | |
| 94 | return 0; // ��� ��� �� ���������� ���� ����� 0. |
| 95 | } |
| 96 | |
| 97 | /********************************************************************* |
| 98 | ANSI C code from the article "Centroid of a Polygon" |
| 99 | by Gerard Bashein and Paul R. Detmer |
| 100 | |
| 101 | polyCentroid: Calculates the centroid (xCentroid, yCentroid) and area |
| 102 | of a polygon, given its vertices (x[0], y[0]) ... (x[n-1], y[n-1]). It |
| 103 | is assumed that the contour is closed, i.e., that the vertex following |
| 104 | (x[n-1], y[n-1]) is (x[0], y[0]). The algebraic sign of the area is |
| 105 | positive for counterclockwise ordering of vertices in x-y plane; |
| 106 | otherwise negative. |
| 107 | |
| 108 | Returned values: 0 for normal execution; 1 if the polygon is |
| 109 | degenerate (number of vertices < 3); and 2 if area = 0 (and the |
| 110 | centroid is undefined). |
| 111 | **********************************************************************/ |
| 112 | int geo_polycentroid(pt_t * poly, int n, var_num_t *xCentroid, var_num_t *yCentroid, var_num_t *area) { |
| 113 | int i, j; |
| 114 | var_num_t ai, atmp = 0, xtmp = 0, ytmp = 0; |
| 115 | |
| 116 | if (n < 3) { |
| 117 | return 1; |
| 118 | } |
| 119 | |
| 120 | for (i = n - 1, j = 0; j < n; i = j, j++) { |
| 121 | ai = poly[i].x * poly[j].y - poly[j].x * poly[i].y; |
| 122 | atmp += ai; |
| 123 | xtmp += (poly[j].x + poly[i].x) * ai; |
| 124 | ytmp += (poly[j].y + poly[i].y) * ai; |
| 125 | } |
| 126 | |
| 127 | *area = atmp / 2; |
| 128 | if (atmp != 0) { |
| 129 | *xCentroid = xtmp / (3 * atmp); |
| 130 | *yCentroid = ytmp / (3 * atmp); |
| 131 | return 0; |
| 132 | } |
| 133 | |
| 134 | return 2; |
| 135 | } |
| 136 | |