Render country labels
The positions are still a bit off, because they are simply calculated as the average of all polygon coordinates. That causes a bias towards detailed borderlines. A better way would be to calculate the center of mass for each polygon, but that is not implemented yet.
This commit is contained in:
parent
60f59379e5
commit
e965ec9032
85
qsomap.py
85
qsomap.py
|
@ -9,10 +9,7 @@ import json
|
||||||
import random
|
import random
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
REF_LATITUDE = 49.58666
|
LABEL_MIN_FONT_SIZE = 2
|
||||||
REF_LONGITUDE = 11.01250
|
|
||||||
# REF_LATITUDE = -30
|
|
||||||
# REF_LONGITUDE = 90
|
|
||||||
|
|
||||||
|
|
||||||
def map_azimuthal_equidistant(lat, lon, ref_lat, ref_lon, R=1):
|
def map_azimuthal_equidistant(lat, lon, ref_lat, ref_lon, R=1):
|
||||||
|
@ -57,14 +54,6 @@ def map_azimuthal_equidistant(lat, lon, ref_lat, ref_lon, R=1):
|
||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
|
|
||||||
def random_country_color():
|
|
||||||
h = random.random()
|
|
||||||
s = 0.7
|
|
||||||
v = 0.8
|
|
||||||
r, g, b = [int(255.99*x) for x in hsv_to_rgb([h, s, v])]
|
|
||||||
return f"#{r:02x}{g:02x}{b:02x}"
|
|
||||||
|
|
||||||
|
|
||||||
def is_point_in_polygon(point, polygon):
|
def is_point_in_polygon(point, polygon):
|
||||||
# Idea: draw an infinite line from the test point along the x axis to the
|
# Idea: draw an infinite line from the test point along the x axis to the
|
||||||
# right. Then check how many polygon edges this line intersects. If the
|
# right. Then check how many polygon edges this line intersects. If the
|
||||||
|
@ -203,6 +192,18 @@ def map_all_polygons(simplegeodata, ref_lat, ref_lon, map_radius):
|
||||||
v['proj_coordinates'] = proj_polys
|
v['proj_coordinates'] = proj_polys
|
||||||
|
|
||||||
|
|
||||||
|
def hsv_to_svgstr(h, s, v):
|
||||||
|
r, g, b = [int(255.99*x) for x in hsv_to_rgb([h, s, v])]
|
||||||
|
return f"#{r:02x}{g:02x}{b:02x}"
|
||||||
|
|
||||||
|
|
||||||
|
def assign_country_colors(simplegeodata):
|
||||||
|
for k, v in simplegeodata.items():
|
||||||
|
hue = random.random()
|
||||||
|
v['polygon_color'] = hsv_to_svgstr(hue, 0.7, 0.8)
|
||||||
|
v['label_color'] = hsv_to_svgstr(hue, 0.5, 0.4)
|
||||||
|
|
||||||
|
|
||||||
def svg_add_countries(doc, simplegeodata, ref_lat, ref_lon, map_radius):
|
def svg_add_countries(doc, simplegeodata, ref_lat, ref_lon, map_radius):
|
||||||
antipodal_lat = -ref_lat
|
antipodal_lat = -ref_lat
|
||||||
antipodal_lon = ref_lon + np.pi
|
antipodal_lon = ref_lon + np.pi
|
||||||
|
@ -211,9 +212,9 @@ def svg_add_countries(doc, simplegeodata, ref_lat, ref_lon, map_radius):
|
||||||
antipodal_lon -= 2*np.pi
|
antipodal_lon -= 2*np.pi
|
||||||
|
|
||||||
for k, v in simplegeodata.items():
|
for k, v in simplegeodata.items():
|
||||||
print(f"Exporting {k}…", file=sys.stderr)
|
print(f"Mapping {k}…", file=sys.stderr)
|
||||||
|
|
||||||
color = random_country_color()
|
color = v['polygon_color']
|
||||||
|
|
||||||
group = doc.g()
|
group = doc.g()
|
||||||
|
|
||||||
|
@ -293,6 +294,55 @@ def svg_add_maidenhead_grid(doc, ref_lat, ref_lon, map_radius):
|
||||||
doc.add(group) # Maidenhead grid
|
doc.add(group) # Maidenhead grid
|
||||||
|
|
||||||
|
|
||||||
|
def svg_add_country_names(doc, simplegeodata, map_radius):
|
||||||
|
group = doc.g()
|
||||||
|
|
||||||
|
for k, v in simplegeodata.items():
|
||||||
|
print(f"Labeling {k} ", end='')
|
||||||
|
for poly in v['proj_coordinates']:
|
||||||
|
x = poly[0, :]
|
||||||
|
y = poly[1, :]
|
||||||
|
|
||||||
|
w = np.max(x) - np.min(x)
|
||||||
|
h = np.max(y) - np.min(y)
|
||||||
|
|
||||||
|
# FIXME: calculate center of mass
|
||||||
|
center_x = np.median(x) + map_radius
|
||||||
|
center_y = np.median(y) + map_radius
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'class': 'country_label',
|
||||||
|
'fill': v['label_color']
|
||||||
|
}
|
||||||
|
|
||||||
|
# rotate text by 90 degrees if polygon is higher than wide
|
||||||
|
if h > w:
|
||||||
|
font_size = h / len(v['name'])
|
||||||
|
rotate = True
|
||||||
|
else:
|
||||||
|
font_size = w / len(v['name'])
|
||||||
|
rotate = False
|
||||||
|
|
||||||
|
if font_size < LABEL_MIN_FONT_SIZE:
|
||||||
|
print('.', end='', flush=True)
|
||||||
|
continue # too small
|
||||||
|
else:
|
||||||
|
print('#', end='', flush=True)
|
||||||
|
|
||||||
|
kwargs['font-size'] = font_size
|
||||||
|
|
||||||
|
txt = doc.text(v['name'], (center_x, center_y),
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
|
if rotate:
|
||||||
|
txt.rotate(90, center=(center_x, center_y))
|
||||||
|
group.add(txt)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
doc.add(group)
|
||||||
|
|
||||||
|
|
||||||
def svg_add_distance_azimuth_lines(doc, ref_lat, ref_lon, map_radius):
|
def svg_add_distance_azimuth_lines(doc, ref_lat, ref_lon, map_radius):
|
||||||
group = doc.g()
|
group = doc.g()
|
||||||
|
|
||||||
|
@ -388,6 +438,7 @@ def render(ref_lat, ref_lon, output_stream):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
map_all_polygons(simplegeodata, ref_lat, ref_lon, R)
|
map_all_polygons(simplegeodata, ref_lat, ref_lon, R)
|
||||||
|
assign_country_colors(simplegeodata)
|
||||||
|
|
||||||
# generate the SVG
|
# generate the SVG
|
||||||
|
|
||||||
|
@ -418,10 +469,13 @@ def render(ref_lat, ref_lon, output_stream):
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.maidenhead_label {
|
.maidenhead_label, .country_label {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
dominant-baseline: middle;
|
dominant-baseline: middle;
|
||||||
text-anchor: middle;
|
text-anchor: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maidenhead_label {
|
||||||
fill: red;
|
fill: red;
|
||||||
opacity: 0.25;
|
opacity: 0.25;
|
||||||
}
|
}
|
||||||
|
@ -432,6 +486,7 @@ def render(ref_lat, ref_lon, output_stream):
|
||||||
stroke_width=1, stroke='black'))
|
stroke_width=1, stroke='black'))
|
||||||
|
|
||||||
svg_add_countries(doc, simplegeodata, ref_lat, ref_lon, R)
|
svg_add_countries(doc, simplegeodata, ref_lat, ref_lon, R)
|
||||||
|
svg_add_country_names(doc, simplegeodata, R)
|
||||||
svg_add_maidenhead_grid(doc, ref_lat, ref_lon, R)
|
svg_add_maidenhead_grid(doc, ref_lat, ref_lon, R)
|
||||||
svg_add_distance_azimuth_lines(doc, ref_lat, ref_lon, R)
|
svg_add_distance_azimuth_lines(doc, ref_lat, ref_lon, R)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue