Converting SVG cave maps to Therion th2 format (by Jürgen Bohnert)
Update (10. 06. 2012): Cookbook for conversion of SVG files to th2 format with Inkscape
Update: Check the Inkscape Export Plugin, it's an improved and simple to use version of the converter script.
Therion comes in very handy due to the fact that it produces dynamic maps and supports a bunch of 2D and 3D formats, especially GIS formats like ArcView. Also the generation of 3D maps from 2D maps is very striking. And it is Open Source software …. To me, given all these advantages, Therion is definitely the best cave map drawing tool around and will probably sooner or later be accepted as THE cave map format standard!
One drawback however remains: in the meantime a lot of cave maps have been produced using classic vector graphic drawing packages like Corel Draw, Adobe Illustrator etc…. (just to mention a few) and Therion cannot import these maps…. For example, most of my cave maps were drawn using Corel Draw. As much as I wanted to convert my Corel Draw maps to Therion format, there was previously no practical way of doing so. Redrawing is simply not an option because the data is already available in a digital format so why spend countless redrawing hours meaning twice the drawing work for the same cave?
We have discussed this topic on the Therion mailing list and while I was writing this chapter the new Therion 0.51 release came out - and it has some svg import capability!
Nevertheless, I was experimenting with some algorithms to convert one of my own cave maps, that was drawn with Corel Draw, into Therion th2 map format. Finally, I succeded in doing so with a tiny quick-and-dirty Python script that converts cave maps in svg format to th2 format. So, the more ways of doing it the better! The advantage of my script is, that it can be easily modified by the user for the particular task at hand.
There is still a lot of room for improvement, but I felt that it might be useful to others and have made it available at http://www.cavediving.de/svg2th2.py
I think that it could be a good starting point for a program that sooner or later will be capable of automatically extracting all the necessary data and generating a more or less sophisticated th2 file. One could also easily add some nice Tcl/TK GUI to make it more user-friendly.
I have also put together a short manual which you will find below:
How to convert vector maps to th2 format using svg2th2.py
I will mainly refer to my specific experience with the conversion of Corel Draw 11 maps to Therion th2 format. The workflow might be different for you if you have another software package, which might also mean that you have to considerably alter the Python script to get useful results. Please report your experiences and feel free to ask me if you have any problems.
1. Conversion of proprietary vector graphic formats to svg format
To reverse engineer cave maps one needs a certain understanding of how the cave map vector data is organized in classic vector drawing programs. However, since this is also highly dependent on personal preferences (country - and/or grotto - specific), I will just focus on the way of how this is done in our grotto. Our Corel Draw cave maps basically consist of four different stroke widths of 0.25, 0.35, 0.5 and 0.7 mm. 0.7 mm represents the cave walls, 0.5 pits, countour lines and larger rocks, 0.35 smaller stones etc…… Unfortunately, the classic vector graphic programs do not let you assign specific attributes to a certain cave line which would allow for exporting data separately. However, the newer programs at least allow for organizing data in different layers which partly solves the problem. In my case however, the cave map, that I had to convert, was drawn with an older Corel Draw version, lacking the layer function, so I ended up with only four distinct entities based on stroke width. In this manual I will only describe how to exctract the walls (stroke width 0.7mm) from the Corel Draw map, but you can easily apply this technique to other lines.
Here is the Corel Draw 11 cave map at the very beginning of the conversion process:
To get the right orientation in the final th2 map I had to do two things:
1. perform a 180° rotation of the map 2. flip the map horizontally
Now I saved the file in the proprietary format first and then exported it to the svg format (which Corel Draw and Adobe Illustrator can do easily). Note: if one applies the rotation and flipping to the svg file, one might not get the expected results in the later workflow, since the coordinates are not changed!
Since the svg file produced by Corel Draw 11 is hardly human readable and stores the line data as relative coordinates, one now needs to import the Corel svg file into the free vector graphic software “Inkscape” to convert it to a “plain svg” file. This leads to better readable svg code and stores the line data as absolute coordinates in a format that is very close to the Therion th2 format. Also, “Inkscape” can be used for extracting only the lines of a certain stroke width of interest - in this case the cave walls. The script svg2th2.py works only with such pre-filtered svg files.
2. Extracting lines of a specific stroke width from an svg file using Inkscape
Now that we have imported the Corel Draw svg file into Inkscape, we can extract the lines that represent cave walls. To do so, we have to first save the file in the more readable “plain svg” format provided by Inkscape.
Then the svg source code has to be checked with a simple text editor. We soon come across something like this:
<path d="M 188.5,1675.4563 C 188.5,1675.4563 130.5,1698.4563 90.5,1684.4563 C 51.5,1670.4563 -56.5,1629.4563 -93.5,1631.4563 C -131.5,1632.4563 -152.5,1653.4563 -186.5,1632.4563 C -221.5,1611.4563 -308.5,1600.4563 -309.5,1600.4563" style="fill:none;fill-rule:evenodd;stroke:#1f1a17;stroke-width:71" id="path23236" />
This is what is called a “path” in SVG and is basically describing a cubic Bezier curve in a manner very similar to the organization of Therion Bezier curves.
The “M” stands for “Move to” and is the starting point of each curve. x and y coordinates are separated by a comma. Then after each “C” the x,y coordinates of 2 control points and a target point are given. These coordinates will later be converted to th2 format using the svg2th2.py script. If the lines you are seeing in your own svg file are somewhat different from the format shown here, you will have to modify this script.
Meanwhile however, we need to identify the stroke width of the cave walls in our map. In this case it is easy to identify the correct stroke width since it is the one with the highest number. If you are not sure in the case of your own map, you just have to try it out. Depending on wether you specified mm or pixels during the svg export you might end up with all kinds of weird numbers. In our example the stroke width is given in the “style” line and is 71.
We can now extract the cave walls of this stroke width using Inkscapes “Find” option which you will find under the “Edit” Menu. Note: it is important that the single elements of this vector graphic are completely ungrouped, otherwise this procedure will not work. Here is the dialog box for the line extraction:
If the specific selection of only the cave walls has been successful, we can now use “copy” and “paste in place” (needed if you want to overlay several layers) to transfer these lines to a new Inkscape file that can be saved once again as “plain svg” under the name “cave.svg” (which is recognized by the script). If several layers are to be used, it is the best option, to save each layer in a separate svg file corresponding to a distinct stroke width, e.g. cave0.7mm.svg, and to change the names in the script accordingly.
We can also use this graphical view now to obtain the size of the coordinate box by moving over the borders of this map with the mouse cursor and writing down the coordinate pairs. We will use these to modify our script. Also, the correct zoom adjustement can be derived from the lower right corner of this picture (2% to display the whole cave in one frame). We will come back to these adjustements in the next chapter.
3. Conversion of a line-extracted svg file to Therion th2 format
Now we have a file called cave.svg containing only one line type - in our case the cave walls. We now need to modify our svg2th2.py script using a simple text editor.
Specifically, I am referring to these lines in the script:
therion='''encoding utf-8\n ##XTHERION## xth_me_area_adjust -5000 -11000 6000 12000\n ##XTHERION## xth_me_area_zoom_to 2\n scrap scrap1 -scale [-5000 -11000 6000 12000 0.0 0.0 5 0.0 m]\n\n '''
Here we can adjust the boundaries of the map box (which I found out to extend from -5000,-11000 to 6000,12000) and the best zoom adjustment (2% in my case). Please refer to the Therion manual for more detailed information.
If you have absolutely no clue of what paramaters you should enter, you can also simply use very high values as a “first approach mode” like in the following sample code:
therion='''encoding utf-8\n ##XTHERION## xth_me_area_adjust -100000 -100000 100000 100000\n ##XTHERION## xth_me_area_zoom_to 1\n scrap scrap1 -scale [-100000 -100000 100000 100000 0.0 0.0 5 0.0 m]\n\n '''
Then we need to install Python 2.5 (if not already done so) and run the script in the same folder where cave.svg resides. If all works as predicted we should now obtain a file named “svg_converted.th2” that Therion can directly read.
This saved me countless hours of redrawing work!
The same can now be done for other stroke widths and all the information can be overlayed in Therion.
To make real Therion cave maps, at least two reference survey stations have to be generated in the th2 file. One option would be to import all survey stations directly from the svg file, using another script, however it is generally much easier to add some stations manually to certain cave wall features that are well defined.
After having defined at least two survey stations, one can then easily link the th2 map to the survey data (which in my case simply means importing a WinCompass file, since my raw survey shot data is stored in that format).
Also, I should mention, that all cave data is stored in one single scrap, which is OK for smaller caves, but might lead to severe problems in larger caves. In this case the length of the cave was 860 m which seemed to work reasonably well. However, the Therion authors recommend much smaller scraps. So the best way might be to break up your map into several smaller pieces before you do the conversion.
Dealing with several cave map sections and various stroke width entities at the same time might be a bit cumbersome, so a lot of this process should be automated in the future.
Generally, as I already mentioned, there is a lot of room for improvement.
Please contribute to this project!