Skip to content

Commit

Permalink
split Nik4Image.setup_options into multiple methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Nakaner committed Jun 28, 2018
1 parent 2a40f8b commit 70c622d
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 59 deletions.
35 changes: 3 additions & 32 deletions nik4.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,35 +126,6 @@ def prepare_wld(bbox, mwidth, mheight):
]])


def get_paper_size(name):
"""Returns paper size for name, [long, short] sides in mm"""
# ISO A*
m = re.match(r'^a?(\d)$', name)
if m:
return [math.floor(1000 / 2**((2*int(m.group(1)) - 1) / 4.0) + 0.2),
math.floor(1000 / 2**((2*(int(m.group(1)) + 1) - 1) / 4.0) + 0.2)]
# ISO B*
m = re.match(r'^b(\d)$', name)
if m:
return [math.floor(1000 / 2**((int(m.group(1)) - 1) / 2.0) + 0.2),
math.floor(1000 / 2**(int(m.group(1)) / 2.0) + 0.2)]
# German extensions
if name == '4a0':
return [2378, 1682]
if name == '2a0':
return [1682, 1189]
# US Legal
if re.match(r'^leg', name):
return [355.6, 215.9]
# US Letter
if re.match(r'^l', name):
return [279.4, 215.9]
# Cards
if re.match(r'^c(?:re|ar)d', name):
return [85.6, 54]
return None


def xml_vars(style, variables):
"""Replace ${name:default} from style with variables[name] or 'default'"""
# Convert variables to a dict
Expand Down Expand Up @@ -244,7 +215,7 @@ def run(options, settings):
if options.fit:
settings.bbox = layer_bbox(m, options.fit.split(','), settings.proj_target, settings.bbox)
# here's where we can fix scale, no new bboxes below
if settings.bbox and fix_scale:
if settings.bbox and settings.fix_scale:
settings.scale = settings.scale / math.cos(math.radians(settings.transform.backward(settings.bbox.center()).y))
bbox_web_merc = Nik4Image.TRANSFORM_LONLAT_WEBMERC.forward(settings.transform.backward(settings.bbox))
settings.correct_scale(bbox_web_merc)
Expand All @@ -255,7 +226,7 @@ def run(options, settings):
else:
tscale = min((settings.bbox.maxx - settings.bbox.minx) / max(settings.size[0], 0.01),
(settings.bbox.maxy - settings.bbox.miny) / max(settings.size[1], 0.01))
settings.bbox.pad(options.padding * ppmm * tscale)
settings.bbox.pad(options.padding * settings.ppmm * tscale)

# bbox should be specified by this point
if not settings.bbox:
Expand Down Expand Up @@ -409,7 +380,7 @@ def run(options, settings):
else:
log_level = logging.INFO
logging.basicConfig(level=log_level, format='%(asctime)s %(message)s', datefmt='%H:%M:%S')
settings = Nik4Image(options)
settings = Nik4Image(options, HAS_CAIRO)
settings.setup_options()
logging.info(settings.__dict__)
run(options, settings)
62 changes: 36 additions & 26 deletions nik4/nik4_image.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-

import argparse
import math
import logging
import mapnik
import math
import re
from nik4.paper_size import get_paper_size


VERSION = '1.7'
Expand All @@ -15,12 +18,14 @@

class Nik4Image:

def __init__(self, options):
def __init__(self, options, has_cairo):
self.options = options
self.has_cairo = has_cairo
self.need_cairo = False
self.fmt = None
self.ppmm = None
self.scale = None
self.fix_scale = False
self.scale_factor = None
self.size = None
self.bbox = None
Expand All @@ -29,7 +34,7 @@ def __init__(self, options):
self.rotate = None


def parse_url(url, options):
def _parse_url(self, url, options):
"""Parse map URL into options map"""
lat = None
lon = None
Expand Down Expand Up @@ -81,11 +86,34 @@ def _set_ppm_and_scale_factor(self):
self.ppmm = 90.7 / 25.4 * self.scale_factor

# svg / pdf can be scaled only in cairo mode
if self.scale_factor != 1 and self.need_cairo and not HAS_CAIRO:
if self.scale_factor != 1 and self.need_cairo and not self.has_cairo:
logging.error('Warning: install pycairo for using --factor or --ppi')
self.scale_factor = 1
self.ppmm = 90.7 / 25.4

def _set_projections_and_transform(self):
if self.options.projection.isdigit():
self.proj_target = mapnik.Projection('+init=epsg:{}'.format(self.options.projection))
else:
self.proj_target = mapnik.Projection(self.options.projection)
self.transform = mapnik.ProjTransform(PROJ_LONLAT, self.proj_target)

