コード例 #1
0
ファイル: street_index.py プロジェクト: ccnz/eqnz-ocitysmap
    def find_bounding_box_by_name(self, db, name):
        """Find the bounding box of a city from its name.

        Args:
            db: connection to the database
            name (string): The city name.
        Returns a BoundingBox object describing the bounding box around
        the given city.
        """

        LOG.info("Looking for rendering bounding box around %s..." % name)

        cursor = db.cursor()
        cursor.execute("""select osm_id, st_astext(st_transform(st_envelope(way), 4002))
                          from planet_osm_line
                          where boundary='administrative' and
                                admin_level='8' and
                                name=%s;""" % \
                           sql_escape_unicode(name))
        records = cursor.fetchall()
        if not records:
            raise UnsufficientDataError, "Wrong city name (%s) or missing administrative boundary in database!" % repr(name)

        osm_id, wkt = records[0]
        LOG.info("Found matching OSMID %s with bounding box %s." % (osm_id, wkt))
        return BoundingBox.parse_wkt(wkt)
コード例 #2
0
ファイル: street_index.py プロジェクト: ccnz/eqnz-ocitysmap
    def find_bounding_box_by_osmid(self, db, osmid):
        """Find the bounding box of a city from its OSM id.

        Args:
            db: connection to the database
            osmid (integer): The city OSM id.
        Returns a BoundingBox object describing the bounding box around
        the given city.
        """

        LOG.info('Looking for rendering bounding box around OSMID %s...' % osmid)

        cursor = db.cursor()
        cursor.execute("""select st_astext(st_transform(st_envelope(way), 4002))
                          from planet_osm_polygon
                          where osm_id=%d;""" % \
                           osmid)
        records = cursor.fetchall()
        if not records:
            raise UnsufficientDataError, "OSMID %s not found in the database!" % repr(osmid)

        LOG.info("Found bounding box: %s" % records[0][0])
        return BoundingBox.parse_wkt(records[0][0])
