Easy (or at least straightforward) Terrain Relief Models

Easy (or at least straightforward) Terrain Relief Models

I promised to write up my process for making high-resolution terrain relief model carvings. This is how I currently do it. The process is easy enough that I can prepare a new area in just a few minutes, and for a 150-170mm square carving with a 1/4" ball nose roughing pass and a tapered mill finishing pass at a stepover of 0.25mm or so, the machine time is somewhere in the 2-3 hour range. So, on to the instructions.

Preparing Your Digital Workspace

I spent some time dialing in a workflow for creating my to-scale high-resolution terrain relief models. You may prefer to follow a different process, but by documenting mine, I figure you may have a better place from which to launch into your own tweaks and optimizations. So, to start off, what do I use?

  1. My Relief Model Tools spreadsheet.
    Not necessary, but I attempted to make the mathy bit of the process as smooth as possible.
  2. Digital Elevation Model (DEM) data from USGS.
    In the USA, we have access to lots of free public domain data, so I have not investigated other sources.
  3. QGIS 2 and the DEMto3D plugin.
    A great tool for working with DEM data, and free.

    There is a port of the DEMto3D plugin to QGIS 3, but it is not completely functional at last check. It suffers from UI issues that make it much more difficult to use, and since QGIS 2.18 works fine, I have yet to spend the time to grok the new code.

  4. Meshmixer.
    Used to correct model aspect ratio and optionally add a border (e.g. for style or for making models from multiple physical tiles).
  5. PixelCNC.
    I like it for doing relief models. It’s got some rough edges and such, but it’s inexpensive and very quick to work with.

    You can also use MeshCAM if you have it. I downloaded it for a trial, but I have not purchased it. I cannot say whether the generated toolpaths would be better than those from PixelCNC, but it is definitely slower at processing the data.

  6. Carbide Motion.
    Any G-code sender will work, but the probing example at the end describes Carbide Motion v4 specifically to illustrate the procedure.

Defining Your Map Area

Obviously, step one of any relief modeling project is defining the area you want to model. If you’re looking at a general area, you can just choose the corners of a rectangle and jot down the coordinates. (This can be done in practically any mapping program or even with paper maps.) On the other hand, if you’re looking to make a “souvenir” relief model of a particular place including various waypoints, you’ll want to find the northernmost, southernmost, easternmost, and westernmost points. From there, you can easily add margins.

If you don’t spend your days in maps and coordinates, there’s a simple method to collect the relevant data from Google Maps. Just go to each point you want to have on your model. In a web browser, right-click and choose “What’s here?” from the menu. The coordinates for that point will be displayed at the bottom of the little info box. If you’re in Google Maps on your phone, long-press on the point to drop a pin, and the coordinates of the pin will be displayed in the search bar. Using any method you find convenient, collect the coordinates of all your points (not bothering with any that you know are in the middle of your desired map). Then just independently take the highest and lowest values for the latitude and for the longitude, and you’ve got your target rectangle.

The way I like to work a project is to start by finding the basic bounding box (northernmost, southernmost, easternmost, and westernmost coordinates). Then I go to the spreadsheet and set “Calculate from:” to “Two corner points”. I enter the two latitudes and two longitudes. That gives me the coordinates of the center point and the height and width of my selection (measured N-S and W-E across the center point, respectively). With the center coordinates in hand, I copy them up to the “Center Point and Size” section and change the “Calculate from:” to “Center point and size”. I can round the height and width up to nice round numbers, adding however much margin I feel looks good (and defining the aspect ratio of the carve). With that, the results box updates to show the four bounds I need to use in the next steps.

Acquiring Your Elevation Data

Go to The National Map’s download system: https://viewer.nationalmap.gov/basic/

On the right side above the map, choose “Coordinates” and enter your four values as the pair of latitudes and longitudes. The map will zoom to a highlight box showing the area you’ve specified.

