23 #include <grass/Vect.h>
24 #include <grass/gis.h>
25 #include <grass/glocale.h>
29 #define LENGTH(DX, DY) (sqrt((DX*DX)+(DY*DY)))
31 #define MIN(X,Y) ((X<Y)?X:Y)
34 #define MAX(X,Y) ((X>Y)?X:Y)
40 #define NON_LOOPED_LINE 0
43 static void norm_vector(
double x1,
double y1,
double x2,
double y2,
double *x,
50 if ((dx == 0) && (dy == 0)) {
64 static void rotate_vector(
double x,
double y,
double cosa,
double sina,
65 double *nx,
double *ny)
67 *nx = x * cosa - y * sina;
68 *ny = x * sina + y * cosa;
77 static void elliptic_transform(
double x,
double y,
double da,
double db,
78 double dalpha,
double *nx,
double *ny)
80 double cosa = cos(dalpha);
81 double sina = sin(dalpha);
93 va = (x * cosa + y * sina) * da;
94 vb = (x * (-sina) + y * cosa) * db;
95 *nx = va * cosa + vb * (-sina);
96 *ny = va * sina + vb * cosa;
107 static void elliptic_tangent(
double x,
double y,
double da,
double db,
108 double dalpha,
double *px,
double *py)
110 double cosa = cos(dalpha);
111 double sina = sin(dalpha);
115 rotate_vector(x, y, cosa, -sina, &x, &y);
120 len = da * db / sqrt(da * da * v * v + db * db * u * u);
123 rotate_vector(u, v, cosa, sina, px, py);
132 static void line_coefficients(
double x1,
double y1,
double x2,
double y2,
133 double *a,
double *
b,
double *c)
137 *c = x2 * y1 - x1 * y2;
147 static int line_intersection(
double a1,
double b1,
double c1,
double a2,
148 double b2,
double c2,
double *x,
double *
y)
152 if (fabs(a2 * b1 - a1 * b2) == 0) {
153 if (fabs(a2 * c1 - a1 * c2) == 0)
159 d = a1 * b2 - a2 * b1;
160 *x = (b1 * c2 - b2 * c1) / d;
161 *y = (c1 * a2 - c2 * a1) / d;
166 static double angular_tolerance(
double tol,
double da,
double db)
168 double a =
MAX(da, db);
173 return 2 * acos(1 - tol / a);
188 static void parallel_line(
struct line_pnts *Points,
double da,
double db,
189 double dalpha,
int side,
int round,
int caps,
int looped,
190 double tol,
struct line_pnts *nPoints)
194 double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry;
195 double vx1, vy1, wx1, wy1;
196 double a0, b0, c0, a1, b1, c1;
197 double phi1, phi2, delta_phi;
198 double nsegments, angular_tol, angular_step;
199 int inner_corner, turns360;
213 np = Points->n_points;
217 if ((np == 0) || (np == 1))
220 if ((da == 0) || (db == 0)) {
225 side = (side >= 0) ? (1) : (-1);
227 angular_tol = angular_tolerance(tol, da, db);
229 for (i = 0; i < np - 1; i++) {
238 norm_vector(x[i], y[i], x[i + 1], y[i + 1], &tx, &ty);
239 if ((tx == 0) && (ty == 0))
242 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
250 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
258 delta_phi = atan2(ty, tx) - atan2(y[i] - y[i - 1], x[i] - x[i - 1]);
261 else if (delta_phi <= -
PI)
264 turns360 = (fabs(fabs(delta_phi) -
PI) < 1e-15);
265 inner_corner = (side * delta_phi <= 0) && (!turns360);
267 if ((turns360) && (!(caps &&
round))) {
269 norm_vector(0, 0, vx, vy, &tx, &ty);
270 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx,
280 else if ((!round) || inner_corner) {
281 res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry);
302 elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1);
303 elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1);
305 phi1 = atan2(wy1, wx1);
306 phi2 = atan2(vy1, vx1);
307 delta_phi = side * (phi2 - phi1);
313 nsegments = (
int)(delta_phi / angular_tol) + 1;
314 angular_step = side * (delta_phi / nsegments);
316 for (j = 0; j <= nsegments; j++) {
317 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
320 phi1 += angular_step;
324 if ((!looped) && (i == np - 2)) {
342 static void convolution_line(
struct line_pnts *Points,
double da,
double db,
343 double dalpha,
int side,
int round,
int caps,
344 double tol,
struct line_pnts *nPoints)
348 double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry;
349 double vx1, vy1, wx1, wy1;
350 double a0, b0, c0, a1, b1, c1;
351 double phi1, phi2, delta_phi;
352 double nsegments, angular_tol, angular_step;
353 double angle0, angle1;
354 int inner_corner, turns360;
356 G_debug(3,
"convolution_line() side = %d", side);
358 np = Points->n_points;
361 if ((np == 0) || (np == 1))
363 if ((x[0] != x[np - 1]) || (y[0] != y[np - 1])) {
370 if ((da == 0) || (db == 0)) {
375 side = (side >= 0) ? (1) : (-1);
377 angular_tol = angular_tolerance(tol, da, db);
380 norm_vector(x[i], y[i], x[i + 1], y[i + 1], &tx, &ty);
381 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
382 angle1 = atan2(ty, tx);
388 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
390 for (i = 0; i <= np - 2; i++) {
391 G_debug(4,
"point %d, segment %d-%d", i, i, i + 1);
402 norm_vector(x[i], y[i], x[i + 1], y[i + 1], &tx, &ty);
403 if ((tx == 0) && (ty == 0))
405 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
406 angle1 = atan2(ty, tx);
412 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
415 delta_phi = angle1 - angle0;
418 else if (delta_phi <= -
PI)
421 turns360 = (fabs(fabs(delta_phi) -
PI) < 1e-15);
422 inner_corner = (side * delta_phi <= 0) && (!turns360);
426 if (turns360 && caps && (!round)) {
427 norm_vector(0, 0, vx, vy, &tx, &ty);
428 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx, &ty);
430 G_debug(4,
" append point (c) x=%.16f y=%.16f", x[i] + wx + tx,
433 G_debug(4,
" append point (c) x=%.16f y=%.16f", nx + tx, ny + ty);
436 if ((!turns360) && (!round) && (!inner_corner)) {
437 res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry);
440 G_debug(4,
" append point (o) x=%.16f y=%.16f", rx, ry);
447 (
"unexpected result of line_intersection() res = %d",
451 if (round && (!inner_corner) && (!turns360 || caps)) {
455 elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1);
456 elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1);
458 phi1 = atan2(wy1, wx1);
459 phi2 = atan2(vy1, vx1);
460 delta_phi = side * (phi2 - phi1);
466 nsegments = (
int)(delta_phi / angular_tol) + 1;
467 angular_step = side * (delta_phi / nsegments);
469 phi1 += angular_step;
470 for (j = 1; j <= nsegments - 1; j++) {
471 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
474 G_debug(4,
" append point (r) x=%.16f y=%.16f", x[i] + tx,
476 phi1 += angular_step;
481 G_debug(4,
" append point (s) x=%.16f y=%.16f", nx, ny);
483 G_debug(4,
" append point (s) x=%.16f y=%.16f", mx, my);
497 int side,
int winding,
int stop_at_line_end,
498 struct line_pnts *nPoints)
511 double opt_angle, tangle;
512 int opt_j, opt_side, opt_flag;
515 "extract_contour(): v1=%d, v2=%d, side=%d, stop_at_line_end=%d",
516 first->
v1, first->
v2, side, stop_at_line_end);
531 vert0 = &(pg->
v[v0]);
533 eangle = atan2(vert->
y - vert0->
y, vert->
x - vert0->
x);
536 if (nPoints->n_points > 0 && (nPoints->x[nPoints->n_points - 1] != vert0->
x ||
537 nPoints->y[nPoints->n_points - 1] != vert0->
y))
541 G_debug(4,
"ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d", v0,
542 v, eside, edge->
v1, edge->
v2);
543 G_debug(4,
"ec: append point x=%.18f y=%.18f", vert0->
x, vert0->
y);
556 for (j = 0; j < vert->
ecount; j++) {
558 if (vert->
edges[j] != edge) {
559 tangle = vert->
angles[j] - eangle;
562 else if (tangle >
PI)
566 if (opt_flag || (tangle < opt_angle)) {
568 opt_side = (vert->
edges[j]->
v1 == v) ? (1) : (-1);
582 if (stop_at_line_end) {
583 G_debug(3,
" end has been reached, will stop here");
589 G_debug(3,
" end has been reached, turning around");
594 if ((vert->
edges[opt_j] == first) && (opt_side == side))
598 G_warning(_(
"Next edge was visited but it is not the first one !!! breaking loop"));
600 "ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d",
601 v, (edge->
v1 == v) ? (edge->
v2) : (edge->
v1),
602 opt_side, vert->
edges[opt_j]->
v1,
609 G_warning(_(
"Next edge was visited but it is not the first one !!! breaking loop"));
611 "ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d",
612 v, (edge->
v1 == v) ? (edge->
v2) : (edge->
v1),
613 opt_side, vert->
edges[opt_j]->
v1,
619 edge = vert->
edges[opt_j];
622 v = (edge->
v1 == v) ? (edge->
v2) : (edge->
v1);
625 eangle = vert0->
angles[opt_j];
629 G_debug(4,
"ec: append point x=%.18f y=%.18f", vert->
x, vert->
y);
644 static void extract_outer_contour(
struct planar_graph *pg,
int side,
645 struct line_pnts *nPoints)
652 double min_x, min_angle;
654 G_debug(3,
"extract_outer_contour()");
663 for (i = 0; i < pg->
vcount; i++) {
664 if (flag || (pg->
v[i].
x < min_x)) {
673 for (i = 0; i < vert->
ecount; i++) {
674 if (flag || (vert->
angles[i] < min_angle)) {
675 edge = vert->
edges[i];
676 min_angle = vert->
angles[i];
695 static int extract_inner_contour(
struct planar_graph *pg,
int *winding,
696 struct line_pnts *nPoints)
701 G_debug(3,
"extract_inner_contour()");
703 for (i = 0; i < pg->
ecount; i++) {
708 extract_contour(pg, &(pg->
e[i]),
RIGHT_SIDE, w, 0, nPoints);
716 extract_contour(pg, &(pg->
e[i]),
LEFT_SIDE, w, 0, nPoints);
731 static int point_in_buf(
struct line_pnts *Points,
double px,
double py,
double da,
732 double db,
double dalpha)
736 double delta, delta_k, k;
737 double vx, vy, wx, wy, mx, my, nx, ny;
738 double len, tx, ty, d, da2;
744 np = Points->n_points;
746 for (i = 0; i < np - 1; i++) {
749 wx = Points->x[i + 1];
750 wy = Points->y[i + 1];
756 elliptic_tangent(mx / len, my / len, da, db, dalpha, &cx, &cy);
758 delta = mx * cy - my * cx;
759 delta_k = (px - vx) * cy - (py - vy) * cx;
776 elliptic_transform(px - nx, py - ny, 1 / da, 1 / db, dalpha, &tx,
804 static int get_polygon_orientation(
const double *x,
const double *y,
int n)
806 double x1, y1, x2, y2;
820 area += (y2 + y1) * (x2 - x1);
827 static void add_line_to_array(
struct line_pnts *Points,
828 struct line_pnts ***arrPoints,
int *
count,
829 int *allocated,
int more)
831 if (*allocated == *count) {
834 G_realloc(*arrPoints, (*allocated) *
sizeof(
struct line_pnts *));
836 (*arrPoints)[*
count] = Points;
842 static void destroy_lines_array(
struct line_pnts **arr,
int count)
846 for (i = 0; i <
count; i++)
854 static void buffer_lines(
struct line_pnts *area_outer,
struct line_pnts **area_isles,
855 int isles_count,
int side,
double da,
double db,
856 double dalpha,
int round,
int caps,
double tol,
857 struct line_pnts **oPoints,
struct line_pnts ***iPoints,
861 struct line_pnts *sPoints, *cPoints;
862 struct line_pnts **arrPoints;
872 auto_side = (side == 0);
880 G_debug(3,
" processing outer contour");
884 get_polygon_orientation(area_outer->x, area_outer->y,
885 area_outer->n_points -
887 convolution_line(area_outer, da, db, dalpha, side, round, caps, tol,
890 extract_outer_contour(pg2, 0, *oPoints);
891 res = extract_inner_contour(pg2, &winding, cPoints);
898 if (area_size == 0) {
902 if (cPoints->x[0] != cPoints->x[cPoints->n_points - 1] ||
903 cPoints->y[0] != cPoints->y[cPoints->n_points - 1]) {
911 if (!point_in_buf(area_outer, px, py, da, db, dalpha)) {
912 add_line_to_array(cPoints, &arrPoints, &count, &allocated,
918 G_warning(_(
"Vect_get_point_in_poly() failed"));
922 res = extract_inner_contour(pg2, &winding, cPoints);
927 G_debug(3,
" processing inner contours");
928 for (i = 0; i < isles_count; i++) {
931 get_polygon_orientation(area_isles[i]->x, area_isles[i]->y,
932 area_isles[i]->n_points -
934 convolution_line(area_isles[i], da, db, dalpha, side, round, caps,
937 extract_outer_contour(pg2, 0, cPoints);
938 res = extract_inner_contour(pg2, &winding, cPoints);
945 if (area_size == 0) {
949 if (cPoints->x[0] != cPoints->x[cPoints->n_points - 1] ||
950 cPoints->y[0] != cPoints->y[cPoints->n_points - 1]) {
960 (cPoints->x[0], cPoints->y[0], area_isles[i])) {
962 if (!point_in_buf(area_isles[i], px, py, da, db, dalpha)) {
963 add_line_to_array(cPoints, &arrPoints, &count,
969 G_warning(_(
"Vect_get_point_in_poly() failed"));
973 res = extract_inner_contour(pg2, &winding, cPoints);
978 arrPoints = G_realloc(arrPoints, count *
sizeof(
struct line_pnts *));
979 *inner_count =
count;
980 *iPoints = arrPoints;
985 G_debug(3,
"buffer_lines() ... done");
1008 double dalpha,
int round,
int caps,
double tol,
1009 struct line_pnts **oPoints,
1010 struct line_pnts ***iPoints,
int *inner_count)
1013 struct line_pnts *tPoints, *outer;
1014 struct line_pnts **isles;
1015 int isles_count = 0;
1018 int isles_allocated = 0;
1020 G_debug(2,
"Vect_line_buffer()");
1024 if (Points->n_points == 1)
1026 dalpha, round, tol, oPoints);
1035 extract_outer_contour(pg, 0, outer);
1038 res = extract_inner_contour(pg, &winding, tPoints);
1040 add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated,
1043 res = extract_inner_contour(pg, &winding, tPoints);
1046 buffer_lines(outer, isles, isles_count,
RIGHT_SIDE, da, db, dalpha, round,
1047 caps, tol, oPoints, iPoints, inner_count);
1051 destroy_lines_array(isles, isles_count);
1073 double dalpha,
int round,
int caps,
double tol,
1074 struct line_pnts **oPoints,
1075 struct line_pnts ***iPoints,
int *inner_count)
1077 struct line_pnts *tPoints, *outer;
1078 struct line_pnts **isles;
1079 int isles_count = 0, n_isles;
1082 int isles_allocated = 0;
1084 G_debug(2,
"Vect_area_buffer()");
1089 isles_allocated = n_isles;
1090 isles = G_malloc(isles_allocated *
sizeof(
struct line_pnts *));
1099 for (i = 0; i < n_isles; i++) {
1110 add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated,
1115 buffer_lines(outer, isles, isles_count, 0, da, db, dalpha, round, caps,
1116 tol, oPoints, iPoints, inner_count);
1120 destroy_lines_array(isles, isles_count);
1138 double dalpha,
int round,
double tol,
1139 struct line_pnts **oPoints)
1142 double angular_tol, angular_step, phi1;
1145 G_debug(2,
"Vect_point_buffer()");
1151 if (round || (!round)) {
1152 angular_tol = angular_tolerance(tol, da, db);
1154 nsegments = (
int)(2 *
PI / angular_tol) + 1;
1155 angular_step = 2 *
PI / nsegments;
1158 for (j = 0; j < nsegments; j++) {
1159 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
1162 phi1 += angular_step;
1191 double dalpha,
int side,
int round,
double tol,
1192 struct line_pnts *OutPoints)
1194 G_debug(2,
"Vect_line_parallel(): npoints = %d, da = %f, "
1195 "db = %f, dalpha = %f, side = %d, round_corners = %d, tol = %f",
1196 InPoints->n_points, da, db, dalpha, side, round, tol);
1198 parallel_line(InPoints, da, db, dalpha, side, round, 1,
NON_LOOPED_LINE,
struct planar_graph * pg_create(struct line_pnts *Points)
void G_free(void *buf)
Free allocated memory.
void pg_destroy_struct(struct planar_graph *pg)
int Vect_get_isle_points(struct Map_info *Map, int isle, struct line_pnts *BPoints)
Returns the polygon array of points in BPoints.
struct line_pnts * Vect_new_line_struct()
Creates and initializes a struct line_pnts.
int Vect_reset_line(struct line_pnts *Points)
Reset line.
int Vect_get_area_num_isles(struct Map_info *Map, int area)
Returns number of isles for area.
double dig_distance2_point_to_line(double x, double y, double z, double x1, double y1, double z1, double x2, double y2, double z2, int with_z, double *px, double *py, double *pz, double *pdist, int *status)
int Vect_get_area_isle(struct Map_info *Map, int area, int isle)
Returns isle for area.
int Vect_append_point(struct line_pnts *Points, double x, double y, double z)
Appends one point to the end of a line.
int Vect_get_area_points(struct Map_info *Map, int area, struct line_pnts *BPoints)
Returns the polygon array of points in BPoints.
int Vect_copy_xyz_to_pnts(struct line_pnts *Points, double *x, double *y, double *z, int n)
Copy points from array to line structure.
void Vect_area_buffer2(struct Map_info *Map, int area, double da, double db, double dalpha, int round, int caps, double tol, struct line_pnts **oPoints, struct line_pnts ***iPoints, int *inner_count)
Creates buffer around area.
void Vect_line_buffer2(struct line_pnts *Points, double da, double db, double dalpha, int round, int caps, double tol, struct line_pnts **oPoints, struct line_pnts ***iPoints, int *inner_count)
Creates buffer around line.
void Vect_line_parallel2(struct line_pnts *InPoints, double da, double db, double dalpha, int side, int round, double tol, struct line_pnts *OutPoints)
int Vect_point_in_poly(double X, double Y, struct line_pnts *Points)
Determines if a point (X,Y) is inside a polygon.
int Vect_line_prune(struct line_pnts *Points)
Remove duplicate points, i.e. zero length segments.
G_warning("category support for [%s] in mapset [%s] %s", name, mapset, type)
int G_debug(int level, const char *msg,...)
Print debugging message.
int dig_find_area_poly(struct line_pnts *Points, double *totalarea)
int Vect_line_delete_point(struct line_pnts *Points, int index)
Delete point at given index and move all points above down.
int G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
int Vect_destroy_line_struct(struct line_pnts *p)
Frees all memory associated with a struct line_pnts, including the struct itself. ...
void Vect_point_buffer2(double px, double py, double da, double db, double dalpha, int round, double tol, struct line_pnts **oPoints)
Creates buffer around the point (px, py).
int Vect_get_point_in_poly(struct line_pnts *Points, double *X, double *Y)
Get point inside polygon.