def _set_bbox_with_center_scale_and_size(self):
# We don't know over which latitude range the bounding box spans, so we
# first do everything in Web Mercator.
center = TRANSFORM_LONLAT_WEBMERC.forward(mapnik.Coord(*self.options.center))
w = self.size[0] * self.scale / 2
h = self.size[1] * self.scale / 2
bbox_web_merc = mapnik.Box2d(center.x-w, center.y-h, center.x+w, center.y+h)
self.bbox = TRANSFORM_LONLAT_WEBMERC.backward(bbox_web_merc)
self.bbox = self.transform.forward(self.bbox)
# now correct the scale
self.correct_scale(bbox_web_merc)
center = self.transform.forward(mapnik.Coord(*self.options.center))
w = self.size[0] * self.scale / 2
h = self.size[1] * self.scale / 2
self.bbox = mapnik.Box2d(center.x-w, center.y-h, center.x+w, center.y+h)

def setup_options(self):
dim_mm = None
self.rotate = not self.options.norotate
Expand All @@ -98,14 +126,10 @@ def setup_options(self):
self._set_format()

if self.options.url:
parse_url(self.options.url, self.options)
self._parse_url(self.options.url, self.options)

# output projection
if self.options.projection.isdigit():
self.proj_target = mapnik.Projection('+init=epsg:{}'.format(self.options.projection))
else:
self.proj_target = mapnik.Projection(self.options.projection)
self.transform = mapnik.ProjTransform(PROJ_LONLAT, self.proj_target)
self._set_projections_and_transform()

# get image size in millimeters
if self.options.paper:
Expand Down Expand Up @@ -145,7 +169,6 @@ def setup_options(self):
self.bbox = self.options.bbox

# scale can be specified with zoom or with 1:NNN scale
fix_scale = False
if self.options.zoom:
self.scale = 2 * 3.14159 * 6378137 / 2 ** (self.options.zoom + 8) / self.scale_factor
elif self.options.scale:
Expand All @@ -157,7 +180,7 @@ def setup_options(self):
elif self.options.bbox:
self.scale = self.scale / math.cos(math.radians((self.options.bbox[3] + self.options.bbox[1]) / 2))
else:
fix_scale = True
self.fix_scale = True

# all calculations are in EPSG:3857 projection (it's easier)
if self.bbox:
Expand All @@ -168,20 +191,7 @@ def setup_options(self):

# calculate bbox through center, zoom and target size
if not self.bbox and self.options.center and self.size and self.size[0] > 0 and self.size[1] > 0 and self.scale:
# We don't know over which latitude range the bounding box spans, so we
# first do everything in Web Mercator.
center = TRANSFORM_LONLAT_WEBMERC.forward(mapnik.Coord(*self.options.center))
w = self.size[0] * self.scale / 2
h = self.size[1] * self.scale / 2
bbox_web_merc = mapnik.Box2d(center.x-w, center.y-h, center.x+w, center.y+h)
self.bbox = TRANSFORM_LONLAT_WEBMERC.backward(bbox_web_merc)
self.bbox = self.transform.forward(self.bbox)
# now correct the scale
self.correct_scale(bbox_web_merc)
center = self.transform.forward(mapnik.Coord(*self.options.center))
w = self.size[0] * self.scale / 2
h = self.size[1] * self.scale / 2
self.bbox = mapnik.Box2d(center.x-w, center.y-h, center.x+w, center.y+h)
self._set_bbox_with_center_scale_and_size()

def correct_scale(self, bbox_web_merc):
# correct scale if output projection is not EPSG:3857
Expand Down
30 changes: 30 additions & 0 deletions nik4/paper_size.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import math
import re

def get_paper_size(name):
"""Returns paper size for name, [long, short] sides in mm"""
# ISO A*
m = re.match(r'^a?(\d)$', name)
if m:
return [math.floor(1000 / 2**((2*int(m.group(1)) - 1) / 4.0) + 0.2),
math.floor(1000 / 2**((2*(int(m.group(1)) + 1) - 1) / 4.0) + 0.2)]
# ISO B*
m = re.match(r'^b(\d)$', name)
if m:
return [math.floor(1000 / 2**((int(m.group(1)) - 1) / 2.0) + 0.2),
math.floor(1000 / 2**(int(m.group(1)) / 2.0) + 0.2)]
# German extensions
if name == '4a0':
return [2378, 1682]
if name == '2a0':
return [1682, 1189]
# US Legal
if re.match(r'^leg', name):
return [355.6, 215.9]
# US Letter
if re.match(r'^l', name):
return [279.4, 215.9]
# Cards
if re.match(r'^c(?:re|ar)d', name):
return [85.6, 54]
return None
2 changes: 1 addition & 1 deletion tests/test_map_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def get_args_str(self):
def get_settings(self, test_str):
test_str += ' ' + self.get_args_str()
options = self.parser.parse_args(shlex.split(test_str))
settings = Nik4Image(options)
settings = Nik4Image(options, True)
settings.setup_options()
return settings

Expand Down

0 comments on commit 70c622d

Please sign in to comment.