On the left side, click “Elevation Products (3DEP)” under “Data”. Now use the “Show Availability” links to find the best data available. Start with “1 meter DEM”, and if your area is covered, it will be shaded. If you’re not covered, try “1/9 arc-second DEM” next, as it’s more or less a third the resolution of “1 meter DEM”. If you’re still not covered, try “1/3 arc-second DEM”, which basically covers the entire US with something approximating 10m resolution. Some of the formats only provide IMG output, but if you do have an option for “File Format”, you will want to explicitly choose IMG (Erdas Imagine Image), as it will be the most convenient.

If you’re making a relief map of a large area and using a 1/4" ball nose mill, you probably don’t want to bother with the 1 meter DEM data. You don’t need that much detail, so why would you want to download gigs of data you’re just rounding off. On the other hand, if you’re wanting to make a model of just one smallish mountain and you have 1-meter coverage, rejoice! I personally start with the best data I can, since hard drive space is cheap and download speeds aren’t bad these days.

With your search area highlighted and your preferred DEM variety chosen (as an IMG file), now click the “Find Products” button to do your search. On each result, you can click the “Footprint” link in the “Actions” column to see what that file covers. Choose a data set that covers your selected area, or as many as it takes to cover everything. If your area is split across multiple data sets, you’ll have to do an extra step to combine the data later, but no worries. Download the data, and extract the zip file or files to a folder of your choosing.

Using QGIS To Prep Your DEMs

If you have QGIS 2 and the DEMto3D plugin already installed, open QGIS. If you don’t have it yet, go to https://qgis.org/ to download and install QGIS 2.18. Use the “QGIS Standalone Installer Version 2.18” link, as that installs in just one step (compared to however many it takes to get your desired results via the Network Installer). Then open QGIS and choose “Manage and Install Plugins” from the “Plugins” menu. Search for and install the DEMto3D plugin – you don’t even need to restart QGIS.

If you had to download multiple files to cover your selected area, you’ll need to merge the data before you continue. I like to start by putting all my source IMG files in one folder. Either copy the IMG files (the largest file in each zip), or just dump the full contents of all the zip files into the same folder. (Some files will overwrite others, but the data we care about is in the IMG files, which all have unique names.) With all the IMG files in the same folder, it’s time to merge:

  1. Go to QGIS and click the “Raster” menu, go down to “Miscellaneous”, and choose “Merge…”.
  2. Click the select button next to the “Input files” box, change the file type drop-down from “All Files (*) (*.*)” to “Erdas Imagine Images (*.img) (*.IMG)”. Then select all your IMG files.
  3. Click the select button next to the “Output file” box and choose where to save your merged file, being sure to set “Save as type:” to “Erdas Imagine Images (*.img) (*.IMG)”.
  4. Leave all the other settings unchecked, except “Load into canvas when finished”, which just saves you from having to load your merged DEM data.
  5. Click OK to start the merge, then OK when it finishes, and so on all the way back to the main screen. (You can skip the next paragraph – your layer’s already loaded.)

To load your DEM data, click the “Layer” menu, go down to “Add Layer…”, then select “Add Raster Layer…”. Change the type drop down (bottom, far right) to “Erdas Imagine Images (*.img *.IMG)”, then go to where you extracted the zip file (or saved your merged data) to select and open your data file. It’s generally the largest file in the folder, by far. You should now see it displayed as a greyscale height map.

To make things as convenient as possible when generating the model, I like to clip the part of the layer I’m planning to work with.

  1. From the menu bar, click “Raster”, go down to “Extraction”, and choose “Clipper…”.
  2. If you have multiple layers loaded, be sure “Input file (raster)” is the layer you’re working with.
  3. Then click “Select…” by the “Output file” box to choose your output file. Choose a folder, give it a name, and of course, save it as an “Erdas Imagine Images (*.img) (*.IMG)” file.
  4. Click “Save” to return to the Clipper dialog box.
  5. Be sure “Clipping mode” is set to “Extent”.
  6. Take your latitude and longitude bounds (e.g. from the spreadsheet you worked in earlier) and enter them in the four boxes: X is longitude, and Y is latitude.
  7. Leave “Load into canvas when finished” checked, and your clipped layer will automatically be loaded. (It will also be saved where you specified, so if you want to come back and redo your model, you’ll be able to load it and skip all the earlier steps.)

