Skip to content

Commit 131dc61

Browse files
committed
arc with axes, fix implode undo, minor fixes
20141211 replace2.py merged in replace.py by adding Params 20141211 circle via ellipse.py 20141211 various comments, including stdin section for each modified scripts 20141212 fix deletion order in OsmData.py 20141213 Params in arc.py for axes, "Arc with axes" command 20141213 tagcalc and arc2 icons
1 parent 14f0a32 commit 131dc61

16 files changed

+579
-691
lines changed

OsmData.py

+292-268
Large diffs are not rendered by default.

arc.py

+118-74
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
33
#
4-
# arc.py
4+
# arc.py {Point1},{Point2},{Point3} {Segments} {Params}
5+
# stdin: -
6+
#
7+
# Script creates an arc by three specified points - start, intermediate and end of an arc. Arc will have specified number of segments.
8+
# Params: 0 - nothing special, 1 - creates axes of an arc
9+
# Segments = 0 will use autocalculation for smooth arc
10+
# Note: arc will not be more than semicircle, if intermediate point is far from start and end
11+
# then script will create counterpart arc of same circle (TOFIX)
512
#
613
# Copyright 2010-2011 Hind <foxhind@gmail.com>
14+
# modified by OverQuantum:
15+
# 2014-12-13 Fix to 4 spaces indentation; added Params (0/1) - 1 for creation of axes
716
#
817
# This program is free software; you can redistribute it and/or modify
918
# it under the terms of the GNU General Public License as published by
@@ -12,7 +21,7 @@
1221
#
1322
# This program is distributed in the hope that it will be useful,
1423
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1625
# GNU General Public License for more details.
1726
#
1827
# You should have received a copy of the GNU General Public License
@@ -26,85 +35,120 @@
2635
from OsmData import OsmData, Map, LON, LAT, ACTION, MODIFY, TAG, CREATE, REF, NODES, WAYS
2736

2837
if sys.version_info[0] < 3:
29-
reload(sys)
30-
sys.setdefaultencoding("utf-8") # a hack to support UTF-8
38+
reload(sys)
39+
sys.setdefaultencoding("utf-8") # a hack to support UTF-8
3140

3241
def intersect(vector1, pivot1, vector2, pivot2): # intersection of 2 lines
33-
k1 = vector1[1]/vector1[0]
34-
b1 = (vector1[0]*pivot1[1] - vector1[1]*pivot1[0]) / vector1[0]
35-
k2 = vector2[1]/vector2[0]
36-
b2 = (vector2[0]*pivot2[1] - vector2[1]*pivot2[0]) / vector2[0]
37-
x = (b1 - b2) / (k2 - k1)
38-
y = (k2*b1 - k1*b2) / (k2 - k1)
39-
return (x, y)
42+
k1 = vector1[1]/vector1[0]
43+
b1 = (vector1[0]*pivot1[1] - vector1[1]*pivot1[0]) / vector1[0]
44+
k2 = vector2[1]/vector2[0]
45+
b2 = (vector2[0]*pivot2[1] - vector2[1]*pivot2[0]) / vector2[0]
46+
x = (b1 - b2) / (k2 - k1)
47+
y = (k2*b1 - k1*b2) / (k2 - k1)
48+
return (x, y)
4049

4150
def createarc(C, P1, P2, r, segments):
42-
arc = [P1]
43-
CP1 = (P1[0]-C[0], P1[1]-C[1])
44-
CP2 = (P2[0]-C[0], P2[1]-C[1])
45-
a1 = math.atan(CP1[1]/CP1[0]) # start angle
46-
if CP1[0] < 0:
47-
a1 += math.pi
48-
if a1 < 0:
49-
a1 += math.pi*2
50-
a2 = math.atan(CP2[1]/CP2[0]) # end angle
51-
if CP2[0] < 0:
52-
a2 += math.pi
53-
if a2 < 0:
54-
a2 += math.pi*2
55-
56-
if a2-a1 > math.pi:
57-
a2 -= math.pi*2
58-
elif a1-a2 > math.pi:
59-
a1 -= math.pi*2
60-
61-
if segments == 0: # optimal number of segments
62-
P1P2 = (P2[0]-P1[0], P2[1]-P1[1])
63-
P1P2abs = math.sqrt(P1P2[0]*P1P2[0] + P1P2[1]*P1P2[1])
64-
segments = int(math.ceil(math.log(P1P2abs, 4) * (math.cos((a2-a1)/2) + 1.5))) # cat's magic formula
51+
arc = [P1]
52+
CP1 = (P1[0]-C[0], P1[1]-C[1])
53+
CP2 = (P2[0]-C[0], P2[1]-C[1])
54+
a1 = math.atan(CP1[1]/CP1[0]) # start angle
55+
if CP1[0] < 0:
56+
a1 += math.pi
57+
if a1 < 0:
58+
a1 += math.pi*2
59+
a2 = math.atan(CP2[1]/CP2[0]) # end angle
60+
if CP2[0] < 0:
61+
a2 += math.pi
62+
if a2 < 0:
63+
a2 += math.pi*2
6564