コード例 #3
0
def main():
    logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

    # Known renderer names
    KNOWN_RENDERERS_NAMES = \
        list(map(lambda r: "%s (%s)" % (r.name, r.description),
            ocitysmap.layoutlib.renderers.get_renderers()))

    # Known paper orientations
    KNOWN_PAPER_ORIENTATIONS = ['portrait', 'landscape']

    usage = '%prog [options] [-b <lat1,long1 lat2,long2>|--osmid <osmid>]'
    parser = optparse.OptionParser(usage=usage,
                                   version='%%prog %s' % __version__)
    parser.add_option('-C', '--config', dest='config_file', metavar='FILE',
                      help='specify the location of the config file.')
    parser.add_option('-p', '--prefix', dest='output_prefix', metavar='PREFIX',
                      help='set a prefix to the generated file names. '
                           'Defaults to "citymap".',
                      default='citymap')
    parser.add_option('-f', '--format', dest='output_formats', metavar='FMT',
                      help='specify the output formats. Supported file '
                           'formats: svg, svgz, pdf, ps, ps.gz, png, and csv. '
                           'Defaults to PDF. May be specified multiple times.',
                      action='append')
    parser.add_option('-t', '--title', dest='output_title', metavar='TITLE',
                      help='specify the title displayed in the output files.',
                      default="")
    parser.add_option('--osmid', dest='osmid', metavar='OSMID',
                      help='OSM ID representing the polygon of the city '
                      'to render.', type="int"),
    parser.add_option('-b', '--bounding-box', dest='bbox',  nargs=2,
                      metavar='LAT1,LON1 LAT2,LON2',
                      help='bounding box (EPSG: 4326).')
    parser.add_option('-L', '--language', dest='language',
                      metavar='LANGUAGE_CODE',
                      help='language to use when generating the index '
                           '(default=en_US.UTF-8). The map language is '
                           'driven by the system\' locale setting.',
                      default='en_US.UTF-8')
    parser.add_option('-s', '--stylesheet', dest='stylesheet',
                      metavar='NAME',
                      help='specify which stylesheet to use. Defaults to the '
                      'first specified in the configuration file.')
    parser.add_option('--overlay', dest='overlays',
                      metavar='NAME',
                      help='comma separated list of overlay stylesheets to use. '
                      'Defaults to none')
    parser.add_option('-l', '--layout', dest='layout',
                      metavar='NAME',
#                      default=KNOWN_RENDERERS_NAMES[0].split()[0],
#                      help=('specify which layout to use. Available layouts '
#                            'are: %s. Defaults to %s.' %
#                            (', '.join(KNOWN_RENDERERS_NAMES),
#                             KNOWN_RENDERERS_NAMES[0].split()[0]))
                     )
    parser.add_option('--paper-format', metavar='FMT',
                      help='set the output paper format. Either "default", '
                           '"Best fit", one of the paper size names '
                           'defined in the configuration file, '
                           'or a custom size in millimeters like e.g. 100x100',
                      default='default')
    parser.add_option('--orientation', metavar='ORIENTATION',
                      help='set the output paper orientation. Either '
                            '"portrait" or "landscape". Defaults to portrait.',
                      default='portrait')
    parser.add_option('--poi-file', metavar='FILE',
                      help='provide a file containing POI information to '
                           'create an index instead of auto-generating it.')
    parser.add_option('--gpx-file', metavar='FILE',
                      help='a GPX track to be put on top of the rendered map.')
    parser.add_option('--umap-file', metavar='FILE',
                      help='a Umap export file to be put on top of the rendered map.')
    parser.add_option('--import-file', metavar='FILE', action='append',
                      help='import file, any of GPX, Umap, GeoJson or POI file, can be used multiple times')

    (options, args) = parser.parse_args()
    if len(args):
        parser.print_help()
        return 1

    # Make sure either -b or -c is given
    optcnt = 0
    for var in options.bbox, options.osmid:
        if var:
            optcnt += 1

    if optcnt == 0:
        parser.error("One of --bounding-box "
                     "or --osmid is mandatory")

    if optcnt > 1:
        parser.error("Options --bounding-box "
                     "or --osmid are exclusive")

    # Parse config file and instanciate main object
    mapper = ocitysmap.OCitySMap(
        [options.config_file or os.path.join(os.environ["HOME"], '.ocitysmap.conf')])

    # Parse bounding box arguments when given
    bbox = None
    if options.bbox:
        try:
            bbox = BoundingBox.parse_latlon_strtuple(options.bbox)
        except ValueError:
            parser.error('Invalid bounding box!')
        # Check that latitude and langitude are different
        lat1, lon1 = bbox.get_top_left()
        lat2, lon2 = bbox.get_bottom_right()
        if lat1 == lat2:
            parser.error('Same latitude in bounding box corners')
        if lon1 == lon2:
            parser.error('Same longitude in bounding box corners')

    # Parse OSM id when given
    if options.osmid:
        try:
            bbox  = BoundingBox.parse_wkt(
                mapper.get_geographic_info(options.osmid)[0])
        except LookupError:
            parser.error('No such OSM id: %d' % options.osmid)

    # Parse stylesheet (defaults to 1st one)
    if options.stylesheet is None:
        stylesheet = mapper.get_all_style_configurations()[0]
    else:
        try:
            stylesheet = mapper.get_stylesheet_by_name(options.stylesheet)
        except LookupError as ex:
            parser.error("%s. Available stylesheets: %s."
                 % (ex, ', '.join(map(lambda s: s.name,
                      mapper.STYLESHEET_REGISTRY))))

    # Parse overlay stylesheet (defaults to none)
    overlays = []
    if options.overlays is not None:
        for overlay_name in options.overlays.split(","): 
            try:
                overlays.append(mapper.get_overlay_by_name(overlay_name))
            except LookupError as ex:
                parser.error("%s. Available overlay stylesheets: %s."
                     % (ex, ', '.join(map(lambda s: s.name,
                          mapper.OVERLAY_REGISTRY))))

    # Parse rendering layout
    if options.layout is None:
        cls_renderer = ocitysmap.layoutlib.renderers.get_renderers()[0]
    else:
        try:
            cls_renderer = ocitysmap.layoutlib.renderers.get_renderer_class_by_name(options.layout)
        except LookupError as ex:
            parser.error("%s\nAvailable layouts: %s."
                 % (ex, ', '.join(map(lambda lo: "%s (%s)"
                          % (lo.name, lo.description),
                          ocitysmap.layoutlib.renderers.get_renderers()))))

    # Output file formats
    if not options.output_formats:
        options.output_formats = ['pdf']
    options.output_formats = set(options.output_formats)

    # Reject output formats that are not supported by the renderer
    compatible_output_formats = cls_renderer.get_compatible_output_formats()
    for format in options.output_formats:
        if format not in compatible_output_formats:
            parser.error("Output format %s not supported by layout %s" %
                         (format, cls_renderer.name))

    # check paper-format option if given
    paper_width = None
    paper_height = None
    if options.paper_format and options.paper_format != 'default':
        matches = re.search('^(\d+)[x\*](\d+)$', options.paper_format)
        if bool(matches):
            paper_width  = int(matches.group(1))
            paper_height = int(matches.group(2))
        else:
            paper_format_names = mapper.get_all_paper_size_names()
            for format_name in paper_format_names:
                name1 = format_name.lower().replace(" ","")
                name2 = options.paper_format.lower().replace(" ","")
                if name1 == name2:
                    options.paper_format = format_name
                    break
            if not options.paper_format in paper_format_names:
                parser.error("Requested paper format %s not found. Compatible paper formats are:\n\t%s."
                             % ( options.paper_format,
                                 ', '.join(paper_format_names)))

    # Determine actual paper size

    if paper_width and paper_height:
        min_width, min_height = cls_renderer.get_minimal_paper_size(bbox)
        if paper_width < min_width or paper_height < min_height:
            parser.error("Given paper size %dmm x %dmm is too small, minimal required size is: %dmm x %dmm" %
                         (paper_width, paper_height, min_width, min_height))
    else:
        compat_papers = cls_renderer.get_compatible_paper_sizes(bbox, mapper)
        if not compat_papers:
            parser.error("No paper size compatible with this rendering.")

        paper_descr = None
        if options.paper_format == 'default':
            for paper in compat_papers:
                if paper['default']:
                    paper_descr = p
                    break
        else:
            # Make sure the requested paper size is in list
            for paper in compat_papers:
                if paper['name'] == options.paper_format:
                    paper_descr = paper
                    break
        if not paper_descr:
            parser.error("Requested paper format not compatible with rendering. Compatible paper formats are:\n\t%s."
                         % ',\n\t'.join(map(lambda p: "%s (%.1fx%.1fcm²)"
                                            % (p['name'], p['width']/10., p['height']/10.),
                                            compat_papers)))
        assert paper_descr['portrait_ok'] or paper_descr['landscape_ok']

        # Validate requested orientation
        if options.orientation not in KNOWN_PAPER_ORIENTATIONS:
            parser.error("Invalid paper orientation. Allowed orientations: %s"
                         % KNOWN_PAPER_ORIENTATIONS)

        if (options.orientation == 'portrait' and not paper_descr['portrait_ok']) or \
           (options.orientation == 'landscape' and not paper_descr['landscape_ok']):
            parser.error("Requested paper orientation %s not compatible with this rendering at this paper size." % options.orientation)

    # Prepare the rendering config
    rc              = ocitysmap.RenderingConfiguration()
    rc.title        = options.output_title
    rc.osmid        = options.osmid or None # Force to None if absent
    rc.bounding_box = bbox
    rc.language     = options.language
    rc.stylesheet   = stylesheet
    rc.overlays     = overlays
    if (options.poi_file):
        rc.poi_file     = os.path.realpath(options.poi_file)
    if (options.gpx_file):
        rc.gpx_file     = os.path.realpath(options.gpx_file)
    if (options.umap_file):
        rc.umap_file    = os.path.realpath(options.umap_file)
    rc.import_files = []
    if options.import_file:
        for import_file in options.import_file:
            import_file = os.path.realpath(import_file)
            file_type = ocitysmap.guess_filetype(import_file)
            rc.import_files.append((file_type, import_file))
    if paper_width and paper_height:
        rc.paper_width_mm  = paper_width
        rc.paper_height_mm = paper_height
    elif options.orientation == 'portrait':
        rc.paper_width_mm  = paper_descr['width']
        rc.paper_height_mm = paper_descr['height']
    else:
        rc.paper_width_mm  = paper_descr['height']
        rc.paper_height_mm = paper_descr['width']

    # Go !...
    mapper.render(rc, cls_renderer.name, options.output_formats,
                  options.output_prefix)

    return 0