Creating Your 3D Model

With your data all merged, loaded, and clipped, you’re ready to turn your selected layer into a 3D model saved as an STL file.

  1. Start DEMto3D and select your layer:
    1. Click the “Raster” menu, go down to “DEMto3D”, and select “DEM 3D Printing”.
    2. If you have multiple layers loaded, be sure the “Layer to print” drop-down box shows the one you’re working with.
    3. Click the “Select layer extent” button (looks like a four-arrowed cross) and choose your clipped layer from the list. The X and Y boxes will be filled in, and you’ll see a red selection box around your layer. Now we fill in the other boxes.
  2. Fill in the details:
    1. In the “Length (mm):” box, fill in the final physical size of your model along what a Shapeoko calls the X axis.
    2. Ignore the “Width (mm):” field – the model height scales with the length field, and DEM data in arc-seconds is distorted and must be stretched (a later step) to make it square in distances.
    3. Leave the “Exaggeration factor:” field at 1.0 so you get a true model – we’ll do any expansion or compression later.
    4. In the “Height base” section, choose a value for the bottom of your model and fill in the “Height (m):” field – I always copy the value displayed as “Lowest point:”.
    5. Now, go back up and enter a value for “Spacing (mm):” in the “Model size” section. This defines the detail in your 3D model STL file. (Think of it as something like stepover, so if you’re planning to use a 1mm stepover, there’s no reason to use a 0.2mm spacing. The STL files can get quite large with small spacings.)
  3. Copy numbers into the spreadsheet:
    1. Go back to the spreadsheet and scroll down to the section under “Part Two: Model Scaling”.
    2. Copy the values for length, base height, lowest, and highest.
    3. Feel free to ignore the width value, as it is not used.
  4. Save your STL file:
    • Click the “Export to STL” button to save your model. This can take a few minutes if you’ve got a big model and a small spacing. Once your model is saved, we’re done with DEMto3D and QGIS, and we’re off for a quick trip through Meshmixer.


If you don’t have Meshmixer yet, go to http://meshmixer.com/ to download and install it. Open Meshmixer, and click “Import” to load your newly created STL from wherever you had DEMto3D save it.

First, we need to fix the stretch/squish that came from the file being scaled in lat/lon and not distances. Click “Edit” and choose Transform. Look at the Size X, Size Y, and Size Z values. What you entered as “Length” should be there as the “Size X” value. Now, click on the number next to “Size Z” and replace it with the value for “Model Width” on the bottom of the spreadsheet, being sure “Uniform Scaling” is not checked. You have now successfully scaled the model.

My process of carving the model carves it into a piece of wood, leaving a nice uncarved border around it. If you want to have the surroundings low instead of high, we can do that with a quick bit of Meshmixing:

  1. With your model selected, click Edit and choose “Align”. This centers your model.
  2. Click “Meshmix”, then drag one of the solid primitives to the work area. (I generally use the cube.)
  3. In the Transform dialog that pops up, fill in the three size values (noting that Y and Z are swapped compared to your CNC axes). You can use the “Model Width” and “Model Height” values on the bottom of the spreadsheet as a reference when you’re adding a “border” like this.
  4. For the “Size Y” (CNC Z) value, note that DEMto3D always adds 2mm to the bottom of the model, using 2mm as the “Size Y” value will make the top of your border the same CNC Z height as the lowest point.

If you want to make a large relief map out of tiles, you can use something less than 2mm as your border. Cut the tiles out on the border and sand off any remaining lip so the tiles fit together just right.

  1. With your added piece selected, click Edit and choose “Align”. It is now also centered.
  2. Hold Shift, click to select both the new piece and your terrain model, then click “Combine”.
  3. Your combined model with border is now ready for export.