66-
interval = (a2 - a1) / segments
67-
for n in range(1, segments):
68-
val = a1 + interval * n
69-
arc.append(( C[0] + r * math.cos(val), C[1] + r * math.sin(val) ))
70-
arc.append(P2)
71-
return arc
65+
if a2-a1 > math.pi:
66+
a2 -= math.pi*2
67+
elif a1-a2 > math.pi:
68+
a1 -= math.pi*2
69+
70+
if segments == 0: # optimal number of segments
71+
P1P2 = (P2[0]-P1[0], P2[1]-P1[1])
72+
P1P2abs = math.sqrt(P1P2[0]*P1P2[0] + P1P2[1]*P1P2[1])
73+
segments = int(math.ceil(math.log(P1P2abs, 4) * (math.cos((a2-a1)/2) + 1.5))) # cat's magic formula
74+
75+
interval = (a2 - a1) / segments
76+
for n in range(1, segments):
77+
val = a1 + interval * n
78+
arc.append(( C[0] + r * math.cos(val), C[1] + r * math.sin(val) ))
79+
arc.append(P2)
80+
return arc
7281

7382
def main():
74-
if len(sys.argv) != 3:
83+
if len(sys.argv) != 4:
84+
return 0
85+
coords = (sys.argv[1].split(','))
86+
A = projections.from4326((float(coords[0]),float(coords[1])), "EPSG:3857")
87+
B = projections.from4326((float(coords[2]),float(coords[3])), "EPSG:3857")
88+
C = projections.from4326((float(coords[4]),float(coords[5])), "EPSG:3857")
89+
segments = int(sys.argv[2])
90+
params = int(sys.argv[3])
91+
AM = ((B[0] - A[0])/2, (B[1] - A[1])/2)
92+
BN = ((C[0] - B[0])/2, (C[1] - B[1])/2)
93+
M = (A[0] + AM[0], A[1] + AM[1])
94+
N = (B[0] + BN[0], B[1] + BN[1])
95+
MM = (AM[1], -AM[0])
96+
NN = (BN[1], -BN[0])
97+
O = intersect(MM, M, NN, N) # circle center
98+
OA = (O[0] - A[0], O[1] - A[1])
99+
r = math.sqrt(OA[0]*OA[0] + OA[1]*OA[1]) # radius
100+
arc = createarc(O, A, C, r, segments)
101+
102+
tData = OsmData()
103+
wayid = tData.addway()
104+
for point in arc:
105+
p = projections.to4326(point, "EPSG:3857")
106+
newid = tData.addnode()
107+
tData.nodes[newid][LON] = p[0]
108+
tData.nodes[newid][LAT] = p[1]
109+
tData.nodes[newid][TAG] = {}
110+
tData.ways[wayid][REF].append(newid)
111+
if params == 1:
112+
p2 = projections.to4326(O, "EPSG:3857") # center
113+
p1 = projections.to4326((O[0]-r*1.05,O[1]), "EPSG:3857") # axes points
114+
p3 = projections.to4326((O[0]+r*1.05,O[1]), "EPSG:3857")
115+
p4 = projections.to4326((O[0],O[1]-r*1.05), "EPSG:3857")
116+
p5 = projections.to4326((O[0],O[1]+r*1.05), "EPSG:3857")
117+
wayid = tData.addway()
118+
newid = tData.addnode()
119+
tData.nodes[newid][LON] = p1[0]
120+
tData.nodes[newid][LAT] = p1[1]
121+
tData.nodes[newid][TAG] = {}
122+
tData.ways[wayid][REF].append(newid)
123+
newid2 = tData.addnode()
124+
tData.nodes[newid2][LON] = p2[0]
125+
tData.nodes[newid2][LAT] = p2[1]
126+
tData.nodes[newid2][TAG] = {}
127+
tData.ways[wayid][REF].append(newid2)
128+
newid = tData.addnode()
129+
tData.nodes[newid][LON] = p3[0]
130+
tData.nodes[newid][LAT] = p3[1]
131+
tData.nodes[newid][TAG] = {}
132+
tData.ways[wayid][REF].append(newid)
133+
wayid = tData.addway()
134+
newid = tData.addnode()
135+
tData.nodes[newid][LON] = p4[0]
136+
tData.nodes[newid][LAT] = p4[1]
137+
tData.nodes[newid][TAG] = {}
138+
tData.ways[wayid][REF].append(newid)
139+
tData.ways[wayid][REF].append(newid2)
140+
newid = tData.addnode()
141+
tData.nodes[newid][LON] = p5[0]
142+
tData.nodes[newid][LAT] = p5[1]
143+
tData.nodes[newid][TAG] = {}
144+
tData.ways[wayid][REF].append(newid)
145+
146+
tData.addcomment("Done.")
147+
tData.write(sys.stdout)
148+
#f = open("out.txt", "w")
149+
#tData.write(f)
150+
#f.close()
75151
return 0
76-
coords = (sys.argv[1].split(','))
77-
A = projections.from4326((float(coords[0]),float(coords[1])), "EPSG:3857")
78-
B = projections.from4326((float(coords[2]),float(coords[3])), "EPSG:3857")
79-
C = projections.from4326((float(coords[4]),float(coords[5])), "EPSG:3857")
80-
segments = int(sys.argv[2])
81-
AM = ((B[0] - A[0])/2, (B[1] - A[1])/2)
82-
BN = ((C[0] - B[0])/2, (C[1] - B[1])/2)
83-
M = (A[0] + AM[0], A[1] + AM[1])
84-
N = (B[0] + BN[0], B[1] + BN[1])
85-
MM = (AM[1], -AM[0])
86-
NN = (BN[1], -BN[0])
87-
O = intersect(MM, M, NN, N)
88-
OA = (O[0] - A[0], O[1] - A[1])
89-
r = math.sqrt(OA[0]*OA[0] + OA[1]*OA[1])
90-
arc = createarc(O, A, C, r, segments)
91-
92-
tData = OsmData()
93-
wayid = tData.addway()
94-
for point in arc:
95-
p = projections.to4326(point, "EPSG:3857")
96-
newid = tData.addnode()
97-
tData.nodes[newid][LON] = p[0]
98-
tData.nodes[newid][LAT] = p[1]
99-
tData.nodes[newid][TAG] = {}
100-
tData.ways[wayid][REF].append(newid)
101-
102-
tData.addcomment("Done.")
103-
tData.write(sys.stdout)
104-
#f = open("out.txt", "w")
105-
#tData.write(f)
106-
#f.close()
107-
return 0
108152

