The script generates the hillshading for a fixed map area in Switzerland, but you can change this quite easily in the script. You can also change other parameters, like shading (and alpenglow) colors, elevation ranges etc.
The script also demonstrates the power of writing a custom shader. A shader transforms a small part of the digital elevation model (DEM) into a pixel color, based on the elevation, aspect and the slope of that part of the DEM. This way you can write your own hillshading effects function and then supply it to the generator. Here’s how it’s done for Alpenglow.py:
The last parameter of the generate_relief_bitmap function is the shader function, in our case called alpenglow:
# The actual shader function which is called for each pixel of the hillshading bitmap.
# It receives the elevation, the aspect (orientation) of the slope and the steepnes (slope).
def alpenglow(elevation, aspect, slope):
sin_slope = math.sin (slope)
nx = math.cos(aspect) * sin_slope
ny = math.sin(aspect) * sin_slope
nz = math.cos(slope)
direction = dotproduct(nx, ny, nz, lx, ly, lz)
direction = (direction - minDirection) / (1 - minDirection);
if direction < 0:
direction = 0
# This is how we can mix two colors together.
shade_color = shade_base_color.mix (light_color, direction)
if direction > 0.0 and elevation > min_alpenglow_elevation:
elevation_factor = min((elevation - min_alpenglow_elevation) / delta_alpenglow_elevation, 1);
alpenglow_factor = math.pow(direction, 4)
return shade_color.mix (alpenglow_color, elevation_factor * alpenglow_factor).argb;
return shade_color.argb;
UPDATE: my math was buggy, the eggs look a bit different after the correction. Note that the formula fails on very large distances (> 2000 km).
A little Maperitive Python script I was playing with today, showing the line of distance of 3000 km (larger egg) and 2000 km (smaller egg) from my home town of Maribor, drawn on the standard Web Mercator projection map:
I’ve just received the “Oxford Bus & Cycle Map” from Richard Mann (thanks, Richard!). The interesting thing is that it was made from OpenStreetMap data using Maperitive. It’s a stunning beauty, Richard has put a lot of effort into it.
Even though most of Maperitive work I’m doing lately is done in a separate branch that will come out as a brand new Maperitive 2.0 release some time in the beginning of 2012, I do occasionally implement some quick enhancements to the currently “unofficially” released Maperitive beta. I’ve just uploaded a new beta version with a couple of neat features, one of which I will describe in this post (the other will have to wait for the next post).
Subpixel Accuracy
This is an important, although probably not very well known feature Mapnik provides. What is subpixel accuracy? Simply put, it is the ability to set the thickness of the line in fractions of a pixel (image stolen from AGG’s site):
Up until now this was not really possible in Maperitive. Well, you could specify the thickness as, say, 1.3 pixels, but it would be rendered as a line with thickness of one pixel, ignoring the fraction. The reason is simple: Maperitive uses GDI+ library for rendering, which doesn’t do subpixel accuracy (it does support antialiasing, but that’s not enough). Mapnik, on the other hand, uses superior Anti-Grain Geometry (AGG) library (you can read more about it in AGG’s Introduction page, which is very interesting).
Why is subpixel accuracy important? Certain map features require delicacy. In his Cartographic Relief Presentation book Eduard Imhof gives very precise recommendations for elevation contour lines thicknesses. 0.05 to 0.08 mm for black normal contours for map scale 1 : 50,000, as an example. Without subpixel accuracy it is very difficult to come even close to such measures and then you end up with both normal and index contours (the thicker ones) having the same thickness in the rendering:
So given that I cannot directly render lines with subpixel accuracy and using AGG in Maperitive is not a practical solution because of various technical reasons I won’t go into, I’ve more or less given up on this.
The Solution
… Until I came up with a simple but effective trick to achieve subpixel accuracy: render the whole map scaled to (say) three times and then downsample the whole image back to the “normal” scale. Before I delve into details, here’s how the same map looks like using this technique:
I think the difference is obvious: you can now see two distinctive contour line types. Index lines are 1.25 wide, while normal lines have a width of 0.65 pixels.Don’t worry about these numbers, subpixel accuracy is not that precise, but it is precise enough.
The Details
Subpixel accuracy can be tuned for three Maperitive commands:
export-bitmap
export-3d
generate-tiles
All of them have a new subpixel parameter which accepts a positive integer value. This value is used as a scaling factor when rendering. Once the rendering is done, Maperitive uses Supersampling algorithm to resample (downsample actually) the rendering to the scale factor of 1. So for example if you want to generate tiles using subpixel accuracy, you type in something like
generate-tiles minzoom=10 maxzoom=12 subpixel=3
Caveats
What is the best value for subpixel parameter, you may ask? I’ve been experimenting with the value of 3. You could try larger values, although I doubt there will be a noticeable increase in the quality of rendering. The downside of larger values is that Maperitive takes longer to render. This could considerably slow down your tiles generation, so there is a trade-off between the quality and speed (isn’t there always?). Measurements of tile generation speed show that by increasing subpixel value by 1 halves the speed of tile generation. In future this should be mitigated by allowing Maperitive to render tiles using multiple processors.
You should also be aware that if you intend to use subpixel accuracy for exporting large bitmaps, Maperitive has to actually allocate a much bigger bitmap in the process of rendering. So for example if you want to create a 4000x4000 bitmap using subpixel=3, Maperitive will want to allocate a 12000x12000 bitmap in the process and will probably fail due to limitations of GDI+ bitmap size. So there is no free lunch (at least until I figure a way around this problem ;) ).
One final note: interactive map does not use subpixel accuracy since this would make the map rendering pretty slow. In future versions Maperitive will provide some kind of “map quality” / “level of detail” setting, so you’ll be able to control this.
The latest Maperitive beta (download it from here) now contains a new command called export-3d, which generates a 3D mesh using the digital elevation model and places the map texture on top of it. The 3D model is exported into a COLLADA format, which can be imported into various 3D programs (Google SketchUp is the one I mostly used, it’s free).
Quick How-To
The quickest/easiest way to generate a 3D export is to move the map to the area you’re interested in and simply select the Tools | Export To 3D menu command. Maperitive will then generate files in the output/Maperitive3D directory of your Maperitive installation. If you do not load your own OSM vector layer, Maperitive will use OSM tiles, the same ones used to show tne OSM web map.
NOTE: be careful to keep the map area fairly small, otherwise you’ll end up with a 3D model that you won’t be able to import into other software, especially if you don’t have a top-of-the-line computer at your disposal.
Importing Into SketchUp
After opening SketchUp, choose **File | Import…” menu command. NOTE: Before browsing for the file, click on the Options… button and make sure Validate COLLADA file is turned off:
Validation should be disabled because it makes importing unbearably slow, especially for larger models. After you’ve done this, browse to your generated Maperitive3D.dae file and open it.
Depending on the size of your model, you might have to wait for some time for the importing to finish. Sometimes I even have to resort to killing the SketchUp process and regenerating a simpler model.
Configuring SketchUp
After the model has been successfully imported, you may want to tweak a few settings in SketchUp to make the rendering look better:
View | Edge Style | Edge - uncheck this so the edges of surfaces are not shown.
View | Face Style - choose Shaded With Textures to get the best effect.
View | Shadows - check this to turn on the sun shadows.
Tweaking The 3D Model
export-3d command provides additional parameters we can tweak. Type in help-command export-3d into the command prompt and you’ll get the list of those parameters:
COMMAND NAME: export-3d
DESCRIPTION: generates a 3D map from the current map view and saves it to the disk
PARAMETERS:
output-dir=<the directory where output files will be saved> (text, optional)
mesh-points=<the maximum number of points the terrain TIM mesh should have> (integer, optional)
tin-error=<the maximum allowed elevation difference (in meters) when simplifying the terrain TIN mesh (default is 1 meter)> (real number, optional)
width=<bitmap width> (value, optional)
height=<bitmap height> (value, optional)
map-scale=<map scale to use when exporting> (value, optional)
scale=<graphics scale to use when exporting> (value, optional)
dpi=<DPI to use when exporting> (value, optional)
zoom=<zoom level to use when exporting> (value, optional)
Better Bitmap Texture
By setting various bitmap parameters you can increase the resolution of the bitmap and/or the zoom level of the underlying OSM bitmap.
tin-error: this is the maximum error (tolerance) allowed between the actual DEM elevation and the generated model, in meters. The default value is 1 meter and if your model becomes too big to handle, I suggest increasing the tolerance value.
mesh-points: this is the maximum number of points (vertices) the TIN should have. The simplification algorithm starts from a very simple model (just two triangles) and incrementally adds new points to it. Upon reaching the maximum number of points, the algorithm stops (regardless of the tin-error setting). This is a safeguard against the model going wild with too many points. So I suggest experimenting with those two values to get something workable for your case.
Setting The Map Area More Precisely
Instead of relying on the map window to act as your area of interest, you can specify printing bounds (right click on the map) and move them to an exact position of your choice.
Final Notes
This 3D export function is by no means of the same quality as some other OSM 3D projects - you don’t get any 3D objects apart from the terrain model, so don’t expect to see any 3D buildings, trees etc. It is, however, a very simple tool to use (I hope) and it produces an output in a fairly open standard (COLLADA) which can then be tweaked with other software.
The next logical step would be to include the things like roads and buildings as actual 3D objects, but I will leave that for the future since my task list already very full with other features.
Please send me feedback if you find this feature useful (or indeed if you find it crappy). Since all this is beta, expect to find bugs. Also, if you’re more of an expert in 3D field than me, a question for you: can you recommend any (preferably free) tool for raytracing which can consume COLLADA files generated by Maperitive?
A new release of Maperitive (branded as build 2001) is finally here - albeit in beta form. I wanted to release the new stuff I was working on since May, but I didn’t want to wait for everything to be totally finished. But let’s start with some…
Notes about this release you should be aware of
NOTE 1: This beta release will not appear as an update when running the “standard” Maperitive release. It will also not be possible to later auto-update it with a new release when it arrives. I’m working on a revamped auto-updating system and the old updating mechanism has been turned off in beta (that’s why it’s beta). So you will have to download the beta manually, unzip it somewhere, and run Maperitive.exe (on Windows) or Maperitive.sh (on Linux/Mac). I do not recommend overwriting the previous installation, so keep that as your backup.
NOTE 2: there have been some changes in certain Maperitive script commands, so you may need to update your scripts. The changes are mostly in how the bounds are specified when exporting bitmaps or SVGs. More on that later.
NOTE 3: there wasn’t any major bug fixing done for this release. You can see the list of open bugs (it’s not the full list, some old bugs are reported in other places - I will migrate/fix those soon).
NOTE 4: the new GUI features like map elements selection and editing may be a little bit buggy. A lot of time has been invested in making them work as there were some fundamental problems that needed to be solved. Users running Maperitive on Linux/Mac may especially notice certain problems, due to the fact that Maperitive is running through Mono. In any case, please report any problems if you see them and I will do my best to fix them.
New Features
First let me say there aren’t any revolutionary new features in this beta. Most of the work I did was done on the infrastructure code, which will help me introduce cool new things in next releases.
What is new is the way how bounds are specified (bounds specify the geographical extents of Maperitive commands). Up until now, there was only one bounds parameter, but from now on you have geometry bounds and printing bounds.
Geometry Bounds
These are more or less the “old” bounds - you use them to specify the map area to download OSM data for (as an example). Geometry bounds are defined in terms of “min longitude, min latitude, max longitude, max latitude” coordinates. They are shown as a red rectangle with diagonal hatching (see the screenshot above).
Maperitive commands that act on geometry bounds have been renamed to dump-geo-bounds, geo-bounds-use-source, reset-geo-bounds, set-geo-bounds. I haven’t updated the Maperitive documentation for these yet, but you can still use help-command to get the list of supported arguments, like:
help-commands set-geo-bounds
Printing Bounds
Printing bounds are used by export-bitmap and export-svg commands to control the exported map area. What is cool about the printing bounds is that you can specify them in terms of paper size, paper orientation, paper margins, map scale and DPI resolution. This was one of the most requested features - to be able to export a map in terms of physical paper dimensions.
Printing bounds work in two modes: fixed paper mode and free-size mode. In free-size mode you are not bound to a particular paper size, so you can define the bounds in the old way (just like geometry bounds).
Printing bounds are shown as blue dashed rectangle:
New printing bounds commands are set-print-bounds-geo, set-print-bounds-paper and set-print-bounds-view. There is also a new command for setting the paper properties: set-paper.
Why Two Boundary Types?
It may seem a bit complicated two introduce two types of boundaries, but it is necessary precondition for me to be able to introduce map rotation in Maperitive (and support for different map projections). Why? Because once you rotate the map, the geometry bounds rotate, too, so they are useless for any kind of printing boundaries (which need to be rectangles parallel with the screen).
Editing Bounds Visually
There is no need to specify bounds using the command line interface, because there are a couple of new GUI features (which gave me the greatest headache). More on that follows.
Map Context Menu
Yes, the map now has a context menu (finally). So if you want to specify printing bounds, simply right-click on the map and choose Place Printing Bounds Here. Now you have printing bounds placed on the map and selected…
Selecting And Manipulating Map Elements
If you click on the geometry or printing bounds, you can select them - small yellow selection handles appear. You can drag the handles to resize the bounds. If you hold the Shift key, the resizing will maintain the aspect ratio. Hold the Control key and you will be able to resize while maintaining the center point.
Move the mouse a little bit more inside the bounds box and you will be able to move the whole bounds across the map.
Properties Window
The last major new GUI “thingy” is the Properties window. If you right-click on the printing bounds and choose Properties, a tool window will appear that lets you edit the properties. This means you don’t need to mess with command line to specify the paper size, for example.
What Comes Next
As I’ve already mentioned, Maperitive is getting a new updating system. The next “official” release will start using semantic versioning, like 2.4.2 and the old build numbering will be consigned to history. This will enable a more transparent updating system - users will be able to choose whether they want to install unstable releases or wait for the next stable/tested one.
Of course, I plan to fix some bugs too (including the ones that I’m sure you’ll report for this beta release).
Next major features: a better labeling mechanism (collision and duplicates detection, abbreviations…) and maperipy, the Python API and integrated Python scripting.
That’s really. I hope you’ll try the new beta and enjoy it. And don’t hesitate to send me your feedback (positive and/or negative)!
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.
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.
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:
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.
By specifying lflp.min-buffer-space you set the minimum buffer (in pixels) between the street’s end points and the text label.
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.