Skip to content

Commit d73469a

Browse files
committed
add geojson to svg
1 parent 38e73c0 commit d73469a

File tree

2 files changed

+2024
-0
lines changed

2 files changed

+2024
-0
lines changed

naive_svg/geojson2svg.py

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import colorsys
2+
import os
3+
import random
4+
5+
import numpy as np
6+
from pybind11_geobuf import geojson, tf
7+
8+
from naive_svg import SVG, Color
9+
10+
11+
def random_stroke():
12+
h, s, v = random.uniform(0, 1), random.uniform(0.4, 1), random.uniform(0.7, 1)
13+
r, g, b = (np.array(colorsys.hsv_to_rgb(h, s, v)) * 255).astype(np.uint8)
14+
# return f'#{r:02x}{g:02x}{b:02x}'
15+
return r, g, b
16+
17+
18+
def geojson2svg(
19+
input_path: str,
20+
output_path: str,
21+
*,
22+
with_label: bool = False,
23+
with_grid: bool = True,
24+
):
25+
fc = geojson.FeatureCollection()
26+
assert fc.load(input_path), f"failed to load {input_path}"
27+
28+
strokes = {}
29+
bbox = None
30+
svg = SVG(-1, -1)
31+
anchor = None
32+
gtypes = set()
33+
for idx, f in enumerate(fc):
34+
geom = f.geometry()
35+
if not geom.is_line_string() and not geom.is_polygon():
36+
continue
37+
llas = f.as_numpy()
38+
gtypes.add(f.geometry().type())
39+
if anchor is None:
40+
anchor = np.copy(llas[0])
41+
props = f.properties()
42+
ftype = str(props["type"]()) if "type" in props else "unknown"
43+
if ftype not in strokes:
44+
strokes[ftype] = random_stroke()
45+
r, g, b = strokes[ftype]
46+
enus = tf.lla2enu(llas, anchor_lla=anchor)
47+
if geom.is_line_string():
48+
svg.add_polyline(enus[:, :2]).stroke(Color(r, g, b)).stroke_width(0.2)
49+
else:
50+
svg.add_polygon(enus[:, :2]).stroke(Color(r, g, b)).fill(
51+
Color(r, g, b, 0.2)
52+
).stroke_width(0.2)
53+
pass
54+
if with_label:
55+
fid = str(props["id"]()) if "id" in props else f"f#{idx}"
56+
svg.add_text(enus[0, :2], text=fid, fontsize=1.0).lines(
57+
[f"type:{ftype}", f"index={idx}"]
58+
)
59+
emin = enus.min(axis=0)[:2]
60+
emax = enus.max(axis=0)[:2]
61+
if bbox is None:
62+
bbox = np.array([*emin, *emax])
63+
else:
64+
bbox[:2] = np.min([bbox[:2], emin], axis=0)
65+
bbox[2:] = np.max([bbox[2:], emax], axis=0)
66+
bbox[:2] -= 10.0
67+
bbox[2:] -= 10.0
68+
width, height = bbox[2:] - bbox[:2]
69+
70+
llas = tf.enu2lla([[*bbox[:2], 0.0], [*bbox[2:], 0.0]], anchor_lla=anchor)
71+
llas = llas.round(5)[:, :2]
72+
svg.width(width).height(height)
73+
if with_grid:
74+
svg.grid_step(100.0)
75+
svg.view_box([*bbox[:2], width, height])
76+
svg.attrs(f"bbox='{llas.reshape(-1).tolist()}'")
77+
os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
78+
return svg.dump(output_path)
79+
80+
81+
if __name__ == "__main__":
82+
import fire
83+
84+
fire.core.Display = lambda lines, out: print(*lines, file=out)
85+
fire.Fire(geojson2svg)

0 commit comments

Comments
 (0)