September 13, 2011
maperipy: Maperitive API for Python - A First Glimpse

A few days ago I started implementing maperipy, a Maperitive API for Python. It turns out to be a quite uncomplicated thing to do, compared to all infrastructure stuff I’m working on for the next Maperitive release, so it’s a kind of a relaxation between all the hard work.

The API is still very young and unsophisticated, but I’m very excited about it, because it could provide a whole new dimension of functionality to Maperitive users.

Here’s a simple Python script that clears the map and then adds a custom Web map to it (with custom copyright text):

from maperipy import MapLayer

map.clear_map();
layer = map.add_web_map_custom(
        "my hiking map", 
        ["http://beta1234.com.sunflower.arvixe.com/maps/tiles"])
layer.copyright = "it's made by me"
layer.opacity = 0.75

Another one, which scrolls the map along the X-axis:

from maperipy import MapPosition
import time

pos = map.position;

for n in range(10):
    map.position = MapPosition(15 + n/10.0, pos.y, 11)
    app.refresh_map()
    time.sleep(0.3)

First versions of maperipy will probably be available after I finish the work on the next major release of Maperitive. Hopefully some time in October.

September 8, 2011
Maperitive Tutorial: Generating OSM Map For Adobe Illustrator In Seven Easy Steps

In this tutorial you will learn how to produce a vector map based on OpenStreetMap data and then export it to SVG format suitable for editing in Adobe Illustrator. SVG export is one of the most useful features Maperitive provides and I’ve spent a lot of time tweaking the code so that Illustrator can handle the exported SVGs.

NOTE: the tutorial has been written for Maperitive build 1228. Some things will change in the near future, so please visit http://maperitive.net for any updates.

First things first: start Maperitive (if you don’t already have it, you can download it from here). Unzip the package somewhere on your disk and run Maperitive.exe (on Windows) or Maperitive.sh (on Linux/Mac).

Step 1: Setting Your Map Limits

Currently Maperitive uses your computer’s memory to store map data, so there is a limit of how large a map it can work on. Because of that, we need to tell Maperitive what area we’re interested in, so all the operations will limit themselves on that area.

There are several ways to set the limits. The easiest is to move the map to the area, zoom in our out appropriately to cover all the area you want, and then use the Map / Set Bounds menu function.

I will do this manually by entering a following command in the command prompt (at the bottom of the screen):

bounds-set -74.03,40.7,-73.96,40.72

I suggest you do the same for the purposes of this tutorial, so our map areas would match. The area in question is lower end of Manhattan.

Step 2: Loading OSM Data

Now we need to get the vector OSM data for our map. There are several ways of doing this.

The easiest one is to use the Map / Download OSM Data menu function, which contacts an OSM server to fetch the data. Try it out. If it fails, try it a couple more times. The problem is that these servers are sometimes overloaded and unresponsive.

If this doesn’t work, another option is to use JOSM or the Export tab on the OSM Web Map site. In that case you will get an OSM XML file, which you need to save on your disk (using .osm extension!) and then load into Maperitive using the File / Open Map Sources menu function (or simply drag and drop the file into Maperitive).

Once the OSM data is in, we can proceed with the next step…

Step 3: Removing The Web Map

Now that we have some vector content of our own, we don’t really need the OSM web map anymore. Select the Web Map (OSM Mapnik) in the Map Sources window at the bottom of the screen and then click on the “X” button to remove it:

Step 4: Changing The Map Style

The default map style resembles the standard OSM Web map layer (generated using Mapnik). But just to show off, we will switch to something that looks like Google Maps. Choose Map / Switch To Rules / googlemaps menu function. After a second or two of processing, the map will change its style.

Step 5: Deciding The Map Scale

Depending on your needs, you can export the map using different map scales. Map scale is directly linked to the zoom level and together they determine what type of content is visible on the map and how the content is rendered. In the case of our Google Maps-like style, the street names are starting to appear on zoom level 15 and higher, so if you need them in your export, you will have to use the zoom level 15 or higher.

The zoom level value is displayed at the bottom of the screen:

The map scale is shown at the bottom left of the map itself, together with the bar scale indicator:

For this tutorial I’ve decided the zoom level 16 is the one I want. Try it out, you can set your own later.

Step 6: Exporting To SVG

The easiest way to export would be to use Tools / Export to SVG (For Adobe Illustrator) menu function. But since we need to specify the zoom level in our case, we will type the export-svg command manually into the Command Prompt:

export-svg compatibility=illustrator zoom=16

We instructed Maperitive to export the current map to a SVG file suitable for Adobe Illustrator and to use zoom level 16. After a couple of seconds a new file called output.svg should appear under the output directory of your Maperitive installation.

Step 7: Import Into Adobe Illustrator

Now that you have a SVG file, open up your AI and import it. If it complains about “roundtrips to Tiny”, simply ignore that.

Adobe Illustrator vs. Inkscape

You may wonder why you had to specify the compatibility=illustrator argument in the Step 6. I will just quote Maperitive documentation on this:

Due to the pretty buggy support which Adobe Illustrator provides for loading SVG files, it is not possible to have the same SVG optimally shown in both Illustrator and Inkscape. In other words, if you plan to use the SVG file in Illustrator, you should specify compatibility=illustrator parameter. Maperitive will in this case do some tweaks to the SVG file which allow it to be shown without any problems in Illustrator (tested in CS5). But do not expect this file to be usable in other SVG viewers/editors.

On the other hand, if you need a SVG file which can be shown in various Web browsers and editable in Inkscape, you should specify compatibility=inkscape parameter. Again, do not expect this file to be usable in Illustrator.

Conclusion

This tutorial shows only the basic workflow, but there are many ways of how the workflow can be customized and even automated (by putting everything into a Maperitive script). Visit http://maperitive.net for more information.

Good luck and enjoy mapping!

May 9, 2011
Line Rendering Artifacts

I’m investigating ways of removing nasty little rendering bugs which occur when Maperitive draws something that should be a continuous polyline, but has to be rendered in several separate segments because these segments belong to different layers of painter’s algorithm.

Here’s the bug under the microscope:

I’ve turned the transparency to visualize the actual endings of several line segments. The bug is in the missing pieces of line/curve at the bottom right.

There are some workarounds for it, but of them are perfect. The first one is setting the line-start-cap : round property:

This removes the artifacts between segments, but you end up with an ugly rounded end of lines.

The next one is setting the line-start-cap property to square value:

Now you’ll have nice square end of lines, but you’ll also have new artifacts between line segment joins.

Other possible solutions:

  • Extending each line segment a pixel or two in both directions.
  • Drawing additional joins between unconnected segments once all layers have been drawn. Could be problematic.
  • Some modification of the painter’s algorithm that would allow rendering of polylines as single continuous segments. Now we’re in the SciFi region.

April 10, 2011
No, It’s Not Google Earth

It’s Maperitive with the new MapQuest OpenAerial map layer, actually. Cooming soon.

April 2, 2011
Maperitive: Python Scripting Introduction

The upcoming release of Maperitive comes with a new and exciting feature: Python scripting.

What I’ll describe here is just an initial introduction of Python into Maperitive and right now is more of an experimental nature. I have great plans with Python, but there is still a lot of work to do and I wanted to release something to users so they can test it out and give some feedback.

Writing Python Functions

In the new release Python scripting can be used to define text labels. Let me give you an example with a piece of Python code:

def cycleLabel(e):
    str_list = []
    for set in e.tagSets:
        if set.hasTag('ref'):
            str_list.append(set['ref'])

    str_list.sort()
    return '+'.join(str_list)

So what does this code do? I won’t go into Python syntax (since I think it’s not that hard to understand for anyone with a little bit of programming inclination), but I’ll explain some basics.

We wrote a nice little function called cycleLabel which receives a map element (e) as an input argument. The function goes through the list of element tags and looks for ref tags, which it then puts into a list. The list is then sorted and transformed into a single string using the plus sign as a delimiter.

The above function can be used to render cycle route names. In OSM these are usually represented using cycle relations. Each route has its own relation, but several routes can share the same OSM way, so we need a way to show all the route names in a single label for that way. This is where the cycleLabel function comes into play.