コード例 #4
0
ファイル: render.py プロジェクト: hitzi/ocitysmap
def main():
    logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

    # Paper sizes, sorted in increasing widths
    KNOWN_PAPER_SIZE_NAMES = \
        map(lambda p: p[0],
            sorted(ocitysmap.layoutlib.PAPER_SIZES,
                   key=lambda p: p[1]))

    # Known renderer names
    KNOWN_RENDERERS_NAMES = \
        map(lambda r: "%s (%s)" % (r.name, r.description),
            ocitysmap.layoutlib.renderers.get_renderers())

    # Known paper orientations
    KNOWN_PAPER_ORIENTATIONS = ['portrait', 'landscape']

    usage = '%prog [options] [-b <lat1,long1 lat2,long2>|--osmid <osmid>]'
    parser = optparse.OptionParser(usage=usage,
                                   version='%%prog %s' % __version__)
    parser.add_option('-C', '--config', dest='config_file', metavar='FILE',
                      help='specify the location of the config file.')
    parser.add_option('-p', '--prefix', dest='output_prefix', metavar='PREFIX',
                      help='set a prefix to the generated file names. '
                           'Defaults to "citymap".',
                      default='citymap')
    parser.add_option('-f', '--format', dest='output_formats', metavar='FMT',
                      help='specify the output formats. Supported file '
                           'formats: svg, svgz, pdf, ps, ps.gz, png, and csv. '
                           'Defaults to PDF. May be specified multiple times.',
                      action='append')
    parser.add_option('-t', '--title', dest='output_title', metavar='TITLE',
                      help='specify the title displayed in the output files.',
                      default="My Map")
    parser.add_option('--osmid', dest='osmid', metavar='OSMID',
                      help='OSM ID representing the polygon of the city '
                      'to render.', type="int"),
    parser.add_option('-b', '--bounding-box', dest='bbox',  nargs=2,
                      metavar='LAT1,LON1 LAT2,LON2',
                      help='bounding box (EPSG: 4326).')
    parser.add_option('-L', '--language', dest='language',
                      metavar='LANGUAGE_CODE',
                      help='language to use when generating the index '
                           '(default=fr_FR.UTF-8). The map language is '
                           'driven by the system\' locale setting.',
                      default='fr_FR.UTF-8')
    parser.add_option('-s', '--stylesheet', dest='stylesheet',
                      metavar='NAME',
                      help='specify which stylesheet to use. Defaults to the '
                      'first specified in the configuration file.')
    parser.add_option('-l', '--layout', dest='layout',
                      metavar='NAME',
                      default=KNOWN_RENDERERS_NAMES[0].split()[0],
                      help=('specify which layout to use. Available layouts '
                            'are: %s. Defaults to %s.' %
                            (', '.join(KNOWN_RENDERERS_NAMES),
                             KNOWN_RENDERERS_NAMES[0].split()[0])))
    parser.add_option('--paper-format', metavar='FMT',
                      help='set the output paper format. Either "default", '
                           'or one of %s.' % ', '.join(KNOWN_PAPER_SIZE_NAMES),
                      default='default')
    parser.add_option('--orientation', metavar='ORIENTATION',
                      help='set the output paper orientation. Either '
                            '"portrait" or "landscape". Defaults to portrait.',
                      default='portrait')

    (options, args) = parser.parse_args()
    if len(args):
        parser.print_help()
        return 1

    # Make sure either -b or -c is given
    optcnt = 0
    for var in options.bbox, options.osmid:
        if var:
            optcnt += 1

    if optcnt == 0:
        parser.error("One of --bounding-box "
                     "or --osmid is mandatory")

    if optcnt > 1:
        parser.error("Options --bounding-box "
                     "or --osmid are exclusive")

    # Parse config file and instanciate main object
    mapper = ocitysmap.OCitySMap(
        [options.config_file or os.path.join(os.environ["HOME"], '.ocitysmap.conf')])

    # Parse bounding box arguments when given
    bbox = None
    if options.bbox:
        try:
            bbox = BoundingBox.parse_latlon_strtuple(options.bbox)
        except ValueError:
            parser.error('Invalid bounding box!')
        # Check that latitude and langitude are different
        lat1, lon1 = bbox.get_top_left()
        lat2, lon2 = bbox.get_bottom_right()
        if lat1 == lat2:
            parser.error('Same latitude in bounding box corners')
        if lon1 == lon2:
            parser.error('Same longitude in bounding box corners')

    # Parse OSM id when given
    if options.osmid:
        try:
            bbox  = BoundingBox.parse_wkt(
                mapper.get_geographic_info(options.osmid)[0])
        except LookupError:
            parser.error('No such OSM id: %d' % options.osmid)

    # Parse stylesheet (defaults to 1st one)
    if options.stylesheet is None:
        stylesheet = mapper.get_all_style_configurations()[0]
    else:
        try:
            stylesheet = mapper.get_stylesheet_by_name(options.stylesheet)
        except LookupError, ex:
            parser.error("%s. Available stylesheets: %s."
                 % (ex, ', '.join(map(lambda s: s.name,
                      mapper.STYLESHEET_REGISTRY))))
