Skip to content

Commit 2a40f8b

Browse files
committed
make most methods of Nik4Image non-static, decompose setup_options()
1 parent 151c9ba commit 2a40f8b

File tree

3 files changed

+127
-117
lines changed

3 files changed

+127
-117
lines changed

nik4.py

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -126,35 +126,6 @@ def prepare_wld(bbox, mwidth, mheight):
126126
]])
127127

128128

129-
def parse_url(url, options):
130-
"""Parse map URL into options map"""
131-
lat = None
132-
lon = None
133-
zoom = None
134-
m = re.search(r'[#/=]([0-9]{1,2})/(-?[0-9]{1,2}\.[0-9]+)/(-?[0-9]{1,3}\.[0-9]+)', url)
135-
if m:
136-
zoom = int(m.group(1))
137-
lat = float(m.group(2))
138-
lon = float(m.group(3))
139-
else:
140-
m = re.search(r'lat=(-[0-9]{1,2}\.[0-9]+)', url, flags=re.IGNORECASE)
141-
if m:
142-
lat = float(m.group(1))
143-
m = re.search(r'lon=(-[0-9]{1,3}\.[0-9]+)', url, flags=re.IGNORECASE)
144-
if m:
145-
lon = float(m.group(1))
146-
m = re.search(r'zoom=([0-9]{1,2})', url, flags=re.IGNORECASE)
147-
if m:
148-
zoom = int(m.group(1))
149-
if zoom and not options.zoom:
150-
options.zoom = zoom
151-
if lat and lon and not options.center:
152-
options.center = [lon, lat]
153-
if (not options.size and not options.size_px and not options.paper
154-
and not options.fit and not options.bbox):
155-
options.size_px = [1280, 1024]
156-
157-
158129
def get_paper_size(name):
159130
"""Returns paper size for name, [long, short] sides in mm"""
160131
# ISO A*
@@ -276,7 +247,7 @@ def run(options, settings):
276247
if settings.bbox and fix_scale:
277248
settings.scale = settings.scale / math.cos(math.radians(settings.transform.backward(settings.bbox.center()).y))
278249
bbox_web_merc = Nik4Image.TRANSFORM_LONLAT_WEBMERC.forward(settings.transform.backward(settings.bbox))
279-
settings.scale = Nik4Image.correct_scale(settings.bbox, settings.scale, bbox_web_merc, settings.bbox)
250+
settings.correct_scale(bbox_web_merc)
280251
# expand bbox with padding in mm
281252
if settings.bbox and options.padding and (settings.scale or settings.size):
282253
if settings.scale:
@@ -438,6 +409,7 @@ def run(options, settings):
438409
else:
439410
log_level = logging.INFO
440411
logging.basicConfig(level=log_level, format='%(asctime)s %(message)s', datefmt='%H:%M:%S')
441-
settings = Nik4Image.setup_options(options)
412+
settings = Nik4Image(options)
413+
settings.setup_options()
442414
logging.info(settings.__dict__)
443415
run(options, settings)

nik4/nik4_image.py

Lines changed: 121 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515

1616
class Nik4Image:
1717

18-
def __init__(self):
18+
def __init__(self, options):
19+
self.options = options
1920
self.need_cairo = False
2021
self.fmt = None
22+
self.ppmm = None
2123
self.scale = None
2224
self.scale_factor = None
2325
self.size = None
@@ -26,132 +28,166 @@ def __init__(self):
2628
self.proj_target = None
2729
self.rotate = None
2830