A name of a route is stored in the ref tag and we collect all ref tags to be able to show them as a single label:

Using Python Code

Once we have our labeling function, we need to tell Maperitive to use it. Here’s an excerpt of rendering rules I used to produce the above map:

import-script:test.py

features
    lines
        cycle route : osmnetwork[type=route]
    ...     
rules
    target : cycle route
        define
            line-width : 3
            line-color : red
        draw : line
        define
            text-func : cycleLabel(e)
        draw : text

The important things are:

  • import-script tells Maperitive to load a Python source file
  • text-func is a new rendering property which you can use to call a Python function to prepare the text label.

In the next post we’ll go through element variable attributes which can be used in Python code to access various properties of the element.

April 2, 2011
Maperitive: Line Feature Label Placement Explained

Line Feature Label Placement

This is a quick description of how Maperitive places labels on line features (streets, rivers etc.). The system is likely to change in the future, so make sure you read the online docs for the latest info.

Currently Maperitive tries to fit the text into the width of the street, but there are several rendering properties (see the Default rules as an example) which control this:

  1. Maperitive ignores any potential text placements which are too winding (= not straight enough). lflp.max-allowed-corner-angle property specifies the maximum angle (in degrees) that’s allowed of any corner for such a label.
  2. By specifying lflp.min-buffer-space you set the minimum buffer (in pixels) between the street’s end points and the text label.
  3. If this minimum cannot be reached, Maperitive tries to condense the font horizontally (but only up to lflp.max-compression value (1 means no compression, 0.5 means the text can be compressed up to 50%).

If none of this works, the label will not be displayed. You cannot directly force a particular label to display itself, but you can lower the quality criteria and thus make more labels visible.

Important thing to note is that you can set these settings both “globally” for the whole stylesheet and you can also override them in each target rule. So you can have different labeling quality settings for different features.

Currently Maperitive does not have a label collision detection (meaning it will not detect two or more overlapping labels). It also does not eliminate label duplicates (which means two or more labels with the same text could end up being displayed next to each other). These and other improvements (text abbreviations, more quality settings) are planned in the near future.

7:01am  |   URL: http://tmblr.co/Zm5Djx3_vjlz
  
Filed under: Maperitive cartography 
March 30, 2011
Fill Textures In Maperitive

Playing with fill textures in #Maperitive. Just some random forest noise:

Coming up in the next release…

March 18, 2011
Python’s try-except-else-finally Block

Started reading IronPython in Action to get acquainted with my language of choice for Maperitive scripting.

While browsing through the book, I noticed a little gem I complained was missing in C# a few days ago (code stolen from here):

try:
    f = open(arg, 'r')
except IOError:
    print 'cannot open', arg
else:
    print arg, 'has', len(f.readlines()), 'lines'
    f.close()

And the explanation for the else clause:

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try … except statement.

So it looks like I’m not that crazy afterall…

March 11, 2011
OSM Relations Or Seven-Headed Monsters

The more I delve into trying to find a good generic way of handling OSM relations in Maperitive, the more I get the feeling it’s a waste of effort. Relations are just too abstract and require some implicit (and external) semantic knowledge for a map renderer to be able to handle them properly.

Example? Look at multipolygon relations on the OSM wiki. They contain a lot of external knowledge that would be very difficult to codify in a map rendering language. I’ve designed Maperitive’s rendering language to be small & simple to use and I want to avoid creating a more general-purpose language out of it. We already have too many languages.

OK, multipolygons are just one example, and maybe not a good one. You can always say multipolygons are exception and should be treated as such by embedding the semantics directly in the code of the renderer. And I agree, and that’s what I did. But more and more people come up with new types of relations and I don’t want Maperitive to become bloated with all kinds of special cases. I strongly believe in Maperitive as a general-purpose renderer (and not only for OSM-type data).

So what’s the solution? I’m not sure yet. For the last few days I’ve been toying with the idea of providing some kind of Python scripting extension for rendering which would enable users to write custom logic for all kinds of special cases without the need to extend the rendering rules language.

It would probably not be as fast, but if you value the custom rendering features above performance, it could be a good solution.

Liked posts on Tumblr: More liked posts »