With your model’s aspect ratio corrected and any optional border added, you’re ready to save. Click “Export”, and in the “Save as type:” drop-down menu, choose “STL Binary Format (*.stl)”. Give it a name and click save, and you’re done with Meshmixer.

PixelCNC reads binary STLs but not ASCII STLs (like DEMto3D generates), so even if you’re not adding a border or fixing the aspect ratio, you’ll need to import the STL into Meshmixer and export as a Binary STL. If you try to load an STL into PixelCNC and it chokes on it, it’s probably an ASCII STL, so just import into Meshmixer and export as a Binary STL to make everything happy.


Open PixelCNC version 1.30 or later, which is available for purchase at https://deftware.itch.io/pixelcnc (or skip this section and use MeshCAM if you have strong feelings that way). If this is a new install, go to “Config”, choose “CNC/CAM Settings”, and select your “Units of Measure” and “Post-Processor”. (“Millimeters” and “GRBL (Metric).txt” for me.)

Load and Scale the Model

  1. Click “Import Model”, then choose the binary STL you just saved.
  2. Click “Input Size & Origin”.
  3. Set the X-Width to your value for “Model Width” from the spreadsheet, or use the final size if you added a border in Meshmixer. (The model will be scaled uniformly in X and Y.)
  4. Set the Z-Depth to your value for “Model Height” from the spreadsheet. (Adding a border the way it’s described above in the Meshmixer section does not change this value.)

If you want to compress or exaggerate the Z axis, change the “Relief Scale Factor” in the spreadsheet. It will show you the resulting values for “Model Height” and “Total Cut Depth” (which does not include any border you may have added in Meshmixer). Use the scaled value here for Z-Depth.

  1. I like setting the “Z-Offset” to 100%, which sets Z0 as the top of the carve, as that makes the output independent of stock thickness.

Do Your CAM Magic

  1. Define your cutting tools. Ball nose mills are type “Cylinder” with a “Corner Radius” set.
  2. Then define your milling operations. (I like to do a “horizontal” operation to rough it out using a large ball nose mill and leaving a small amount of stock, then follow with a small tapered or ball nose mill to cut in the detail.)
  3. Check the simulation, et cetera.
  4. Click “File” and select “Export G-Code”.

Split The G-Code!

PixelCNC (at least as of v1.30) saves the entire job in a single G-code file, but if you’re using more than one tool (of course you are), you’ll want to split things into separate files. In the G-code file, the section for each tool begins with two lines like “( Tool: 1 )” and “T1 M6” and ends with the lines “( Spindle: STOP )” and “M5”. (Using a different post-processor can change things, of course.) Just save one file for each tool change, cutting out the rest of the (Tool) to (Spindle: STOP) blocks – leave everything before the first (Tool) line and everything after the last (Spindle: STOP)/M5 line. Hopefully an update to PixelCNC will let you export G-code split into files per tool, but it’s just big text files.

On Windows, if you’re not using Notepad++, let me just say that it’s one of the first things I install on a new machine. It’s free, GPL, and just plain great for text editing, even before you start installing fancy plugins.

With that, you’re ready to roll. What a relief!

Notes On Probing

As noted above, I prefer to set my Z0 to top of stock, but since a relief model carve generally involves removing the top, that does mean that setting Z0 requires a little two-step to make tool changes easy and straightforward. This is how I handle it. There are two cases. For Case 1, the stock is too tall for the probe block to fit between the stock and the tool. For Case 2, there is room to fit the probe. (These instructions look long, but that’s just because I’m being extra thorough about going step by step through them.)

