Image for

3D Printing Map Figurines with GPS

Learning to create 3D models with OpenSCAD has opened a world of possibilities for me. Once I was comfortable with the basics, I wondered what it would look like to push the boundaries of programmatic 3D printing even further. In my day job as a software engineer at Strava, I work with GPS data from running and cycling activities. What if there was a way to bring that data into OpenSCAD to use it in a 3D model?

As I thought about this, I realized there’s actually a pretty easy solution – it wouldn’t be terribly difficult to parse GPS data from a GPX file and print that data as an array into a scad file. Distance and elevation can be represented as an array of numbers in scad, and position (lat/lng) can be represented as an array of 2D points. I decided it would be a fun project to try creating an OpenSCAD model that includes GPS data.

It would be pretty easy to parse a GPX file and produce an array for OpenSCAD in almost any programming language, but I chose Ruby for the task. Aside from the fact that I like Ruby and I’m familiar with it, it’s well-suited for the task because it works as a scripting language, it has a nice XML library (Nokogiri) for parsing GPX files (which are really just XML), and it has a templating language (ERB) that I thought I might use for writing data back to SCAD files.

My initial process was somewhat manual. I hacked together a script to parse elevation data out of a GPX file (using Nokogiri to iterate the correct nodes) and dump it to the console as a JSON array. I manually copied and pasted this array into an OpenSCAD file and then worked exclusively in OpenSCAD for a while to design the model. (It’s fortunate that OpenSCAD array syntax is identical to JSON – that kept things really simple 😅.) It was finicky at first – too few data points and the model looked terrible, but too many data points also looked odd and made rendering unreasonably slow in OpenSCAD. After experimenting a little I found that about 100 data points looked decent with most of my samples.

Getting latitude and longitude working was a little trickier than elevation, but not bad. There are a variety of different projections I could’ve used (to transform latitude and longitude to a 2D surface), but for simplicity I went with an equirectangular projection (treating longitude as x and latitude as y). In OpenSCAD, I represented these points as an array of arrays.

Getting GPX data into an OpenSCAD file is one thing, but making a useful model with it is another. GPX data (lat/lng combined with elevation) is basically a sequence of 3D points, and I needed to assign volume to those points to create a 3D object. For this figurine model, I wanted to represent the GPX path as a line (with changing height to represent elevation). To achieve this, I break the path down to a series of line segments (between two consecutive points). For each segment, I create a quadrilateral prism with the correct height at opposite ends, then translate and rotate that prism into the correct relative position for the model. This approach yielded pretty good results but had some oddities when the angle between any two points was too far from 180. To make that look better, I add a cylinder at each GPX point to fill the gaps, and trim the prism at the ends to avoid odd intersections. The final result isn’t perfectly smooth, but looks great from any reasonable distance away.

A 3D printer creating a GPX figurine

With a working prototype, I cleaned things up and made all the tooling nicer to work with. I tweaked the script to use an ERB template to generate a scad file with the arrays of GPX points, and made a nicer CLI interface for the script. Want to try it yourself? I made the code open source and it’s available on GitHub: mkasberg/3d-gpx-figurines. I hope you enjoy printing your own GPX figurines or riffing on my work to create your own cool 3D project!


Sharing my blog posts is a great way to support me and help my blog grow!

About the Author

Mike Kasberg

👋 Hi, I'm Mike! I'm a husband, I'm a father, and I'm a senior software engineer at Strava. I use Ubuntu Linux daily at work and at home. And I enjoy writing about Linux, open source, programming, 3D printing, tech, and other random topics.