109153
if __name__ == '__main__':
110-
main()
154+
main()

arc.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<command version="3" name="Arc" icon="arc.png" run="python arc.py {P1},{P2},{P3} {Segments}">
2+
<command version="3" name="Arc" icon="arc.png" run="python arc.py {P1},{P2},{P3} {Segments} 0">
33
<parameter required="true" type="point">
44
<name>P1</name>
55
<description>Start point of arc</description>

arc2.png

418 Bytes
Loading

arc2.xml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<command version="3" name="Arc with axes" icon="arc2.png" run="python arc.py {P1},{P2},{P3} {Segments} 1">
3+
<parameter required="true" type="point">
4+
<name>P1</name>
5+
<description>Start point of arc</description>
6+
</parameter>
7+
<parameter required="true" type="point">
8+
<name>P2</name>
9+
<description>Middle point on arc</description>
10+
</parameter>
11+
<parameter required="true" type="point">
12+
<name>P3</name>
13+
<description>End point of arc</description>
14+
</parameter>
15+
<parameter required="true" maxvalue="144" type="natural">
16+
<name>Segments</name>
17+
<description>Number of segments (0 - auto)</description>
18+
<value>5</value>
19+
</parameter>
20+
</command>

circle.py

-61
This file was deleted.

circle.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<command version="3" name="Circle" icon="circle.png" run="python circle.py {Center} {Radius} {Sides}">
2+
<command version="3" name="Circle" icon="circle.png" run="python ellipse.py {Center} {Radius} {Radius} 0 {Sides}">
33
<parameter required="true" type="point">
44
<name>Center</name>
55
<description>Center of circle</description>

ellipse.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
# -*- coding: utf-8 -*-
33
#
44
# ellipse.py {Center} {Radius1} {Radius2} {Angle} {Sides}
5+
# stdin: -
56
#
6-
# Script creates ellipse, specified by center, semi-major and semi-minor axises and rotation angle
7-
# Hint: ellipse with 4 sides allows to draw rotated axises
7+
# Script creates ellipse, specified by center, semi-major and semi-minor axes and rotation angle
8+
# Hint: ellipse with 4 sides allows to draw rotated axes
89
#
910
# Made from circle.py ( Copyright 2010-2011 Hind <foxhind@gmail.com> )
1011
# by OverQuantum, 2014-10-30

grid2m.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33
#
44
# grid2m.py {Cell}
5+
# stdin: {EscribingObjects}
56
#
67
# Script creates square grid escribing selected object(s)
78
# (members of selected relations is not counted)
@@ -37,7 +38,7 @@
3738

3839
def main():
3940
nData = OsmData() # Nodes
40-
rData = OsmData() # Escribing way
41+
rData = OsmData() # Escribing ways
4142
nData.read(sys.stdin)
4243
rData.read(sys.stdin)
4344
cell = float(sys.argv[1].replace(',', '.')) # cell size, meters

implode.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# -*- coding: utf-8 -*-
33
#
44
# implode.py
5+
# stdin: {Ways}
56
#
67
# Script implodes each selected way to a single node (bbox center) which inherits all way's tags
78
#
@@ -34,7 +35,7 @@
3435

3536
def main():
3637
nData = OsmData() # Nodes
37-
rData = OsmData() # Reference way
38+
rData = OsmData() # Reference ways
3839
nData.read(sys.stdin)
3940
rData.read(sys.stdin)
4041
idn = list(rData.ways.keys())

0 commit comments

Comments
 (0)