Case 1:

  1. Set the probe block on the leveled wasteboard next to the stock.
  2. Probe for Z. Carbide Motion sets Z0 as the surface of the wasteboard and moves to Z+31mm.
  3. Jog to the vicinity of what will be the highest point of your relief model (or just use anywhere if you’re confident the stock is flat and level).
  4. Manually jog down until your tool tip touches the stock (using the paper trick, backlighting, or whatever other method you prefer).
  5. Write down the currently displayed Z value.
  6. Rezero your Z right here, and run your first toolpath.
  7. After changing to a new tool, set the probe block back on your leveled wasteboard, as you did in step 1.
  8. Probe for Z. Carbide Motion jogs up to Z+31mm.
  9. Jog your Z axis to the value you wrote down in step 5.
  10. Rezero your Z right here, and run your next toolpath. Repeat from step 7 as necessary.

Case 2:

  1. Set the probe block on the leveled wasteboard next to the stock.
  2. Probe for Z. Carbide Motion sets Z0 as the surface of the wasteboard and moves to Z+31mm.
  3. On the “Set Zero” page, click “CLEAR ALL OFFSETS”.
  4. Write down the new value for Z, which will be some negative number.
  5. Set the probe on what will be the highest point of your relief model (or just use anywhere if you’re confident the stock is flat and level).
  6. Probe for Z. Carbide Motion sets Z0 as the surface of the stock and moves to Z+31mm.

If your stock is too tall for the automatic jog to Z+31mm after probing for Z on top of your stock, use the Case 1 instructions.

  1. On the “Set Zero” page, click “CLEAR ALL OFFSETS”.
  2. Write down the difference in the two Z values (e.g. subtract either from the other, and use the absolute value).
  3. Set the probe block on the leveled wasteboard next to the stock.
  4. Probe for Z. Carbide Motion jogs up to Z+31mm.
  5. Jog your Z axis to the value you wrote down in step 8.
  6. Rezero your Z right here, and run your next toolpath. Repeat from step 9 as necessary.

Examples and Resources

Mount LeConte on a piece of scrap pine 2x6.

Mount Saint Helens on a piece of scrap pine 2x6.

Part of Sequoia/Kings Canyon National Parks (Mineral King is near the bottom left) on a piece of scrap pine 2x6.

Part of the Grand Canyon on a piece of red oak 1x8. The North Rim Visitor Center is top center. This was by request of a coworker who hiked rim-to-rim (and back, I believe) on the Bright Angel Trail.

ReliefModelTools.zip (7.8 KB) – The same as the Google Sheets spreadsheet, but exported to Excel format to provide an offline reference version.


This might save a few steps:

1 Like

Not at all, actually. That’s where I started, but it has a resolution of 90m on the equator. For Mount LeConte, I had almost two orders of magnitude better resolution, and even for the 1/3 arc-second resolution DEMs (the common denominator size that has basically full coverage of the USA), that’s still nearly an order of magnitude better resolution than the SRTM3 dataset.

If you’re doing a large area relief model, sure, the SRTM3 dataset is cromulent, and you’ll likely be exaggerating the elevation, too (as elevation simply doesn’t scale over large distances). On the other hand, if you’re doing a very local area, such as what you might hike in a day trip or a few days in a loop backpacking, the SRTM3 dataset just doesn’t cut it. You need high resolution DEM data to get the detail you need, and instead of exaggerating elevation, you may have to either compress it or expand your model’s extents to get it within your available parameters.

For example, for some of the the 2x6-style carves, if I use a 1/8" ball nose mill, I have to really push how little I leave in the collet if I want it to have enough reach to get to the deepest elevations. I switched to a 1/4" tapered mill with a 0.5mm or so tip radius, as that gives me much more reach with even better detail for terrain models, which generally speaking have slopes that are much less vertical than the tapered mill’s sides.

I should actually do a local area carve, like the Alum Trail on Mount LeConte, in both the SRTM3 dataset and the 1 meter DEMs, just to get a physical example of the difference to see exactly what the difference is.

(On further review, it appears the SRTM3 dataset in North America is 1 arc-second resolution, which quite simply is three times less detailed than the 1/3 arc-second DEMs, obviously, so about 30 times less detailed than the 1 meter DEMs where available.)


Wow, that’s really good information to know!

