27 #define LENGTH(DX, DY) (sqrt((DX * DX) + (DY * DY)))
32 #define NON_LOOPED_LINE 0
35 static void norm_vector(
double x1,
double y1,
double x2,
double y2,
double *
x,
42 if ((dx == 0) && (dy == 0)) {
56 static void rotate_vector(
double x,
double y,
double cosa,
double sina,
57 double *nx,
double *ny)
59 *nx =
x * cosa - y * sina;
60 *ny =
x * sina + y * cosa;
69 static void elliptic_transform(
double x,
double y,
double da,
double db,
70 double dalpha,
double *nx,
double *ny)
72 double cosa = cos(dalpha);
73 double sina = sin(dalpha);
85 va = (
x * cosa + y * sina) * da;
86 vb = (
x * (-sina) + y * cosa) * db;
87 *nx = va * cosa + vb * (-sina);
88 *ny = va * sina + vb * cosa;
98 static void elliptic_tangent(
double x,
double y,
double da,
double db,
99 double dalpha,
double *px,
double *py)
101 double cosa = cos(dalpha);
102 double sina = sin(dalpha);
106 rotate_vector(
x, y, cosa, -sina, &
x, &y);
111 len = da * db / sqrt(da * da * v * v + db * db * u * u);
114 rotate_vector(u, v, cosa, sina, px, py);
123 static void line_coefficients(
double x1,
double y1,
double x2,
double y2,
124 double *a,
double *
b,
double *c)
128 *c = x2 * y1 - x1 * y2;
138 static int line_intersection(
double a1,
double b1,
double c1,
double a2,
139 double b2,
double c2,
double *
x,
double *y)
143 if (fabs(a2 * b1 - a1 * b2) == 0) {
144 if (fabs(a2 * c1 - a1 * c2) == 0)
150 d = a1 * b2 - a2 * b1;
151 *
x = (b1 * c2 - b2 * c1) / d;
152 *y = (c1 * a2 - c2 * a1) / d;
157 static double angular_tolerance(
double tol,
double da,
double db)
159 double a =
MAX(da, db);
164 return 2 * acos(1 - tol / a);
180 static void parallel_line(
struct line_pnts *Points,
double da,
double db,
181 double dalpha,
int side,
int round,
int caps,
182 int looped,
double tol,
struct line_pnts *nPoints)
186 double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry;
187 double vx1, vy1, wx1, wy1;
188 double a0, b0, c0, a1, b1, c1;
189 double phi1, phi2, delta_phi;
190 double nsegments, angular_tol, angular_step;
191 int inner_corner, turns360;
209 if ((np == 0) || (np == 1))
212 if ((da == 0) || (db == 0)) {
217 side = (side >= 0) ? (1) : (-1);
219 angular_tol = angular_tolerance(tol, da, db);
221 for (i = 0; i < np - 1; i++) {
229 norm_vector(
x[i], y[i],
x[i + 1], y[i + 1], &tx, &ty);
230 if ((tx == 0) && (ty == 0))
233 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
241 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
249 delta_phi = atan2(ty, tx) - atan2(y[i] - y[i - 1],
x[i] -
x[i - 1]);
252 else if (delta_phi <= -
PI)
255 turns360 = (fabs(fabs(delta_phi) -
PI) < 1e-15);
256 inner_corner = (side * delta_phi <= 0) && (!turns360);
258 if ((turns360) && (!(caps && round))) {
260 norm_vector(0, 0, vx, vy, &tx, &ty);
261 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx,
272 else if ((!round) || inner_corner) {
273 res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry);
295 elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1);
296 elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1);
298 phi1 = atan2(wy1, wx1);
299 phi2 = atan2(vy1, vx1);
300 delta_phi = side * (phi2 - phi1);
306 nsegments = (int)(delta_phi / angular_tol) + 1;
307 angular_step = side * (delta_phi / nsegments);
309 for (j = 0; j <= nsegments; j++) {
310 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
313 phi1 += angular_step;
317 if ((!looped) && (i == np - 2)) {
334 static void convolution_line(
struct line_pnts *Points,
double da,
double db,
335 double dalpha,
int side,
int round,
int caps,
340 double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry;
341 double vx1, vy1, wx1, wy1;
342 double a0, b0, c0, a1, b1, c1;
343 double phi1, phi2, delta_phi;
344 double nsegments, angular_tol, angular_step;
345 double angle0, angle1;
346 int inner_corner, turns360;
348 G_debug(3,
"convolution_line() side = %d", side);
353 if ((np == 0) || (np == 1))
355 if ((
x[0] !=
x[np - 1]) || (y[0] != y[np - 1])) {
362 if ((da == 0) || (db == 0)) {
367 side = (side >= 0) ? (1) : (-1);
369 angular_tol = angular_tolerance(tol, da, db);
372 norm_vector(
x[i], y[i],
x[i + 1], y[i + 1], &tx, &ty);
373 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
374 angle1 = atan2(ty, tx);
380 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
382 for (i = 0; i <= np - 2; i++) {
383 G_debug(4,
"point %d, segment %d-%d", i, i, i + 1);
394 norm_vector(
x[i], y[i],
x[i + 1], y[i + 1], &tx, &ty);
395 if ((tx == 0) && (ty == 0))
397 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
398 angle1 = atan2(ty, tx);
404 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
406 delta_phi = angle1 - angle0;
409 else if (delta_phi <= -
PI)
412 turns360 = (fabs(fabs(delta_phi) -
PI) < 1e-15);
413 inner_corner = (side * delta_phi <= 0) && (!turns360);
416 if (turns360 && caps && (!round)) {
417 norm_vector(0, 0, vx, vy, &tx, &ty);
418 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx, &ty);
420 G_debug(4,
" append point (c) x=%.16f y=%.16f",
x[i] + wx + tx,
424 G_debug(4,
" append point (c) x=%.16f y=%.16f", nx + tx, ny + ty);
427 if ((!turns360) && (!round) && (!inner_corner)) {
428 res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry);
431 G_debug(4,
" append point (o) x=%.16f y=%.16f", rx, ry);
438 _(
"Unexpected result of line_intersection() res = %d"),
442 if (round && (!inner_corner) && (!turns360 || caps)) {
446 elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1);
447 elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1);
449 phi1 = atan2(wy1, wx1);
450 phi2 = atan2(vy1, vx1);
451 delta_phi = side * (phi2 - phi1);
457 nsegments = (int)(delta_phi / angular_tol) + 1;
458 angular_step = side * (delta_phi / nsegments);
460 phi1 += angular_step;
461 for (j = 1; j <= nsegments - 1; j++) {
462 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
465 G_debug(4,
" append point (r) x=%.16f y=%.16f",
x[i] + tx,
467 phi1 += angular_step;
472 G_debug(4,
" append point (s) x=%.16f y=%.16f", nx, ny);
474 G_debug(4,
" append point (s) x=%.16f y=%.16f", mx, my);
489 int side,
int winding,
int stop_at_line_end,
504 double opt_angle, tangle;
505 int opt_j, opt_side, opt_flag;
507 G_debug(3,
"extract_contour(): v1=%d, v2=%d, side=%d, stop_at_line_end=%d",
508 first->
v1, first->
v2, side, stop_at_line_end);
523 vert0 = &(pg->
v[v0]);
525 eangle = atan2(vert->
y - vert0->
y, vert->
x - vert0->
x);
529 G_debug(4,
"ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d", v0, v,
530 eside, edge->
v1, edge->
v2);
531 G_debug(4,
"ec: append point x=%.18f y=%.18f", vert0->
x, vert0->
y);
544 for (j = 0; j < vert->
ecount; j++) {
546 if (vert->
edges[j] != edge) {
547 tangle = vert->
angles[j] - eangle;
550 else if (tangle >
PI)
554 if (opt_flag || (tangle < opt_angle)) {
556 opt_side = (vert->
edges[j]->
v1 == v) ? (1) : (-1);
570 if (stop_at_line_end) {
571 G_debug(3,
" end has been reached, will stop here");
578 G_debug(3,
" end has been reached, turning around");
583 if ((vert->
edges[opt_j] == first) && (opt_side == side))
587 G_warning(
_(
"Next edge was visited (right) but it is not the "
588 "first one !!! breaking loop"));
590 "ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d",
591 v, (edge->
v1 == v) ? (edge->
v2) : (edge->
v1), opt_side,
598 G_warning(
_(
"Next edge was visited (left) but it is not the "
599 "first one !!! breaking loop"));
601 "ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d",
602 v, (edge->
v1 == v) ? (edge->
v2) : (edge->
v1), opt_side,
608 edge = vert->
edges[opt_j];
611 v = (edge->
v1 == v) ? (edge->
v2) : (edge->
v1);
614 eangle = vert0->
angles[opt_j];
618 G_debug(4,
"ec: append point x=%.18f y=%.18f", vert->
x, vert->
y);
633 static void extract_outer_contour(
struct planar_graph *pg,
int side,
641 double min_x, min_angle;
643 G_debug(3,
"extract_outer_contour()");
652 for (i = 0; i < pg->
vcount; i++) {
653 if (flag || (pg->
v[i].
x < min_x)) {
662 for (i = 0; i < vert->
ecount; i++) {
663 if (flag || (vert->
angles[i] < min_angle)) {
664 edge = vert->
edges[i];
665 min_angle = vert->
angles[i];
685 static int extract_inner_contour(
struct planar_graph *pg,
int *winding,
691 G_debug(3,
"extract_inner_contour()");
693 for (i = 0; i < pg->
ecount; i++) {
698 extract_contour(pg, &(pg->
e[i]),
RIGHT_SIDE, w, 0, nPoints);
706 extract_contour(pg, &(pg->
e[i]),
LEFT_SIDE, w, 0, nPoints);
721 static int point_in_buf(
struct line_pnts *Points,
double px,
double py,
722 double da,
double db,
double dalpha)
726 double delta, delta_k, k;
727 double vx, vy, wx, wy, mx, my, nx, ny;
728 double len, tx, ty, d, da2;
736 for (i = 0; i < np - 1; i++) {
739 wx = Points->
x[i + 1];
740 wy = Points->
y[i + 1];
746 elliptic_tangent(mx / len, my / len, da, db, dalpha, &cx, &cy);
748 delta = mx * cy - my * cx;
749 delta_k = (px - vx) * cy - (py - vy) * cx;
767 elliptic_transform(px - nx, py - ny, 1 / da, 1 / db, dalpha, &tx,
782 d =
dig_distance2_point_to_line(px, py, 0, vx, vy, 0, wx, wy, 0, 0,
796 static int get_polygon_orientation(
const double *
x,
const double *y,
int n)
798 double x1, y1, x2, y2;
812 area += (y2 + y1) * (x2 - x1);
819 static void add_line_to_array(
struct line_pnts *Points,
821 int *allocated,
int more)
823 if (*allocated == *
count) {
828 (*arrPoints)[*
count] = Points;
834 static void destroy_lines_array(
struct line_pnts **arr,
int count)
838 for (i = 0; i <
count; i++)
846 static void buffer_lines(
struct line_pnts *area_outer,
847 struct line_pnts **area_isles,
int isles_count,
848 int side,
double da,
double db,
double dalpha,
849 int round,
int caps,
double tol,
851 struct line_pnts ***iPoints,
int *inner_count)
865 auto_side = (side == 0);
873 G_debug(3,
" processing outer contour");
876 side = get_polygon_orientation(area_outer->
x, area_outer->
y,
880 convolution_line(area_outer, da, db, dalpha, side, round, caps, tol,
883 extract_outer_contour(pg2, 0, *oPoints);
884 res = extract_inner_contour(pg2, &winding, cPoints);
891 if (area_size == 0) {
895 if (cPoints->
x[0] != cPoints->
x[cPoints->
n_points - 1] ||
896 cPoints->
y[0] != cPoints->
y[cPoints->
n_points - 1]) {
905 if (!point_in_buf(area_outer, px, py, da, db, dalpha)) {
906 add_line_to_array(cPoints, &arrPoints, &
count,
912 G_warning(
_(
"Vect_get_point_in_poly() failed"));
916 res = extract_inner_contour(pg2, &winding, cPoints);
921 G_debug(3,
" processing inner contours");
922 for (i = 0; i < isles_count; i++) {
924 side = get_polygon_orientation(area_isles[i]->
x, area_isles[i]->
y,
928 convolution_line(area_isles[i], da, db, dalpha, side, round, caps, tol,
931 extract_outer_contour(pg2, 0, cPoints);
932 res = extract_inner_contour(pg2, &winding, cPoints);
939 if (area_size == 0) {
943 if (cPoints->
x[0] != cPoints->
x[cPoints->
n_points - 1] ||
944 cPoints->
y[0] != cPoints->
y[cPoints->
n_points - 1]) {
957 if (!point_in_buf(area_isles[i], px, py, da, db,
959 add_line_to_array(cPoints, &arrPoints, &
count,
965 G_warning(
_(
"Vect_get_point_in_poly() failed"));
969 res = extract_inner_contour(pg2, &winding, cPoints);
975 *inner_count =
count;
976 *iPoints = arrPoints;
981 G_debug(3,
"buffer_lines() ... done");
1010 double dalpha,
int round,
int caps,
double tol,
1017 int isles_count = 0;
1020 int isles_allocated = 0;
1022 G_debug(2,
"Vect_line_buffer()");
1039 extract_outer_contour(pg, 0, outer);
1042 res = extract_inner_contour(pg, &winding, tPoints);
1044 add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated,
1047 res = extract_inner_contour(pg, &winding, tPoints);
1050 buffer_lines(outer, isles, isles_count,
RIGHT_SIDE, da, db, dalpha, round,
1051 caps, tol, oPoints, iPoints, inner_count);
1055 destroy_lines_array(isles, isles_count);
1075 double dalpha,
int round,
int caps,
double tol,
1081 int isles_count = 0, n_isles;
1084 int isles_allocated = 0;
1086 G_debug(2,
"Vect_area_buffer()");
1091 isles_allocated = n_isles;
1101 for (i = 0; i < n_isles; i++) {
1112 add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated,
1117 buffer_lines(outer, isles, isles_count, 0, da, db, dalpha, round, caps, tol,
1118 oPoints, iPoints, inner_count);
1122 destroy_lines_array(isles, isles_count);
1142 double dalpha,
int round,
double tol,
1146 double angular_tol, angular_step, phi1;
1156 angular_tol = angular_tolerance(tol, da, db);
1158 nsegments = (int)(2 *
PI / angular_tol) + 1;
1159 angular_step = 2 *
PI / nsegments;
1162 for (j = 0; j < nsegments; j++) {
1163 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx, &ty);
1165 phi1 += angular_step;
1192 double dalpha,
int side,
int round,
double tol,
1196 "Vect_line_parallel(): npoints = %d, da = %f, "
1197 "db = %f, dalpha = %f, side = %d, round_corners = %d, tol = %f",
1198 InPoints->
n_points, da, db, dalpha, side, round, tol);
1200 parallel_line(InPoints, da, db, dalpha, side, round, 1,
NON_LOOPED_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)
void Vect_line_buffer2(const 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_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_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).
void G_free(void *)
Free allocated memory.
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
int Vect_get_isle_points(struct Map_info *, int, struct line_pnts *)
Returns polygon array of points for given isle.
int Vect_get_area_points(struct Map_info *, int, struct line_pnts *)
Returns polygon array of points (outer ring) of given area.
int Vect_copy_xyz_to_pnts(struct line_pnts *, const double *, const double *, const double *, int)
Copy points from array to line_pnts structure.
int Vect_get_point_in_poly(const struct line_pnts *, double *, double *)
Get point inside polygon.
int Vect_get_area_isle(struct Map_info *, int, int)
Returns isle id for area.
int Vect_get_area_num_isles(struct Map_info *, int)
Returns number of isles for given area.
int Vect_point_in_poly(double, double, const struct line_pnts *)
Determines if a point (X,Y) is inside a polygon.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
int Vect_line_delete_point(struct line_pnts *, int)
Delete point at given index and move all points above down.
void Vect_reset_line(struct line_pnts *)
Reset line.
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
struct planar_graph * pg_create(const struct line_pnts *Points)
void pg_destroy_struct(struct planar_graph *pg)
double dig_distance2_point_to_line(double, double, double, double, double, double, double, double, double, int, double *, double *, double *, double *, int *)
int dig_find_area_poly(struct line_pnts *, double *)
Feature geometry info - coordinates.
double * y
Array of Y coordinates.
double * x
Array of X coordinates.
int n_points
Number of points.
double * z
Array of Z coordinates.