コード例 #5
0
def main():
    logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)

    # Paper sizes, sorted in increasing widths
    KNOWN_PAPER_SIZE_NAMES = \
        map(lambda p: p[0],
            sorted(ocitysmap.layoutlib.PAPER_SIZES,
                   key=lambda p: p[1]))

    # Known renderer names
    KNOWN_RENDERERS_NAMES = \
        map(lambda r: "%s (%s)" % (r.name, r.description),
            ocitysmap.layoutlib.renderers.get_renderers())

    # Known paper orientations
    KNOWN_PAPER_ORIENTATIONS = ['portrait', 'landscape']

    usage = '%prog [options] [-b <lat1,long1 lat2,long2>|--osmid <osmid>]'
    parser = optparse.OptionParser(usage=usage,
                                   version='%%prog %s' % __version__)
    parser.add_option('-C',
                      '--config',
                      dest='config_file',
                      metavar='FILE',
                      help='specify the location of the config file.')
    parser.add_option('-p',
                      '--prefix',
                      dest='output_prefix',
                      metavar='PREFIX',
                      help='set a prefix to the generated file names. '
                      'Defaults to "citymap".',
                      default='citymap')
    parser.add_option('-f',
                      '--format',
                      dest='output_formats',
                      metavar='FMT',
                      help='specify the output formats. Supported file '
                      'formats: svg, svgz, pdf, ps, ps.gz, png, and csv. '
                      'Defaults to PDF. May be specified multiple times.',
                      action='append')
    parser.add_option('-t',
                      '--title',
                      dest='output_title',
                      metavar='TITLE',
                      help='specify the title displayed in the output files.',
                      default="My Map")
    parser.add_option('--osmid',
                      dest='osmid',
                      metavar='OSMID',
                      help='OSM ID representing the polygon of the city '
                      'to render.',
                      type="int"),
    parser.add_option('-b',
                      '--bounding-box',
                      dest='bbox',
                      nargs=2,
                      metavar='LAT1,LON1 LAT2,LON2',
                      help='bounding box (EPSG: 4326).')
    parser.add_option('-L',
                      '--language',
                      dest='language',
                      metavar='LANGUAGE_CODE',
                      help='language to use when generating the index '
                      '(default=en_US.UTF-8). The map language is '
                      'driven by the system\' locale setting.',
                      default='en_US.UTF-8')
    parser.add_option('-s',
                      '--stylesheet',
                      dest='stylesheet',
                      metavar='NAME',
                      help='specify which stylesheet to use. Defaults to the '
                      'first specified in the configuration file.')
    parser.add_option('--overlay',
                      dest='overlay',
                      metavar='NAME',
                      help='specify which overlay stylesheet to use. '
                      'Defaults to none')
    parser.add_option('-l',
                      '--layout',
                      dest='layout',
                      metavar='NAME',
                      default=KNOWN_RENDERERS_NAMES[0].split()[0],
                      help=('specify which layout to use. Available layouts '
                            'are: %s. Defaults to %s.' %
                            (', '.join(KNOWN_RENDERERS_NAMES),
                             KNOWN_RENDERERS_NAMES[0].split()[0])))
    parser.add_option('--paper-format',
                      metavar='FMT',
                      help='set the output paper format. Either "default", '
                      'or one of %s.' % ', '.join(KNOWN_PAPER_SIZE_NAMES),
                      default='default')
    parser.add_option('--orientation',
                      metavar='ORIENTATION',
                      help='set the output paper orientation. Either '
                      '"portrait" or "landscape". Defaults to portrait.',
                      default='portrait')

    (options, args) = parser.parse_args()
    if len(args):
        parser.print_help()
        return 1

    # Make sure either -b or -c is given
    optcnt = 0
    for var in options.bbox, options.osmid:
        if var:
            optcnt += 1

    if optcnt == 0:
        parser.error("One of --bounding-box " "or --osmid is mandatory")

    if optcnt > 1:
        parser.error("Options --bounding-box " "or --osmid are exclusive")

    # Parse config file and instanciate main object
    mapper = ocitysmap.OCitySMap([
        options.config_file
        or os.path.join(os.environ["HOME"], '.ocitysmap.conf')
    ])

    # Parse bounding box arguments when given
    bbox = None
    if options.bbox:
        try:
            bbox = BoundingBox.parse_latlon_strtuple(options.bbox)
        except ValueError:
            parser.error('Invalid bounding box!')
        # Check that latitude and langitude are different
        lat1, lon1 = bbox.get_top_left()
        lat2, lon2 = bbox.get_bottom_right()
        if lat1 == lat2:
            parser.error('Same latitude in bounding box corners')
        if lon1 == lon2:
            parser.error('Same longitude in bounding box corners')

    # Parse OSM id when given
    if options.osmid:
        try:
            bbox = BoundingBox.parse_wkt(
                mapper.get_geographic_info(options.osmid)[0])
        except LookupError:
            parser.error('No such OSM id: %d' % options.osmid)

    # Parse stylesheet (defaults to 1st one)
    if options.stylesheet is None:
        stylesheet = mapper.get_all_style_configurations()[0]
    else:
        try:
            stylesheet = mapper.get_stylesheet_by_name(options.stylesheet)
        except LookupError, ex:
            parser.error("%s. Available stylesheets: %s." % (ex, ', '.join(
                map(lambda s: s.name, mapper.STYLESHEET_REGISTRY))))