29-
@staticmethod
30-
def setup_options(options):
31-
settings = Nik4Image()
31+
32+
def parse_url(url, options):
33+
"""Parse map URL into options map"""
34+
lat = None
35+
lon = None
36+
zoom = None
37+
m = re.search(r'[#/=]([0-9]{1,2})/(-?[0-9]{1,2}\.[0-9]+)/(-?[0-9]{1,3}\.[0-9]+)', url)
38+
if m:
39+
zoom = int(m.group(1))
40+
lat = float(m.group(2))
41+
lon = float(m.group(3))
42+
else:
43+
m = re.search(r'lat=(-[0-9]{1,2}\.[0-9]+)', url, flags=re.IGNORECASE)
44+
if m:
45+
lat = float(m.group(1))
46+
m = re.search(r'lon=(-[0-9]{1,3}\.[0-9]+)', url, flags=re.IGNORECASE)
47+
if m:
48+
lon = float(m.group(1))
49+
m = re.search(r'zoom=([0-9]{1,2})', url, flags=re.IGNORECASE)
50+
if m:
51+
zoom = int(m.group(1))
52+
if zoom and not options.zoom:
53+
self.options.zoom = zoom
54+
if lat and lon and not self.options.center:
55+
self.options.center = [lon, lat]
56+
if (not self.options.size and not self.options.size_px and not self.options.paper
57+
and not self.options.fit and not self.options.bbox):
58+
self.options.size_px = [1280, 1024]
59+
60+
def _set_format(self):
61+
# format should not be empty
62+
if self.options.fmt:
63+
self.fmt = self.options.fmt.lower()
64+
elif '.' in self.options.output:
65+
self.fmt = self.options.output.split('.')[-1].lower()
66+
else:
67+
self.fmt = 'png256'
68+
69+
self.need_cairo = self.fmt in ['svg', 'pdf']
70+
71+
def _set_ppm_and_scale_factor(self):
72+
"""
73+
Set properties ppm and scale_factor.
74+
"""
75+
# ppi and scale factor are the same thing
76+
if self.options.ppi:
77+
self.ppmm = self.options.ppi / 25.4
78+
self.scale_factor = self.options.ppi / 90.7
79+
else:
80+
self.scale_factor = self.options.factor
81+
self.ppmm = 90.7 / 25.4 * self.scale_factor
82+
83+
# svg / pdf can be scaled only in cairo mode
84+
if self.scale_factor != 1 and self.need_cairo and not HAS_CAIRO:
85+
logging.error('Warning: install pycairo for using --factor or --ppi')
86+
self.scale_factor = 1
87+
self.ppmm = 90.7 / 25.4
88+
89+
def setup_options(self):
3290
dim_mm = None
33-
settings.rotate = not options.norotate
91+
self.rotate = not self.options.norotate
3492

35-
if (options.ozi and options.projection.lower() != 'epsg:3857'
36-
and options.projection != EPSG_3857):
93+
if (self.options.ozi and self.options.projection.lower() != 'epsg:3857'
94+
and self.options.projection != EPSG_3857):
3795
raise Exception('Ozi map file output is only supported for Web Mercator (EPSG:3857). ' +
3896
'Please remove --projection.')
3997

40-
if options.url:
41-
parse_url(options.url, options)
42-
43-
# format should not be empty
44-
if options.fmt:
45-
settings.fmt = options.fmt.lower()
46-
elif '.' in options.output:
47-
settings.fmt = options.output.split('.')[-1].lower()
48-
else:
49-
settings.fmt = 'png256'
98+
self._set_format()
5099

51-
settings.need_cairo = settings.fmt in ['svg', 'pdf']
100+
if self.options.url:
101+
parse_url(self.options.url, self.options)
52102

53103
# output projection
54-
if options.projection.isdigit():
55-
settings.proj_target = mapnik.Projection('+init=epsg:{}'.format(options.projection))
104+
if self.options.projection.isdigit():
105+
self.proj_target = mapnik.Projection('+init=epsg:{}'.format(self.options.projection))
56106
else:
57-
settings.proj_target = mapnik.Projection(options.projection)
58-
settings.transform = mapnik.ProjTransform(PROJ_LONLAT, settings.proj_target)
107+
self.proj_target = mapnik.Projection(self.options.projection)
108+
self.transform = mapnik.ProjTransform(PROJ_LONLAT, self.proj_target)
59109