Since I’m not sure if this is appropriate format to do this or if you could use the same tools but open source digital data for Canada appears to be available here: High Resolution Digital Elevation Model (HRDEM) - CanElevation Series - Open Government Portal

1 Like

Okay, just for comparison, I grabbed the Alum Cave trail at 1 meter resolution DEM. Of course, they were in UTM, not lat/lon, so I had to resort to my orienteering experience. Anyway, here’s the same spot (as close as I could get it) from the Terrain2STL site and from USGS 1 meter DEM data.

That’s 1,486,980 vertices and 2,973,956 triangles in the model from the 1 meter DEM data, and 1760 vertices and 3356 triangles in the STL from Terrain2STL. Yeah, if you’re trying to do a local model of just one trail, I think the do-it-yourself method may be slightly better. :joy:


It looks like most of the coverage is up in the arctic, but the footprints show some scattered data availability at lower latitudes. Where there is data, QGIS should be able to load it. Sadly, it doesn’t look like anything around the Sea-To-Sky Highway in British Columbia. I’d love to do a carving of that, as it was utterly breathtaking to drive through on my way to the Alaska Highway as I headed to the Arctic Ocean on a quick road trip… wow… 15 years ago. It’d have to be high resolution data to capture those mountains.

1 Like

When you have comments and info, you should probably put this on the Wiki for future reference. These message boards are not optimal for later reference.


Incidentally, if someone experienced with MeshCAM, VCarve, or any other STL-loading CAM software would be amenable, I know I for one would be very interested in any reports of the experience of doing the CAM portion of the workflow using other software. I briefly had an active trial of MeshCAM, but being unfamiliar with it, I can only say it seemed to work (albeit very slowly compared to PixelCNC). I have zero experience with VCarve (Desktop or Pro, or with Aspire, for that matter).

The model is actually fairly simple, as it’s just a simple 3D carve of a flat piece of stock, using whatever toolpaths you come up with. The catch is that the STL file for a model with high-resolution detail is very large. For the Grand Canyon Bright Angel Trail model, the ASCII STL generated by DEMto3D was almost half a gig, and the Binary STL after the Meshmixer step was still 111MB. There are 1,170,976 vertices and 2,341,948 triangles in the mesh.

It probably wouldn’t be polite to upload the STL file here, as even zipped, it’s still 26MB. I’ve temporarily uploaded it to one of my servers, however, and I’ll gladly send the link in a message to anyone willing to try out doing the CAM in MeshCAM, VCarve, or whatever. The model is just a single STL file, 170mm by 170mm by 18.39mm tall (16.39mm of carving depth, plus the 2mm base DEMto3D adds), and I just carved one with a 1/4" ball nose bit to rough it out and a 1/4" tapered mill (0.75mm tip radius, 31.75mm flute length, 4.36° taper).

So, if anyone is willing to try just playing with toolpaths on a large, detailed STL, please say so. (It’d be nice to actually try running the jobs, but even just a report of how the software handled loading a large STL and generating toolpaths on it would be valuable data.)

For comparison, I just did a full run through PixelCNC. From looking at a just-launched PixelCNC screen, I loaded the STL, set the sizing, defined the two tools, created two operations (a horizontal, i.e. constant depths, roughing job and a parallel, terrain-following finishing job along a 45° angle between X and Y), looked at the previews, and exported the G-code. I’ve had a bit of practice, but it took under three minutes, total. (That doesn’t include separating the saved .nc file into two, one for each tool, but if that takes 30 seconds, I should turn in my text editor license.)

I have nothing to judge the quality or efficiency of the generated toolpaths, but they seem to have been working well enough for hobbyist me. If I were cranking out dozens of these for an Etsy store or something, screen time would be of minimal concern compared to machining time, but when I just want to get a job running and get back to rewatching The Expanse, screen time gets weighted heavily as long as machining time is cromulent (in this case, I was aiming for and getting easily under three hours including roughing, tool change, and finishing).

