26 #define LENGTH(DX, DY) (sqrt((DX*DX)+(DY*DY))) 28 #define MIN(X,Y) ((X<Y)?X:Y) 31 #define MAX(X,Y) ((X>Y)?X:Y) 37 #define NON_LOOPED_LINE 0 40 static void norm_vector(
double x1,
double y1,
double x2,
double y2,
double *
x,
47 if ((dx == 0) && (dy == 0)) {
61 static void rotate_vector(
double x,
double y,
double cosa,
double sina,
62 double *nx,
double *ny)
64 *nx =
x * cosa -
y * sina;
65 *ny =
x * sina +
y * cosa;
74 static void elliptic_transform(
double x,
double y,
double da,
double db,
75 double dalpha,
double *nx,
double *ny)
77 double cosa = cos(dalpha);
78 double sina = sin(dalpha);
90 va = (
x * cosa +
y * sina) * da;
91 vb = (
x * (-sina) +
y * cosa) * db;
92 *nx = va * cosa + vb * (-sina);
93 *ny = va * sina + vb * cosa;
104 static void elliptic_tangent(
double x,
double y,
double da,
double db,
105 double dalpha,
double *px,
double *py)
107 double cosa = cos(dalpha);
108 double sina = sin(dalpha);
112 rotate_vector(
x,
y, cosa, -sina, &
x, &
y);
117 len = da * db / sqrt(da * da * v * v + db * db * u * u);
120 rotate_vector(u, v, cosa, sina, px, py);
129 static void line_coefficients(
double x1,
double y1,
double x2,
double y2,
130 double *a,
double *
b,
double *c)
134 *c = x2 * y1 - x1 * y2;
144 static int line_intersection(
double a1,
double b1,
double c1,
double a2,
145 double b2,
double c2,
double *
x,
double *
y)
149 if (fabs(a2 * b1 - a1 * b2) == 0) {
150 if (fabs(a2 * c1 - a1 * c2) == 0)
156 d = a1 * b2 - a2 * b1;
157 *
x = (b1 * c2 - b2 * c1) / d;
158 *y = (c1 * a2 - c2 * a1) / d;
163 static double angular_tolerance(
double tol,
double da,
double db)
165 double a =
MAX(da, db);
170 return 2 * acos(1 - tol / a);
185 static void parallel_line(
struct line_pnts *Points,
double da,
double db,
186 double dalpha,
int side,
int round,
int caps,
int looped,
191 double tx, ty, vx, vy, wx, wy, nx, ny, mx, my, rx, ry;
192 double vx1, vy1, wx1, wy1;
193 double a0, b0, c0, a1, b1, c1;
194 double phi1, phi2, delta_phi;
195 double nsegments, angular_tol, angular_step;
196 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++) {
235 norm_vector(x[i], y[i], x[i + 1], y[i + 1], &tx, &ty);
236 if ((tx == 0) && (ty == 0))
239 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &vx, &vy);
247 line_coefficients(nx, ny, mx, my, &a1, &b1, &c1);
255 delta_phi = atan2(ty, tx) - atan2(y[i] - y[i - 1], x[i] - x[i - 1]);
258 else if (delta_phi <= -
PI)
261 turns360 = (fabs(fabs(delta_phi) -
PI) < 1e-15);
262 inner_corner = (side * delta_phi <= 0) && (!turns360);
264 if ((turns360) && (!(caps && round))) {
266 norm_vector(0, 0, vx, vy, &tx, &ty);
267 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);
299 elliptic_transform(wx, wy, 1 / da, 1 / db, dalpha, &wx1, &wy1);
300 elliptic_transform(vx, vy, 1 / da, 1 / db, dalpha, &vx1, &vy1);
302 phi1 = atan2(wy1, wx1);
303 phi2 = atan2(vy1, vx1);
304 delta_phi = side * (phi2 - phi1);
310 nsegments = (int)(delta_phi / angular_tol) + 1;
311 angular_step = side * (delta_phi / nsegments);
313 for (j = 0; j <= nsegments; j++) {
314 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
317 phi1 += angular_step;
321 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);
412 delta_phi = angle1 - angle0;
415 else if (delta_phi <= -
PI)
418 turns360 = (fabs(fabs(delta_phi) -
PI) < 1e-15);
419 inner_corner = (side * delta_phi <= 0) && (!turns360);
423 if (turns360 && caps && (!round)) {
424 norm_vector(0, 0, vx, vy, &tx, &ty);
425 elliptic_tangent(side * tx, side * ty, da, db, dalpha, &tx, &ty);
427 G_debug(4,
" append point (c) x=%.16f y=%.16f", x[i] + wx + tx,
430 G_debug(4,
" append point (c) x=%.16f y=%.16f", nx + tx, ny + ty);
433 if ((!turns360) && (!round) && (!inner_corner)) {
434 res = line_intersection(a0, b0, c0, a1, b1, c1, &rx, &ry);
437 G_debug(4,
" append point (o) x=%.16f y=%.16f", rx, ry);
443 G_fatal_error(
_(
"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);
493 int side,
int winding,
int stop_at_line_end,
507 double opt_angle, tangle;
508 int opt_j, opt_side, opt_flag;
510 G_debug(3,
"extract_contour(): v1=%d, v2=%d, side=%d, stop_at_line_end=%d",
511 first->
v1, first->
v2, side, stop_at_line_end);
526 vert0 = &(pg->
v[v0]);
528 eangle = atan2(vert->
y - vert0->
y, vert->
x - vert0->
x);
532 G_debug(4,
"ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d", v0,
533 v, eside, edge->
v1, edge->
v2);
534 G_debug(4,
"ec: append point x=%.18f y=%.18f", vert0->
x, vert0->
y);
547 for (j = 0; j < vert->
ecount; j++) {
549 if (vert->
edges[j] != edge) {
550 tangle = vert->
angles[j] - eangle;
553 else if (tangle >
PI)
557 if (opt_flag || (tangle < opt_angle)) {
559 opt_side = (vert->
edges[j]->
v1 == v) ? (1) : (-1);
573 if (stop_at_line_end) {
574 G_debug(3,
" end has been reached, will stop here");
580 G_debug(3,
" end has been reached, turning around");
585 if ((vert->
edges[opt_j] == first) && (opt_side == side))
589 G_warning(
_(
"Next edge was visited (right) but it is not the first one !!! breaking loop"));
591 "ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d",
592 v, (edge->
v1 == v) ? (edge->
v2) : (edge->
v1),
593 opt_side, vert->
edges[opt_j]->
v1,
600 G_warning(
_(
"Next edge was visited (left) but it is not the first one !!! breaking loop"));
602 "ec: v0=%d, v=%d, eside=%d, edge->v1=%d, edge->v2=%d",
603 v, (edge->
v1 == v) ? (edge->
v2) : (edge->
v1),
604 opt_side, vert->
edges[opt_j]->
v1,
610 edge = vert->
edges[opt_j];
613 v = (edge->
v1 == v) ? (edge->
v2) : (edge->
v1);
616 eangle = vert0->
angles[opt_j];
620 G_debug(4,
"ec: append point x=%.18f y=%.18f", vert->
x, vert->
y);
635 static void extract_outer_contour(
struct planar_graph *pg,
int side,
643 double min_x, min_angle;
645 G_debug(3,
"extract_outer_contour()");
654 for (i = 0; i < pg->
vcount; i++) {
655 if (flag || (pg->
v[i].
x < min_x)) {
664 for (i = 0; i < vert->
ecount; i++) {
665 if (flag || (vert->
angles[i] < min_angle)) {
666 edge = vert->
edges[i];
667 min_angle = vert->
angles[i];
686 static int extract_inner_contour(
struct planar_graph *pg,
int *winding,
692 G_debug(3,
"extract_inner_contour()");
694 for (i = 0; i < pg->
ecount; i++) {
699 extract_contour(pg, &(pg->
e[i]),
RIGHT_SIDE, w, 0, nPoints);
707 extract_contour(pg, &(pg->
e[i]),
LEFT_SIDE, w, 0, nPoints);
722 static int point_in_buf(
struct line_pnts *Points,
double px,
double py,
double da,
723 double db,
double dalpha)
727 double delta, delta_k, k;
728 double vx, vy, wx, wy, mx, my, nx, ny;
729 double len, tx, ty, d, da2;
737 for (i = 0; i < np - 1; i++) {
740 wx = Points->
x[i + 1];
741 wy = Points->
y[i + 1];
747 elliptic_tangent(mx / len, my / len, da, db, dalpha, &cx, &cy);
749 delta = mx * cy - my * cx;
750 delta_k = (px - vx) * cy - (py - vy) * cx;
767 elliptic_transform(px - nx, py - ny, 1 / da, 1 / db, dalpha, &tx,
795 static int get_polygon_orientation(
const double *
x,
const double *y,
int n)
797 double x1, y1, x2, y2;
811 area += (y2 + y1) * (x2 - x1);
818 static void add_line_to_array(
struct line_pnts *Points,
820 int *allocated,
int more)
822 if (*allocated == *
count) {
827 (*arrPoints)[*
count] = Points;
833 static void destroy_lines_array(
struct line_pnts **arr,
int count)
837 for (i = 0; i <
count; i++)
846 int isles_count,
int side,
double da,
double db,
847 double dalpha,
int round,
int caps,
double tol,
863 auto_side = (side == 0);
871 G_debug(3,
" processing outer contour");
875 get_polygon_orientation(area_outer->
x, area_outer->
y,
878 convolution_line(area_outer, da, db, dalpha, side, round, caps, tol,
881 extract_outer_contour(pg2, 0, *oPoints);
882 res = extract_inner_contour(pg2, &winding, cPoints);
889 if (area_size == 0) {
893 if (cPoints->
x[0] != cPoints->
x[cPoints->
n_points - 1] ||
894 cPoints->
y[0] != cPoints->
y[cPoints->
n_points - 1]) {
902 if (!point_in_buf(area_outer, px, py, da, db, dalpha)) {
903 add_line_to_array(cPoints, &arrPoints, &count, &allocated,
909 G_warning(
_(
"Vect_get_point_in_poly() failed"));
913 res = extract_inner_contour(pg2, &winding, cPoints);
918 G_debug(3,
" processing inner contours");
919 for (i = 0; i < isles_count; i++) {
922 get_polygon_orientation(area_isles[i]->
x, area_isles[i]->
y,
925 convolution_line(area_isles[i], da, db, dalpha, side, round, caps,
928 extract_outer_contour(pg2, 0, cPoints);
929 res = extract_inner_contour(pg2, &winding, cPoints);
936 if (area_size == 0) {
940 if (cPoints->
x[0] != cPoints->
x[cPoints->
n_points - 1] ||
941 cPoints->
y[0] != cPoints->
y[cPoints->
n_points - 1]) {
951 (cPoints->
x[0], cPoints->
y[0], area_isles[i])) {
953 if (!point_in_buf(area_isles[i], px, py, da, db, dalpha)) {
954 add_line_to_array(cPoints, &arrPoints, &count,
960 G_warning(
_(
"Vect_get_point_in_poly() failed"));
964 res = extract_inner_contour(pg2, &winding, cPoints);
970 *inner_count =
count;
971 *iPoints = arrPoints;
976 G_debug(3,
"buffer_lines() ... done");
1006 double dalpha,
int round,
int caps,
double tol,
1008 struct line_pnts ***iPoints,
int *inner_count)
1013 int isles_count = 0;
1016 int isles_allocated = 0;
1018 G_debug(2,
"Vect_line_buffer()");
1024 dalpha, round, tol, oPoints);
1033 extract_outer_contour(pg, 0, outer);
1036 res = extract_inner_contour(pg, &winding, tPoints);
1038 add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated,
1041 res = extract_inner_contour(pg, &winding, tPoints);
1044 buffer_lines(outer, isles, isles_count,
RIGHT_SIDE, da, db, dalpha, round,
1045 caps, tol, oPoints, iPoints, inner_count);
1049 destroy_lines_array(isles, isles_count);
1071 double dalpha,
int round,
int caps,
double tol,
1073 struct line_pnts ***iPoints,
int *inner_count)
1077 int isles_count = 0, n_isles;
1080 int isles_allocated = 0;
1082 G_debug(2,
"Vect_area_buffer()");
1087 isles_allocated = n_isles;
1097 for (i = 0; i < n_isles; i++) {
1108 add_line_to_array(tPoints, &isles, &isles_count, &isles_allocated,
1113 buffer_lines(outer, isles, isles_count, 0, da, db, dalpha, round, caps,
1114 tol, oPoints, iPoints, inner_count);
1118 destroy_lines_array(isles, isles_count);
1136 double dalpha,
int round,
double tol,
1140 double angular_tol, angular_step, phi1;
1143 G_debug(2,
"Vect_point_buffer()");
1149 if (round || (!round)) {
1150 angular_tol = angular_tolerance(tol, da, db);
1152 nsegments = (int)(2 *
PI / angular_tol) + 1;
1153 angular_step = 2 *
PI / nsegments;
1156 for (j = 0; j < nsegments; j++) {
1157 elliptic_transform(cos(phi1), sin(phi1), da, db, dalpha, &tx,
1160 phi1 += angular_step;
1189 double dalpha,
int side,
int round,
double tol,
1192 G_debug(2,
"Vect_line_parallel(): npoints = %d, da = %f, " 1193 "db = %f, dalpha = %f, side = %d, round_corners = %d, tol = %f",
1194 InPoints->
n_points, da, db, dalpha, side, round, tol);
1196 parallel_line(InPoints, da, db, dalpha, side, round, 1,
NON_LOOPED_LINE,
int Vect_point_in_poly(double, double, const struct line_pnts *)
Determines if a point (X,Y) is inside a polygon.
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void pg_destroy_struct(struct planar_graph *pg)
int Vect_get_area_isle(const struct Map_info *, int, int)
Returns isle id for area.
int n_points
Number of points.
int Vect_copy_xyz_to_pnts(struct line_pnts *, const double *, const double *, const double *, int)
Copy points from array to line_pnts structure.
void G_free(void *)
Free allocated memory.
int Vect_get_area_num_isles(const struct Map_info *, int)
Returns number of isles for given area.
int Vect_line_prune(struct line_pnts *)
Remove duplicate points, i.e. zero length segments.
double * x
Array of X coordinates.
Feature geometry info - coordinates.
struct planar_graph * pg_create(const struct line_pnts *Points)
int Vect_get_point_in_poly(const struct line_pnts *, double *, double *)
Get point inside polygon.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
double dig_distance2_point_to_line(double, double, double, double, double, double, double, double, double, int, double *, double *, double *, double *, int *)
int Vect_get_isle_points(const struct Map_info *, int, struct line_pnts *)
Returns polygon array of points for given isle.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
double * y
Array of Y coordinates.
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 G_warning(const char *,...) __attribute__((format(printf
double * z
Array of Z coordinates.
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_destroy_line_struct(struct line_pnts *)
Frees all memory associated with a line_pnts structure, including the structure itself.
int Vect_get_area_points(const struct Map_info *, int, struct line_pnts *)
Returns polygon array of points (outer ring) of given area.
int G_debug(int, const char *,...) __attribute__((format(printf
void Vect_area_buffer2(const 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 Vect_reset_line(struct line_pnts *)
Reset line.
int Vect_line_delete_point(struct line_pnts *, int)
Delete point at given index and move all points above down.
int dig_find_area_poly(struct line_pnts *, double *)