60110
# get image size in millimeters
61-
if options.paper:
111+
if self.options.paper:
62112
portrait = False
63-
if options.paper[0] == '-':
113+
if self.options.paper[0] == '-':
64114
portrait = True
65-
settings.rotate = False
66-
options.paper = options.paper[1:]
67-
elif options.paper[0] == '+':
68-
settings.rotate = False
69-
options.paper = options.paper[1:]
115+
self.rotate = False
116+
self.options.paper = self.options.paper[1:]
117+
elif self.options.paper[0] == '+':
118+
self.rotate = False
119+
self.options.paper = self.options.paper[1:]
70120
else:
71-
settings.rotate = True
72-
dim_mm = get_paper_size(options.paper.lower())
121+
self.rotate = True
122+
dim_mm = get_paper_size(self.options.paper.lower())
73123
if not dim_mm:
74-
raise Exception('Incorrect paper format: ' + options.paper)
124+
raise Exception('Incorrect paper format: ' + self.options.paper)
75125
if portrait:
76126
dim_mm = [dim_mm[1], dim_mm[0]]
77-
elif options.size:
78-
dim_mm = options.size
79-
if dim_mm and options.margin:
80-
dim_mm[0] = max(0, dim_mm[0] - options.margin * 2)
81-
dim_mm[1] = max(0, dim_mm[1] - options.margin * 2)
127+
elif self.options.size:
128+
dim_mm = self.options.size
129+
if dim_mm and self.options.margin:
130+
dim_mm[0] = max(0, dim_mm[0] - self.options.margin * 2)
131+
dim_mm[1] = max(0, dim_mm[1] - self.options.margin * 2)
82132

83-
# ppi and scale factor are the same thing
84-
if options.ppi:
85-
ppmm = options.ppi / 25.4
86-
settings.scale_factor = options.ppi / 90.7
87-
else:
88-
settings.scale_factor = options.factor
89-
ppmm = 90.7 / 25.4 * settings.scale_factor
90-
91-
# svg / pdf can be scaled only in cairo mode
92-
if settings.scale_factor != 1 and settings.need_cairo and not HAS_CAIRO:
93-
logging.error('Warning: install pycairo for using --factor or --ppi')
94-
settings.scale_factor = 1
95-
ppmm = 90.7 / 25.4
133+
self._set_ppm_and_scale_factor()
96134

97135
# convert physical size to pixels
98-
if options.size_px:
99-
settings.size = options.size_px
136+
if self.options.size_px:
137+
self.size = self.options.size_px
100138
elif dim_mm:
101-
settings.size = [int(round(dim_mm[0] * ppmm)), int(round(dim_mm[1] * ppmm))]
139+
self.size = [int(round(dim_mm[0] * self.ppmm)), int(round(dim_mm[1] * self.ppmm))]
102140

103-
if settings.size and settings.size[0] + settings.size[1] <= 0:
141+
if self.size and self.size[0] + self.size[1] <= 0:
104142
raise Exception('Both dimensions are less or equal to zero')
105143

106-
if options.bbox:
107-
settings.bbox = options.bbox
144+
if self.options.bbox:
145+
self.bbox = self.options.bbox
108146

109147
# scale can be specified with zoom or with 1:NNN scale
110148
fix_scale = False
111-
if options.zoom:
112-
settings.scale = 2 * 3.14159 * 6378137 / 2 ** (options.zoom + 8) / settings.scale_factor
113-
elif options.scale:
114-
settings.scale = options.scale * 0.00028 / settings.scale_factor
149+
if self.options.zoom:
150+
self.scale = 2 * 3.14159 * 6378137 / 2 ** (self.options.zoom + 8) / self.scale_factor
151+
elif self.options.scale:
152+
self.scale = self.options.scale * 0.00028 / self.scale_factor
115153
# Now we have to divide by cos(lat), but we might not know latitude at this point
116154
# TODO: division should only happen for EPSG:3857 or not at all
117-
if options.center:
118-
settings.scale = settings.scale / math.cos(math.radians(options.center[1]))
119-
elif options.bbox:
120-
settings.scale = settings.scale / math.cos(math.radians((options.bbox[3] + options.bbox[1]) / 2))
155+
if self.options.center:
156+
self.scale = self.scale / math.cos(math.radians(self.options.center[1]))
157+
elif self.options.bbox:
158+
self.scale = self.scale / math.cos(math.radians((self.options.bbox[3] + self.options.bbox[1]) / 2))
121159
else:
122160
fix_scale = True
123161

