-
-
Notifications
You must be signed in to change notification settings - Fork 301
/
split.c
144 lines (121 loc) · 4.45 KB
/
split.c
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;
}