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;
214 if ((np == 0) || (np == 1))
217 if ((da == 0) || (db == 0)) {
222 side = (side >= 0) ? (1) : (-1);
224 angular_tol = angular_tolerance(tol, da, db);
226 for (i = 0; i < np - 1; i++) {
234 norm_vector(
x[i], y[i],
x[i + 1], y[i + 1], &tx, &ty);
235 if ((tx == 0) && (ty == 0))
238 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
246 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
254 delta_phi = atan2(ty, tx) - atan2(y[i] - y[i - 1],
x[i] -
x[i - 1]);
257 else if (delta_phi <= -
PI)
260 turns360 = (fabs(fabs(delta_phi) -
PI) < 1e-15);
261 inner_corner = (side * delta_phi <= 0) && (!turns360);
263 if ((turns360) && (!(caps && round))) {
265 norm_vector(0, 0, vx, vy, &tx, &ty);
266 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx,
277 else if ((!round) || inner_corner) {
278 res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry);
300 elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1);
301 elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1);
303 phi1 = atan2(wy1, wx1);
304 phi2 = atan2(vy1, vx1);
305 delta_phi = side * (phi2 - phi1);
311 nsegments = (int)(delta_phi / angular_tol) + 1;
312 angular_step = side * (delta_phi / nsegments);
314 for (j = 0; j <= nsegments; j++) {
315 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
318 phi1 += angular_step;
322 if ((!looped) && (i == np - 2)) {
339 static void convolution_line(
struct line_pnts *Points,
double da,
double db,
340 double dalpha,
int side,
int round,
int caps,
345 double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry;
346 double vx1, vy1, wx1, wy1;
347 double a0, b0, c0, a1, b1, c1;
348 double phi1, phi2, delta_phi;
349 double nsegments, angular_tol, angular_step;
350 double angle0, angle1;
351 int inner_corner, turns360;
353 G_debug(3,
"convolution_line() side = %d", side);
358 if ((np == 0) || (np == 1))
360 if ((
x[0] !=
x[np - 1]) || (y[0] != y[np - 1])) {
367 if ((da == 0) || (db == 0)) {
372 side = (side >= 0) ? (1) : (-1);
374 angular_tol = angular_tolerance(tol, da, db);
377 norm_vector(
x[i], y[i],
x[i + 1], y[i + 1], &tx, &ty);
378 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
379 angle1 = atan2(ty, tx);
385 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
387 for (i = 0; i <= np - 2; i++) {
388 G_debug(4,
"point %d, segment %d-%d", i, i, i + 1);
399 norm_vector(
x[i], y[i],
x[i + 1], y[i + 1], &tx, &ty);
400 if ((tx == 0) && (ty == 0))
402 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
403 angle1 = atan2(ty, tx);
409 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
411 delta_phi = angle1 - angle0;
414 else if (delta_phi <= -
PI)
417 turns360 = (fabs(fabs(delta_phi) -
PI) < 1e-15);
418 inner_corner = (side * delta_phi <= 0) && (!turns360);
421 if (turns360 && caps && (!round)) {
422 norm_vector(0, 0, vx, vy, &tx, &ty);
423 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx, &ty);
425 G_debug(4,
" append point (c) x=%.16f y=%.16f",
x[i] + wx + tx,
429 G_debug(4,
" append point (c) x=%.16f y=%.16f", nx + tx, ny + ty);
432 if ((!turns360) && (!round) && (!inner_corner)) {
433 res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry);
436 G_debug(4,
" append point (o) x=%.16f y=%.16f", rx, ry);
443 _(
"Unexpected result of line_intersection() res = %d"),
447 if (round && (!inner_corner) && (!turns360 || caps)) {
451 elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1);
452 elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1);
454 phi1 = atan2(wy1, wx1);
455 phi2 = atan2(vy1, vx1);
456 delta_phi = side * (phi2 - phi1);
462 nsegments = (int)(delta_phi / angular_tol) + 1;
463 angular_step = side * (delta_phi / nsegments);
465 phi1 += angular_step;
466 for (j = 1; j <= nsegments - 1; j++) {
467 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
470 G_debug(4,
" append point (r) x=%.16f y=%.16f",
x[i] + tx,
472 phi1 += angular_step;
477 G_debug(4,
" append point (s) x=%.16f y=%.16f", nx, ny);
479 G_debug(4,
" append point (s) x=%.16f y=%.16f", mx, my);
494 int side,
int winding,
int stop_at_line_end,
509 double opt_angle, tangle;
510 int opt_j, opt_side, opt_flag;
512 G_debug(3,
"extract_contour(): v1=%d, v2=%d, side=%d, stop_at_line_end=%d",
513 first->
v1, first->
v2, side, stop_at_line_end);
528 vert0 = &(pg->
v[v0]);
530 eangle = atan2(vert->
y - vert0->
y, vert->
x - vert0->
x);
534 G_debug(4,
"ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d", v0, v,
535 eside, edge->
v1, edge->
v2);
536 G_debug(4,
"ec: append point x=%.18f y=%.18f", vert0->
x, vert0->
y);
549 for (j = 0; j < vert->
ecount; j++) {
551 if (vert->
edges[j] != edge) {
552 tangle = vert->
angles[j] - eangle;
555 else if (tangle >
PI)
559 if (opt_flag || (tangle < opt_angle)) {
561 opt_side = (vert->
edges[j]->
v1 == v) ? (1) : (-1);
575 if (stop_at_line_end) {
576 G_debug(3,
" end has been reached, will stop here");
583 G_debug(3,
" end has been reached, turning around");
588 if ((vert->
edges[opt_j] == first) && (opt_side == side))
592 G_warning(
_(
"Next edge was visited (right) but it is not the "
593 "first one !!! breaking loop"));
595 "ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d",
596 v, (edge->
v1 == v) ? (edge->
v2) : (edge->
v1), opt_side,
603 G_warning(
_(
"Next edge was visited (left) but it is not the "
604 "first one !!! breaking loop"));
606 "ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d",
607 v, (edge->
v1 == v) ? (edge->
v2) : (edge->
v1), opt_side,
613 edge = vert->
edges[opt_j];
616 v = (edge->
v1 == v) ? (edge->
v2) : (edge->
v1);
619 eangle = vert0->
angles[opt_j];
623 G_debug(4,
"ec: append point x=%.18f y=%.18f", vert->
x, vert->
y);
638 static void extract_outer_contour(
struct planar_graph *pg,
int side,
646 double min_x, min_angle;
648 G_debug(3,
"extract_outer_contour()");
657 for (i = 0; i < pg->
vcount; i++) {
658 if (flag || (pg->
v[i].
x < min_x)) {
667 for (i = 0; i < vert->
ecount; i++) {
668 if (flag || (vert->
angles[i] < min_angle)) {
669 edge = vert->
edges[i];
670 min_angle = vert->
angles[i];
690 static int extract_inner_contour(
struct planar_graph *pg,
int *winding,
696 G_debug(3,
"extract_inner_contour()");
698 for (i = 0; i < pg->
ecount; i++) {
703 extract_contour(pg, &(pg->
e[i]),
RIGHT_SIDE, w, 0, nPoints);
711 extract_contour(pg, &(pg->
e[i]),
LEFT_SIDE, w, 0, nPoints);
726 static int point_in_buf(
struct line_pnts *Points,
double px,
double py,
727 double da,
double db,
double dalpha)
731 double delta, delta_k, k;
732 double vx, vy, wx, wy, mx, my, nx, ny;
733 double len, tx, ty, d, da2;
741 for (i = 0; i < np - 1; i++) {
744 wx = Points->
x[i + 1];
745 wy = Points->
y[i + 1];
751 elliptic_tangent(mx / len, my / len, da, db, dalpha, &cx, &cy);
753 delta = mx * cy - my * cx;
754 delta_k = (px - vx) * cy - (py - vy) * cx;
772 elliptic_transform(px - nx, py - ny, 1 / da, 1 / db, dalpha, &tx,
787 d =
dig_distance2_point_to_line(px, py, 0, vx, vy, 0, wx, wy, 0, 0,
801 static int get_polygon_orientation(
const double *
x,
const double *y,
int n)
803 double x1, y1, x2, y2;
817 area += (y2 + y1) * (x2 - x1);
824 static void add_line_to_array(
struct line_pnts *Points,
826 int *allocated,
int more)
828 if (*allocated == *
count) {
833 (*arrPoints)[*
count] = Points;
839 static void destroy_lines_array(
struct line_pnts **arr,
int count)
843 for (i = 0; i <
count; i++)
851 static void buffer_lines(
struct line_pnts *area_outer,
852 struct line_pnts **area_isles,
int isles_count,
853 int side,
double da,
double db,
double dalpha,
854 int round,
int caps,
double tol,
856 struct line_pnts ***iPoints,
int *inner_count)
870 auto_side = (side == 0);
878 G_debug(3,
" processing outer contour");
881 side = get_polygon_orientation(area_outer->
x, area_outer->
y,
885 convolution_line(area_outer, da, db, dalpha, side, round, caps, tol,
888 extract_outer_contour(pg2, 0, *oPoints);
889 res = extract_inner_contour(pg2, &winding, cPoints);
896 if (area_size == 0) {
900 if (cPoints->
x[0] != cPoints->
x[cPoints->
n_points - 1] ||
901 cPoints->
y[0] != cPoints->
y[cPoints->
n_points - 1]) {
910 if (!point_in_buf(area_outer, px, py, da, db, dalpha)) {
911 add_line_to_array(cPoints, &arrPoints, &
count,
917 G_warning(
_(
"Vect_get_point_in_poly() failed"));
921 res = extract_inner_contour(pg2, &winding, cPoints);
926 G_debug(3,
" processing inner contours");
927 for (i = 0; i < isles_count; i++) {
929 side = get_polygon_orientation(area_isles[i]->
x, area_isles[i]->
y,
933 convolution_line(area_isles[i], da, db, dalpha, side, round, caps, tol,
936 extract_outer_contour(pg2, 0, cPoints);
937 res = extract_inner_contour(pg2, &winding, cPoints);
944 if (area_size == 0) {
948 if (cPoints->
x[0] != cPoints->
x[cPoints->
n_points - 1] ||
949 cPoints->
y[0] != cPoints->
y[cPoints->
n_points - 1]) {
962 if (!point_in_buf(area_isles[i], px, py, da, db,
964 add_line_to_array(cPoints, &arrPoints, &
count,
970 G_warning(
_(
"Vect_get_point_in_poly() failed"));
974 res = extract_inner_contour(pg2, &winding, cPoints);
980 *inner_count =
count;
981 *iPoints = arrPoints;
986 G_debug(3,
"buffer_lines() ... done");
1015 double dalpha,
int round,
int caps,
double tol,
1022 int isles_count = 0;
1025 int isles_allocated = 0;
1027 G_debug(2,
"Vect_line_buffer()");
1044 extract_outer_contour(pg, 0, outer);
1047 res = extract_inner_contour(pg, &winding, tPoints);
1049 add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated,
1052 res = extract_inner_contour(pg, &winding, tPoints);
1055 buffer_lines(outer, isles, isles_count,
RIGHT_SIDE, da, db, dalpha, round,
1056 caps, tol, oPoints, iPoints, inner_count);
1060 destroy_lines_array(isles, isles_count);
1080 double dalpha,
int round,
int caps,
double tol,
1086 int isles_count = 0, n_isles;
1089 int isles_allocated = 0;
1091 G_debug(2,
"Vect_area_buffer()");
1096 isles_allocated = n_isles;
1106 for (i = 0; i < n_isles; i++) {
1117 add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated,
1122 buffer_lines(outer, isles, isles_count, 0, da, db, dalpha, round, caps, tol,
1123 oPoints, iPoints, inner_count);
1127 destroy_lines_array(isles, isles_count);
1147 double dalpha,
int round,
double tol,
1151 double angular_tol, angular_step, phi1;
1161 angular_tol = angular_tolerance(tol, da, db);
1163 nsegments = (int)(2 *
PI / angular_tol) + 1;
1164 angular_step = 2 *
PI / nsegments;
1167 for (j = 0; j < nsegments; j++) {
1168 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx, &ty);
1170 phi1 += angular_step;
1197 double dalpha,
int side,
int round,
double tol,
1201 "Vect_line_parallel(): npoints = %d, da = %f, "
1202 "db = %f, dalpha = %f, side = %d, round_corners = %d, tol = %f",
1203 InPoints->
n_points, da, db, dalpha, side, round, tol);
1205 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.