124162
# all calculations are in EPSG:3857 projection (it's easier)
125-
if settings.bbox:
126-
settings.bbox = settings.transform.forward(mapnik.Box2d(*settings.bbox))
127-
bbox_web_merc = TRANSFORM_LONLAT_WEBMERC.forward(mapnik.Box2d(*(options.bbox)))
128-
if settings.scale:
129-
settings.scale = Nik4Image.correct_scale(settings.bbox, settings.scale, bbox_web_merc, settings.bbox)
163+
if self.bbox:
164+
self.bbox = self.transform.forward(mapnik.Box2d(*self.bbox))
165+
bbox_web_merc = TRANSFORM_LONLAT_WEBMERC.forward(mapnik.Box2d(*(self.options.bbox)))
166+
if self.scale:
167+
self.correct_scale(bbox_web_merc)
130168

131169
# calculate bbox through center, zoom and target size
132-
if not settings.bbox and options.center and settings.size and settings.size[0] > 0 and settings.size[1] > 0 and settings.scale:
170+
if not self.bbox and self.options.center and self.size and self.size[0] > 0 and self.size[1] > 0 and self.scale:
133171
# We don't know over which latitude range the bounding box spans, so we
134172
# first do everything in Web Mercator.
135-
center = TRANSFORM_LONLAT_WEBMERC.forward(mapnik.Coord(*options.center))
136-
w = settings.size[0] * settings.scale / 2
137-
h = settings.size[1] * settings.scale / 2
173+
center = TRANSFORM_LONLAT_WEBMERC.forward(mapnik.Coord(*self.options.center))
174+
w = self.size[0] * self.scale / 2
175+
h = self.size[1] * self.scale / 2
138176
bbox_web_merc = mapnik.Box2d(center.x-w, center.y-h, center.x+w, center.y+h)
139-
settings.bbox = TRANSFORM_LONLAT_WEBMERC.backward(bbox_web_merc)
140-
settings.bbox = settings.transform.forward(settings.bbox)
177+
self.bbox = TRANSFORM_LONLAT_WEBMERC.backward(bbox_web_merc)
178+
self.bbox = self.transform.forward(self.bbox)
141179
# now correct the scale
142-
settings.scale = Nik4Image.correct_scale(settings.bbox, settings.scale, bbox_web_merc, settings.bbox)
143-
center = settings.transform.forward(mapnik.Coord(*options.center))
144-
w = settings.size[0] * settings.scale / 2
145-
h = settings.size[1] * settings.scale / 2
146-
settings.bbox = mapnik.Box2d(center.x-w, center.y-h, center.x+w, center.y+h)
147-
return settings
180+
self.correct_scale(bbox_web_merc)
181+
center = self.transform.forward(mapnik.Coord(*self.options.center))
182+
w = self.size[0] * self.scale / 2
183+
h = self.size[1] * self.scale / 2
184+
self.bbox = mapnik.Box2d(center.x-w, center.y-h, center.x+w, center.y+h)
148185

149-
@staticmethod
150-
def correct_scale(bbox, scale, bbox_web_merc, bbox_target):
186+
def correct_scale(self, bbox_web_merc):
151187
# correct scale if output projection is not EPSG:3857
152188
x_dist_merc = bbox_web_merc.maxx - bbox_web_merc.minx
153-
x_dist_target = bbox.maxx - bbox.minx
154-
return scale * (x_dist_target / x_dist_merc)
189+
x_dist_target = self.bbox.maxx - self.bbox.minx
190+
self.scale = self.scale * (x_dist_target / x_dist_merc)
155191

156192
@staticmethod
157193
def get_argument_parser():

tests/test_map_setup.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ def get_args_str(self):
1919
def get_settings(self, test_str):
2020
test_str += ' ' + self.get_args_str()
2121
options = self.parser.parse_args(shlex.split(test_str))
22-
return Nik4Image.setup_options(options)
22+
settings = Nik4Image(options)
23+
settings.setup_options()
24+
return settings
2325

2426

2527
def test_zoom_and_bbox(self):

0 commit comments

Comments
 (0)