def determinePaperDimensions(paperSize): # Paper sizes in meter paperSizes = { 'A5': {'width': 0.149, 'height': 0.210}, 'A4': {'width': 0.210, 'height': 0.297}, 'A3': {'width': 0.297, 'height': 0.420}, 'A2': {'width': 0.420, 'height': 0.594}, 'A1': {'width': 0.594, 'height': 0.841}, 'A0': {'width': 0.841, 'height': 1.189}, } millimeters = re.match(r'^(\d+\.?\d*) mm [x×] (\d+\.?\d*) mm$', paperSize) meters = re.match(r'^(\d+\.?\d*) m [x×] (\d+\.?\d*) m$', paperSize) inches = re.match(r'^(\d+\.?\d*) in [x×] (\d+\.?\d*) in$', paperSize) if paperSize in paperSizes: return paperSizes[paperSize]['width'], paperSizes[paperSize]['height'] elif millimeters: return float(millimeters.group(1)) / 1000, float(millimeters.group(2)) / 1000 elif meters: return float(meters.group(1)), float(meters.group(2)) elif inches: return float(inches.group(1)) * 0.0254, float(inches.group(2)) * 0.0254 else: environment.exitError("The paper size should be one of the values %s or of the form `A mm x B mm`, `A m x B m` or `A in x B in`, but %s was given" % (list(paperSizes.keys()), paperSize)) return
def determinePageOverlap(overlap): pageOverlapMatch = re.match(r'^(\d+\.?\d*)%$', overlap) if not pageOverlapMatch: environment.exitError("The page overlap must be a percentage value, like '5%%' or '10.1%%'. %s was given" % (overlap,)) return return float(overlap[:-1]) / 100.0
def determineBoundingBox(bbox): bboxMatch = re.match(r'^(\d+\.?\d*):(\d+\.?\d*):(\d+\.?\d*):(\d+\.?\d*)$', bbox) if not bboxMatch: environment.exitError("The bounding box must be of the form A:B:C:D with (A, B) the bottom left corner and (C, D) the top right corner. %s was given" % (bbox,)) return return float(bboxMatch.group(1)), float(bboxMatch.group(2)), float(bboxMatch.group(3)), float(bboxMatch.group(4)),
def determineScale(scale): if not scale.strip().startswith('1:'): environment.exitError("The scale should be of the form 1:N but %s was given" % (scale,)) return try: return float(scale[2:]) except: environment.exitError("The scale should parsable as a floating point number but got %s" % (scale[2:],)) return
def determineOrientation(orientation): paperOrientations = { ORIENTATION_LANDSCAPE, ORIENTATION_PORTRAIT, } if orientation not in paperOrientations: environment.exitError("The paper orientation should be one of the values %s but %s was given" % (paperOrientations, orientation)) return return orientation
def boundingBoxes(bbox, pageOverlap, scale, paperDimensions): # The bounding box is in degrees # All other distances are in meters paperWidth, paperHeight = paperDimensions pageWidth = paperWidth * scale pageHeight = paperHeight * scale mercatorBoundingBox = latitudeLongitudeToWebMercator.forward(bbox) averageBboxX = bbox.minx + (bbox.maxx - bbox.minx) / 2 averageBboxY = bbox.miny + (bbox.maxy - bbox.miny) / 2 distanceX = haversine((bbox.minx, averageBboxY), (bbox.maxx, averageBboxY)) distanceY = haversine((averageBboxX, bbox.miny), (averageBboxX, bbox.maxy)) if distanceX < 1 or distanceY < 1: environment.exitError("The horizontal and vertical distance of the bounding box is less than 1 meter. Horizontal distance: %.2f, vertical distance: %.2f." % (distanceX, distanceY)) return mercatorMeterPerRealMeterX = (mercatorBoundingBox.maxx - mercatorBoundingBox.minx) / distanceX mercatorMeterPerRealMeterY = (mercatorBoundingBox.maxy - mercatorBoundingBox.miny) / distanceY # If the bounding box fits on one page, then do not use padding epsilon = 1 fitsOnOnePageHorizontal = distanceX <= pageWidth + epsilon fitsOnOnePageVertical = distanceY <= pageHeight + epsilon numPagesHorizontal = 1 if fitsOnOnePageHorizontal else 1 + int(math.ceil((distanceX - pageWidth) / ((1.0 - pageOverlap) * pageWidth))) numPagesVertical = 1 if fitsOnOnePageVertical else 1 + int(math.ceil((distanceY - pageHeight) / ((1.0 - pageOverlap) * pageHeight))) # Fit the generated pages perfectly 'around' the bounding box paddingX = ((numPagesHorizontal * pageWidth - (numPagesHorizontal - 1) * pageOverlap * pageWidth) - distanceX) / 2 paddingY = ((numPagesVertical * pageHeight - (numPagesVertical - 1) * pageOverlap * pageHeight) - distanceY) / 2 boundingBoxes = [] for i in range(numPagesHorizontal): for j in range(numPagesVertical): topLeft = mercatorBoundingBox.minx + mercatorMeterPerRealMeterX * (- paddingX + i * pageWidth - i * pageOverlap * pageWidth), \ mercatorBoundingBox.maxy + mercatorMeterPerRealMeterY * (+ paddingY - j * pageHeight + j * pageOverlap * pageHeight) bottomRight = topLeft[0] + mercatorMeterPerRealMeterX * pageWidth, \ topLeft[1] - mercatorMeterPerRealMeterY * pageHeight tileBoundingBox = latitudeLongitudeToWebMercator.backward(mapnik.Box2d( topLeft[0], topLeft[1], bottomRight[0], bottomRight[1], )) boundingBoxes.append(tileBoundingBox) return boundingBoxes