1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
/****************************************************************
*
* MODULE: v.clean
*
* AUTHOR(S): Markus Metz
*
* PURPOSE: Split lines - helper tool for breaking lines
*
* COPYRIGHT: (C) 2012 by the GRASS Development Team
*
* This program is free software under the
* GNU General Public License (>=v2).
* Read the file COPYING that comes with GRASS
* for details.
*
***************************************************************/
#include <stdlib.h>
#include <math.h>
#include <grass/gis.h>
#include <grass/vector.h>
#include <grass/glocale.h>
int split_line(struct Map_info *Map, int otype, struct line_pnts *Points,
struct line_cats *Cats, struct Map_info *Err,
double split_distance);
/* split lines
* threshold is determined automatically
* returns number of split points */
int split_lines(struct Map_info *Map, int otype, struct Map_info *Err)
{
int line, nlines, n_split_lines, n_splits_total, type;
struct line_pnts *Points;
struct line_cats *Cats;
double area_size, split_distance;
struct bound_box box;
nlines = Vect_get_num_lines(Map);
n_split_lines = 0;
for (line = 1; line <= nlines; line++) {
type = Vect_get_line_type(Map, line);
if ((type & otype) && (type & GV_LINES))
n_split_lines++;
}
if (n_split_lines < 50)
return 0;
Vect_get_map_box(Map, &box);
area_size = sqrt((box.E - box.W) * (box.N - box.S));
split_distance = area_size / log(n_split_lines);
/* divisor is the handle: increase divisor to decrease split_distance
* see also v.in.ogr */
split_distance = split_distance / 16.;
G_debug(1, "area size: %f", area_size);
G_debug(1, "split distance: %f", split_distance);
Points = Vect_new_line_struct();
Cats = Vect_new_cats_struct();
n_splits_total = 0;
for (line = 1; line <= nlines; line++) {
int n_splits;
type = Vect_get_line_type(Map, line);
if (!((type & otype) && (type & GV_LINES)))
continue;
Vect_read_line(Map, Points, Cats, line);
/* can't split boundaries with only 2 vertices */
if (Points->n_points < 3)
continue;
n_splits = split_line(Map, type, Points, Cats, Err, split_distance);
if (n_splits)
Vect_delete_line(Map, line);
n_splits_total += n_splits;
}
Vect_destroy_line_struct(Points);
Vect_destroy_cats_struct(Cats);
G_verbose_message(_("Line splits: %d"), n_splits_total);
return n_splits_total;
}
/* split a line using split_distance
* returns number of split points */
int split_line(struct Map_info *Map, int otype, struct line_pnts *Points,
struct line_cats *Cats, struct Map_info *Err UNUSED,
double split_distance)
{
int i, n_segs = 0;
double dist = 0., seg_dist, dx, dy;
struct line_pnts *OutPoints;
/* don't write zero length boundaries */
Vect_line_prune(Points);
if (Points->n_points < 2)
return 0;
/* can't split boundaries with only 2 vertices */
if (Points->n_points == 2) {
/* Vect_write_line(Map, otype, Points, Cats); */
return 0;
}
OutPoints = Vect_new_line_struct();
Vect_append_point(OutPoints, Points->x[0], Points->y[0], Points->z[0]);
Vect_append_point(OutPoints, Points->x[1], Points->y[1], Points->z[1]);
dx = Points->x[1] - Points->x[0];
dy = Points->y[1] - Points->y[0];
dist = sqrt(dx * dx + dy * dy);
/* trying to keep line length smaller than split_distance
* alternative, less code: write line as soon as split_distance is exceeded
*/
for (i = 2; i < Points->n_points; i++) {
dx = Points->x[i] - Points->x[i - 1];
dy = Points->y[i] - Points->y[i - 1];
seg_dist = sqrt(dx * dx + dy * dy);
dist += seg_dist;
if (dist > split_distance) {
Vect_write_line(Map, otype, OutPoints, Cats);
Vect_reset_line(OutPoints);
dist = seg_dist;
Vect_append_point(OutPoints, Points->x[i - 1], Points->y[i - 1],
Points->z[i - 1]);
n_segs++;
}
Vect_append_point(OutPoints, Points->x[i], Points->y[i], Points->z[i]);
}
/* write out remaining line points only when original line was split */
if (n_segs)
Vect_write_line(Map, otype, OutPoints, Cats);
Vect_destroy_line_struct(OutPoints);
return n_segs;
}
|