Well, again, if anyone is even slightly willing, I’ve got a big STL waiting for you to have fun. :sunglasses:

1 Like

I decided to try out Cloudland Canyon in Georgia, and I seem to have run into a glitch in my spreadsheet. :sweat_smile:

It looks to be all better now, and the Excel version is reuploaded. (Hopefully I won’t wake up tomorrow and think, “Wait, did I break that other thing?”)

Okay, what can I say? Drop a problem in front of me, and I’ll probably sit there gnawing on it for hours. Case in point, it’s now well after 1am.

I now have a process (not yet tested with a carve) that completely eliminates the STL step and replaces all that jazz with a simple bit of text in one dialog box that generates a nice 16-bit PNG heightmap, non-uniform scaling included. Of course, the steps before and after are still there, and only a few details change (plus, I can now generate STLs to 3D print terrain models), but if replacing a giant STL with a basically normal sized PNG gets equivalent results, call it a win.

To be continued.


Do you have a good resource for dem data for US lakes and reservoirs? I’d love to create one of these but with contours of a lake. Thanks for the info.

1 Like

PixelCNC developer here: I just wanted to point out that you can customize the quality of toolpaths via the Config menu, under CNC/CAM settings, by reducing the Path Simplify and Min Length settings, which will allow for shorter cut motions and also keep more detail.

This will generally increase toolpath generation times and for larger projects tends to be fine with the default settings. For projects less than a square foot in size I suggest perhaps a simplify of 0.1 (half the default) and minimum length of 0.01 (also half the default). The quality of a toolpath is really limited by the resolution of your input image itself as it’s very easy to end up with toolpaths where you can actually see the pixel stair-steps in your paths if your image size and project size end up less than about 100 pixels per inch of project size.

One thing you can do to help smooth that out is nudge up the Smooth Radius parameter when you’re in the Project Setup mode after loading an image - via the Image Size/Origin panel button beneath the load image/import model buttons. Just increment that up to one or two and hit Apply. The catch there is that you will start to lose corner sharpness as a trade-off, but for relief carvings I find that a smoothing radius of 1 is pretty good for most situations.

Thanks for the mention!


This should be pretty trivial to bring into Fusion360 as well.

So, it struck me that taking DEM raster data, which is at its heart a 2D array of heights, and converting that to a 3D model (with all its triangles and vertices) is rather needless. A terrain carve on a 3-axis CNC machine is itself basically just a heightmap. It’s all a bit Rube Goldberg, isn’t it?

I took a step back and thought back, and I think I ended up where I did was simple path dependency and inertia. So, taking a fresh look, what do we really need in order to do proper to-scale terrain relief models? We just need nicely detailed heightmaps (e.g. 16-bit PNG images) and a way to do all the scaling and math quite easily.

Well, it’s not quite released yet (since I don’t have an account on the plugins repository, and I have to do a little cleanup for standards and conventions), but here’s a little screenshot of my Heightmap Export plugin for QGIS.

Clip yourself a raster layer and open the Heightmap Export plugin. Give it your desired height, width, or depth, and it automatically calculates the others to scale. Scale depth or scaling factor let you easily do work the numbers for compressed or exaggerated Z. Then tell it how large an image to create (by pixel size or physical model resolution), and click the Export Heightmap button. It generates a PNG of the specified size with 16 bits of heightmap detail (65536 levels, bottom to top). From there, anything that can take a heightmap and spit out toolpaths should do.

HeightmapExport_prerelease.zip (30.2 KB)

I’ve currently developed the plugin for QGIS 2.18, and I’d like to port it to QGIS 3, as well. In the meantime, if you want to play with it, you can extract this zip to your QGIS 2.18 plugins folder, start QGIS, and check the box to turn the “Heightmap Export” plugin on in the “Installed” section of the “Manage and Install Plugins” dialog. It generates a heightmap from any raster layer, so you can follow the original instructions up to clipping the part of a layer you’re interested in, then use the new plugin.