コード例 #6
0
def main():
    logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s')

    # Known renderer names
    KNOWN_RENDERERS_NAMES = \
        list(map(lambda r: "%s (%s)" % (r.name, r.description),
            ocitysmap.layoutlib.renderers.get_renderers()))

    # Known paper orientations
    KNOWN_PAPER_ORIENTATIONS = ['portrait', 'landscape']

    usage = '%prog [options] [-b <lat1,long1 lat2,long2>|--osmid <osmid>]'
    parser = optparse.OptionParser(usage=usage,
                                   version='%%prog %s' % __version__)
    parser.add_option('-C', '--config', dest='config_file', metavar='FILE',
                      help='specify the location of the config file.')
    parser.add_option('-p', '--prefix', dest='output_prefix', metavar='PREFIX',
                      help='set a prefix to the generated file names. '
                           'Defaults to "citymap".',
                      default='citymap')
    parser.add_option('-f', '--format', dest='output_formats', metavar='FMT',
                      help='specify the output formats. Supported file '
                           'formats: svg, svgz, pdf, ps, ps.gz, png, and csv. '
                           'Defaults to PDF. May be specified multiple times.',
                      action='append')
    parser.add_option('-t', '--title', dest='output_title', metavar='TITLE',
                      help='specify the title displayed in the output files.',
                      default="")
    parser.add_option('--osmids', dest='osmids', metavar='OSMIDS',
                      help='OSM IDs representing the polygon of the cities '
                      'to render.', type="string"),
    parser.add_option('-a', '--add-polys', dest='addpolys',
                      metavar='ADD_WKTPOLY',
                      help='add Polygon(s) (WktString).')
    parser.add_option('-r', '--remove-polys', dest='subpolys',
                      metavar='REMOVE_WKTPOLY',
                      help='remove polygon(s) (WktString).')
    parser.add_option('--insert-pages-before-index', dest='insert_pages_before_index',
                      metavar='INSERT_PAGES_BEFORE_INDEX',
                      help='insert x pages before index.')
    parser.add_option('--multipage-default-scale', dest='multipage_default_scale',
                      metavar='MULTIPAGE_DEFAULT_SCALE',
                      help='scaling.')
    parser.add_option('--map-first-page-number', dest='map_first_page_number',
                      metavar='MULTIPAGE_MAP_FIRST_PAGE',
                      help='first page-map-number')
    parser.add_option('-L', '--language', dest='language',
                      metavar='LANGUAGE_CODE',
                      help='language to use when generating the index '
                           '(default=en_US.UTF-8). The map language is '
                           'driven by the system\' locale setting.',
                      default='en_US.UTF-8')
    parser.add_option('-s', '--stylesheet', dest='stylesheet',
                      metavar='NAME',
                      help='specify which stylesheet to use. Defaults to the '
                      'first specified in the configuration file.')
    parser.add_option('--overlay', dest='overlays',
                      metavar='NAME',
                      help='comma separated list of overlay stylesheets to use. '
                      'Defaults to none')
    parser.add_option('-l', '--layout', dest='layout',
                      metavar='NAME',
#                      default=KNOWN_RENDERERS_NAMES[0].split()[0],
#                      help=('specify which layout to use. Available layouts '
#                            'are: %s. Defaults to %s.' %
#                            (', '.join(KNOWN_RENDERERS_NAMES),
#                             KNOWN_RENDERERS_NAMES[0].split()[0]))
                     )
    parser.add_option('--paper-format', metavar='FMT',
                      help='set the output paper format. Either "default", '
                           '"Best fit", or one of the paper size names '
                           'defined in the configuration file',
                      default='default')
    parser.add_option('--orientation', metavar='ORIENTATION',
                      help='set the output paper orientation. Either '
                            '"portrait" or "landscape". Defaults to portrait.',
                      default='portrait')
    parser.add_option('--poi-file', metavar='FILE',
                      help='provide a file containing POI information to '
                           'create an index instead of auto-generating it.')
    parser.add_option('--gpx-file', metavar='FILE',
                      help='a GPX track to be put on top of the rendered map.')
    parser.add_option('--umap-file', metavar='FILE',
                      help='a Umap export file to be put on top of the rendered map.')

    (options, args) = parser.parse_args()
    if len(args):
        parser.print_help()
        return 1

    # Make sure either --add-polys or --osmids is given
    optcnt = 0
    for var in options.addpolys, options.osmids:
        if var:
            optcnt += 1

    if optcnt == 0:
        parser.error("--add-polys "
                     "and/or --osmids is mandatory")

    # Parse config file and instanciate main object
    mapper = ocitysmap.OCitySMap(
        [options.config_file or os.path.join(os.environ["HOME"], '.ocitysmap.conf')])

    bbox = None
    osmids = None

    # Parse OSM ids when given
    if options.osmids:
        try:
            osmids = list(map(int, options.osmids.split(",")))
            bbox = BoundingBox.parse_wkt(
                    mapper.get_geographic_info(osmids)[0])
        except LookupError:
            parser.error('No such OSM id: %d' % options.osmids)

    # Parse bounding box arguments when given
    #if options.bbox:
    #    try:
    #        bbox = BoundingBox.parse_latlon_strtuple(options.bbox)
    #    except ValueError:
    #        parser.error('Invalid bounding box!')
    #    # Check that latitude and langitude are different
    #    lat1, lon1 = bbox.get_top_left()
    #    lat2, lon2 = bbox.get_bottom_right()
    #    if lat1 == lat2:
    #        parser.error('Same latitude in bounding box corners')
    #    if lon1 == lon2:
    #        parser.error('Same longitude in bounding box corners')

    # Parse stylesheet (defaults to 1st one)
    if options.stylesheet is None:
        stylesheet = mapper.get_all_style_configurations()[0]
    else:
        try:
            stylesheet = mapper.get_stylesheet_by_name(options.stylesheet)
        except LookupError as ex:
            parser.error("%s. Available stylesheets: %s."
                 % (ex, ', '.join(map(lambda s: s.name,
                      mapper.STYLESHEET_REGISTRY))))

    # Parse overlay stylesheet (defaults to none)
    overlays = []
    if options.overlays is not None:
        for overlay_name in options.overlays.split(","): 
            try:
                overlays.append(mapper.get_overlay_by_name(overlay_name))
            except LookupError as ex:
                parser.error("%s. Available overlay stylesheets: %s."
                     % (ex, ', '.join(map(lambda s: s.name,
                          mapper.OVERLAY_REGISTRY))))

    # Parse rendering layout
    if options.layout is None:
        cls_renderer = ocitysmap.layoutlib.renderers.get_renderers()[0]
    else:
        try:
            cls_renderer = ocitysmap.layoutlib.renderers.get_renderer_class_by_name(options.layout)
        except LookupError as ex:
            parser.error("%s\nAvailable layouts: %s."
                 % (ex, ', '.join(map(lambda lo: "%s (%s)"
                          % (lo.name, lo.description),
                          ocitysmap.layoutlib.renderers.get_renderers()))))

    # Output file formats
    if not options.output_formats:
        options.output_formats = ['pdf']
    options.output_formats = set(options.output_formats)

    # Reject output formats that are not supported by the renderer
    compatible_output_formats = cls_renderer.get_compatible_output_formats()
    for format in options.output_formats:
        if format not in compatible_output_formats:
            parser.error("Output format %s not supported by layout %s" %
                         (format, cls_renderer.name))

    # check paper-format option if given
    if options.paper_format and options.paper_format != 'default':
        paper_format_names = mapper.get_all_paper_size_names()
        if not options.paper_format in paper_format_names:
            parser.error("Requested paper format %s not found. Compatible paper formats are:\n\t%s."
                         % ( options.paper_format,
                             ', '.join(paper_format_names)))

    # Determine actual paper size
    compat_papers = cls_renderer.get_compatible_paper_sizes(bbox, mapper)
    if not compat_papers:
        parser.error("No paper size compatible with this rendering.")

    paper_descr = None
    if options.paper_format == 'default':
        for p in compat_papers:
            if p[5]: # TODO: why 5?
                paper_descr = p
                break
    else:
        # Make sure the requested paper size is in list
        for p in compat_papers:
            if p[0] == options.paper_format:
                paper_descr = p
                break
    if not paper_descr:
        parser.error("Requested paper format not compatible with rendering. Compatible paper formats are:\n\t%s."
             % ',\n\t'.join(map(lambda p: "%s (%.1fx%.1fcm²)"
                % (p[0], p[1]/10., p[2]/10.),
                compat_papers)))
    assert paper_descr[3] or paper_descr[4] # Portrait or Landscape accepted

    # Validate requested orientation
    if options.orientation not in KNOWN_PAPER_ORIENTATIONS:
        parser.error("Invalid paper orientation. Allowed orientations: %s"
                     % KNOWN_PAPER_ORIENTATIONS)

    if (options.orientation == 'portrait' and not paper_descr[3]) or \
        (options.orientation == 'landscape' and not paper_descr[4]):
        parser.error("Requested paper orientation %s not compatible with this rendering at this paper size." % options.orientation)

    # Prepare the rendering config
    rc              = ocitysmap.RenderingConfiguration()
    rc.title        = options.output_title
    rc.osmids       = osmids or None # Force to None if absent
    rc.bounding_box = bbox
    rc.language     = options.language
    rc.stylesheet   = stylesheet
    rc.overlays     = overlays
    rc.poi_file     = options.poi_file
    rc.gpx_file     = options.gpx_file
    rc.umap_file     = options.umap_file
    
    if not options.insert_pages_before_index is None:
        rc.ins_pgs_bef_idx = int(options.insert_pages_before_index) or 0
    
    if not options.multipage_default_scale is None:
        rc.multipg_def_scale = int(options.multipage_default_scale) or Renderer.DEFAULT_MULTIPAGE_SCALE

    if not options.map_first_page_number is None and int(options.map_first_page_number) > 0:
        rc.multipg_frst_map_page = int(options.map_first_page_number)

    if options.orientation == 'portrait':
        rc.paper_width_mm  = paper_descr[1]
        rc.paper_height_mm = paper_descr[2]
    else:
        rc.paper_width_mm  = paper_descr[2]
        rc.paper_height_mm = paper_descr[1]

    if options.addpolys:
        rc.addpolys = options.addpolys

    if options.subpolys:
        rc.subpolys = options.subpolys

    # Go !...
    mapper.render(rc, cls_renderer.name, options.output_formats,
                  options.output_prefix)

    return 0