-
Notifications
You must be signed in to change notification settings - Fork 4
/
utils_split.py
123 lines (104 loc) · 4.25 KB
/
utils_split.py
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
# -*- coding: utf-8 -*-
"""
SPLIT LINESTRINGS AS POITS
Andrés García Martínez ([email protected])
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
"""
__author__ = 'Andrés García Martínez'
__date__ = '2019-07-19'
__copyright__ = '(C) 2019 by Andrés García Martínez'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from math import copysign
def split_linestring(linestring, point, tol=0.0):
"""Split a line string at point.
Return
If exits intersection: ([(X0, Y0).. (Xs, Ys)], [(Xs, Ys).. (Xn, Yn)]);
otherwise: None.
Arguments
---------
linestring: list, [(X0, Y0).. (Xn, Yn)] line string
point: tuple, (Xs, Ys) splitting point coordinates
tol: float, tolerance distance
"""
# SPLIT LINE STRING
# SEGMENT LOOP
n = len(linestring)-1
for i in range(n):
xs, ys = linestring[i][0:2]
x1e, y1e = linestring[i+1][0]-xs, linestring[i+1][1]-ys
x1p, y1p = point[0]-xs, point[1]-ys
cteta = x1e / (x1e**2 + y1e**2)**0.5
steta = copysign((1-cteta**2)**0.5, y1e)
b = x1e*cteta + y1e*steta
d = -x1p*steta + y1p*cteta
a = x1p*cteta + y1p*steta
xi = xs + a*cteta
yi = ys + a*steta
# IGNORE TOO SHORT SEGMENT
if b > tol:
# DETECT PROXIMITY
if abs(d) <= tol:
if -tol <= a <= tol:
if i == 0:
#print('Near start point')
return None # IGNORE INTERSECTION AT START POINT
# SPLIT AT INITIAL SEGMENT POINT
print('Splitted at vertex')
fpart = linestring[0:i+2].copy()
spart = linestring[i+1:].copy()
return (fpart, spart)
if b-tol <= a <= b+tol:
if i == n-1:
#print('Near end point')
return None # IGNORE INTERSECTION AT END POINT
# SPLIT AT FINAL SEGMENT POINT
#print('Splitted at vertex')
fpart = linestring[0:i+2].copy()
spart = linestring[i+1:].copy()
return(fpart, spart)
if tol < a < b-tol:
# SPLIT AT SEGMENT
#print('Splitted at inner point')
fpart = linestring[0:i+1].copy()
fpart.append((xi, yi))
spart = linestring[i+1:].copy()
spart.insert(0, (xi, yi))
return (fpart, spart)
#else:
#print('Too short segment')
# SPLITTING POINT NOT FOUND
return None
def split_linestring_m(linestring, points, tol=0.0):
"""Return a list of linestring parts splitted by points.
The result is a list of list containing the linestring parts.
[[initial_point, ..., first_division], ..., [last_division, final_point]]
Arguments
---------
linestring: list, [(x,y), ..]
points: list, [(x, y), ..] splitting points
tol: float, tolerance distance
.
"""
# INITIALIZE RESULT LINES
result = [linestring.copy()]
# POINTS LOOP
for point in points:
# LINESTRINGS LOOP
for index, line in enumerate(result):
# SPLIT
splitted = split_linestring(line, point, tol)
# CHANGE OLD LINE AND ADD NEW
if splitted:
result[index] = splitted[0]
result.insert(index+1, splitted[1])
break
# RETURN RESULT
return result