Sadly, there don’t seem to be many sources for much bathymetric data at all. There are a handful of lakes and reservoirs available (Crater Lake, Lake Mead, etc.), but only a handful. Coastal waters generally have bathymetry data available from NOAA, but if you want to play with that, you’ll have to wait until the misfortunate situation over in that bog on the east coast between Virginia and Maryland… well, you’ll just have to wait.

1 Like

Okay, I finished debugging, made a nice little icon, created the required source code repository, got my OSGeo account, and just now uploaded for review both QGIS 2.18 and QGIS 3 versions of my Heightmap Export plugin. I don’t know yet how long it will take to approve the plugin (at which point it will be listed right there in the QGIS plugin manager), but if you want to play around with it right now, here are the zip files for QGIS 2.18 and QGIS 3, respectively.

HeightmapExport0.2.0.zip (17.6 KB)
HeightmapExport0.3.0.zip (17.7 KB)

In QGIS 3, the plugin manager has an option to load a plugin from a zip file, so until the plugin is listed officially, you can easily load it that way. (For QGIS 2.18, you have to find the plugins folder, extract the folder from the zip there, then relaunch QGIS and enable the plugin in the plugin manager.)

I figured Cloudland Canyon in Georgia would be a nice next model to try, and using the Heightmap Export plugin, the workflow was nicely simplified. I want to try making some of these with baltic birch plywood instead of pieces of 2x8 southern yellow pine, but for trial runs and just playing around, dimensional lumber is a perfectly cromulent medium. :grin:


If I wait a week to try this, I bet you’ll have it set up so I can choose an area, click one button, and the SO3 will do the rest.
Can’t wait to try it!

Alas, I’ve probably about settled out now. Then again, one thing I would absolutely love to be able to do is to take a terrain relief map and engrave the trails onto it. Basically, you would carve the relief map as usual, and then as a final step, take an SVG and trace the paths using the carved Z-height down a chosen offset. Of course, this would also be convenient for engraving text, a signature, a maker’s mark, or any old line art on any 3D carve.

I certainly don’t have @radioteeth’s skills when it comes to turning data into CNC toolpaths, but if I can turn a PNG heightmap into a 2D array, parse an SVG’s paths, and turn the results into heightmap-following G-code… Hey, it might not be impossible. Okay, probably not going to happen soon by any means, but that would be a killer app for hiking trail terrain relief maps.

Well, I don’t have anything that can make G-code, but I have managed to load the PNG heightmap, parse all the paths in an SVG, apply all the transforms (which isn’t too hard if you just parse everything into matrix transforms), walk each path, and copy the values from the heightmap. I figure if I can get this far, there’s a chance I might be able to bodge some G-code out of it.

As for now, after throwing a bunch of “Hello, World!” at it, I just whipped up an SVG with a boatload of paths in it, and sure enough, you can make out Mount Saint Helens in the PNG output I’m using to debug. :grin:

1 Like

Okay, it’s totally a bodge and completely unoptimized G-code, but… I seem to have had a successful proof-of-concept. I present, a completely off-the-cuff test of “The Alum Cave Trail of Mount LeConte” (with the other trails also labeled).

I knew the model was about half a millimeter deeper than the piece of terrible 2x6 I was using, hence the small carve-through in the valley. I didn’t know that there was a huge vein of sapwood in the piece of wood, but hey.

This was carved with a 1/4" ball nose mill to rough it out, then a 0.75mm-radius ball nose tapered mill for the terrain. I then followed that with a 0.25mm-radius ball nose tapered mill for the paths, which were cut with my python-bodged G-code using a Z displaced 0.25mm lower than the terrain carve.

Ideally, the “engraving process” would be within the CAM package so that it could follow the Z depths of the actual carve, but bodging it on as non-optimized G-code made from the same heightmap and model dimensions appears not to be impossible.

(Note: I did get the trails slightly off when I made the SVG out of vector paths, but that’s just refining the clipping process to dial in the alignment. The important part of the proof-of-concept test was the terrain following part.)