Introduction: Laser Cut 3D Ridgeline Map

About: I live in beautiful British Columbia, Canada! I love trying to make new things with a laser cutter (mostly maps!) and creatively manipulating data to make neat projects.

A ridgeline plot is a fun and unique way to showcase and visually compare series of data. They can also be used to create 2-dimensional elevation profile maps as seen in this amazing project by Andrei Kashcha.

I was thinking about the possibility of taking these types of maps and making them 3-dimensional but haven't seen it done before (please share if you've seen a similar project!). In the past couple years, I've learned how to use the laser cutter at my local makerspace and dabbled in Inkscape for personal projects. At the same time, my academic work has led me to learn more about QGIS and GIS/mapping in general. My goal for this project was to use these readily-available tools to blend science and art to produce something that (I think) is quite beautiful!

I'll be specifically showing how to create a map of Vancouver Island, but all of the steps can be used to create a map of any location in the world (as long as you have the right data)!

A vast majority of the time invested in this project is spent on the computer, so most of the images that I've included are screenshots detailing my processes. I've tried to make these steps as comprehensive and straightforward as possible. Some steps done early on may not seem like they are necessary, but they're usually done that way to help speed things along later in the process. This is the 4th or 5th iteration of this process that I've tried, but I'm always open to hearing ideas for things that will make it more efficient, so please share your suggestions!

There are a lot of steps and it can seem a bit overwhelming, but it's definitely an achievable project for anyone who is interested in learning how to use GIS and graphic design software and has access to a laser cutter (check your local library, look for a maker/hackerspace, or use an online service like Ponoko!). Now that I have a good idea of how everything fits together and the steps needed, I can go from input data to laser-ready files within a couple of hours, so it's not a huge time commitment to get things set up once you know how it all works!

Supplies

These are the tools that I've used to create and put my maps together. There may be other ways of doing thing, and I'd love to see them if you have different ideas!

Software

  • QGIS - QGIS is a free and open-source GIS software. I'm using QGIS 3.16.4-Hannover. Some of the processing tools I use for this project were not available in earlier versions, so it's important to be aware of that as the tools change and improve with every version that is released!
  • Inkscape - Inkscape is a free and open-source graphics editor. I'm using version 1.0.2. The features of the Hershey Text tool that I use later in the project are only available in versions 1.0.x and higher, so be aware of that if you're using an earlier version!
  • Laser controller software - My makerspace uses Lightburn, but any controller software that accepts .svg files (which pretty much all of them should!) will work.
  • Text editor - I use Notepad++ but any text editor with find-and-replace capabilities will work.

Tools and Materials

  • Laser cutter - I suppose you could do the cutting by hand, but it would be an incredibly slow process, so a laser cutter makes it much easier!
  • Wood, acrylic, cardboard, etc. - Whatever you want to use to make your map! I'm using 3mm Baltic Birch plywood.
  • Threaded rod and nuts - these will hold everything together in the end and ensure that the pieces are properly aligned with one another. I used #2-56 threaded rod and nylon nuts.
  • Some type of cutting tool for the threaded rod.
  • Glue to attach end pieces and hold loose ends together.

Step 1: Background and Basics

This map is made up of strips of poplar plywood, with each strip representing the elevation profile along a given line of latitude.

Elevation profiles are commonly used in mapping to show how elevation changes along a line or route. You've probably seen them used in hiking guides or in Google maps directions for walking and biking. In this map, we're taking 3-dimensional elevation data, turning it into 2-dimensional elevation profiles to laser cut, then reassembling it in 3 dimensions!

The laser cutter needs a vector file to cut, so we have to create a closed shape for it to follow. We also need some way of aligning and holding the pieces together once they're cut. I've tried just gluing them together or lining them up along thin strips of wood, but both of these methods have their disadvantages. For this version of the project, I'm holding everything together with thin threaded rod and nuts. Whatever process that is used for alignment should be incorporated into the vector file that's sent to the laser cutter.

Step 2: Data Requirements

This map uses a combination of vector data and raster data. If you're not familiar with these terms and their usage in GIS work, here's a brief overview for the context of this project:

  • Vector data: Generally consists of points and lines that can be connected and formed into closed shapes (polygons). For the purposes of this project, the land border of Vancouver Island that I'm using is vector data. The outputs from QGIS and Inkscape for laser cutting are also vector data and give the laser cutter a line to follow to cut the correct shape.
  • Raster data: Can be thought of as a georeferenced image file. Each pixel has attributes that are applicable to a given location. For this project, the elevation data that I'm using is raster data. Each pixel has a value associated with it that tells what the elevation is at that point.

Sourcing vector data

I got my vector data (first image) from a map of the health authorities in British Columbia here. This data covers the whole province, so I used QGIS to strip off the parts that I didn't want to include in my map. You can often find vector data for your area of interest by searching through government open data repositories. In the US and Canada (and likely other countries!), census data often includes detailed boundary files at varying scales.

If you want your area of interest to just be a basic shape instead of using a specified border, you can create that in QGIS and don't need to download any vector data.

Sourcing raster data

My raster files (second image) are NASADEM_HGT v001 from NASA's EarthData website. You need an account to download the data, but the sheer amount of data available from NASA/NOAA/USGS/etc. with an account is well worth signing up for it!

Step 3: Initial Setup and Planning

There are a lot of resources available online for getting started with QGIS, so I won't go into a ton of detail here, but there's a few things that you should know if you're relatively new to the program:

  • Adding files: You can just drag and drop files into the Layers panel in QGIS. If you don't see the Layers panel, click View>Panels>Layers. Vector layers are commonly saved as shapefiles, which contain multiple definition files in a single folder. If you're using a shapefile for your boundary layer, make sure to select all of the individual files to drag them in. I find that it's best to save the files for a given layer in a single folder, then it's as simple as dragging the whole folder into QGIS.
  • Processing toolbox: You'll be using a lot of tools from the processing toolbox, so it will be useful to have it visible at all times. To access it, click on View>Panels>Processing Toolbox Panel
  • Projection/CRS: The projection and Coordinate Reference System (CRS) define how the map is displayed on the screen. You'll want to use a CRS that uses meters (rather than degrees) for measurements. I generally use EPSG:3857 as it's a common one used on the Internet that people are used to. For certain things, though, other projections may look nicer. You can play around and find what you think looks best for your situation! If your vector layer uses a different projection than your project (hover over the layer to see what it's projection is and see if it matches what's shown on the bottom right of the screen), you'll want to reproject your vector layer to match. In the processing toolbox, use the "Reproject Layer" tool to accomplish this.
  • Virtual Raster: If you have multiple elevation raster tiles, you'll need to merge them all into one. Instead of creating another (potentially very large) raster file, you can create what's called a virtual raster instead. This creates a reference of the individual tiles and lets you treat them as if they are one continuous file. In the processing toolbox, use the "Build Virtual Raster" tool to do this. When the raster is loaded into QGIS, the default display behavior is to show black as the lowest elevation and white as the highest.

Think about how big you want your physical map to be. A number of the steps that are done later depend on converting between QGIS map units and physical map units, so it's good to have the size decided as you're getting started.

For my map, I'm shooting for a height of about a foot. One foot is approximately 300mm, so I can use 100 strips of my 3mm plywood to get there.

Step 4: Individual Map Pieces

Each piece of the map looks something like this image and consists of 5 basic parts:

  • Ridgeline: The elevation profile for the piece.
  • Baseline: The bottom of the piece that creates a closed shape to send to the laser cutter.
  • Threaded rod hole: Each piece will have at least one hole in it for threaded rod to pass through to align and hold all of the pieces together.
  • Nut notch: Not every piece will have one of these. Only the ones on the ends of each threaded rods need a notch for the nut to fit in.
  • Label: The label isn't strictly necessary (especially if your map only has a few pieces), but is super helpful for making sure everything is in the right order. The label will be created in QGIS and edited in Inkscape.

Step 5: Overview of the Process

These images show a generalized overview of the steps used to create the map. I've labeled each part with the appropriate step in the Instructable so you can quickly reference what you're working on. I tried to make it as easy to follow as possible with the arrows, but it can be a bit confusing since some intermediate steps are used multiple times to create future layers. In a lot of the steps, the overview just shows a single line or shape, but it's important to know that QGIS will be doing the operation to all of the pieces of the project at once.

In QGIS, almost every process that you run creates a new temporary layer by default, meaning that the layer is not saved after the program is closed or crashes. I generally don't keep all of the intermediate layers when I'm done with a project, but it can be good practice to do so if you're worried about losing your progress. I will be renaming my layers as I go though to make sure I know what each one is doing!

If you make a mistake somewhere along the line, don't worry! It's easy to delete layers (right-click on the layer and click "Remove Layer...") then try again.

Now that we're ready to go, let's get started!

Step 6: Extract Layer Extent

Why?

The goal of this step is to get the overall height and width of the map in QGIS. This will allow us to do an accurate conversion between the QGIS map units and physical map units. This will be especially important later to make holes and notches in the pieces and to scale things before sending them to the laser cutter.

How?

In the processing toolbox, search for and run Extract Layer Extent. The result will create a bounding box around your boundary layer that perfectly fits its height and width. If you notice that this box isn't perfectly squared in the corners, confirm that the projection of your layer and the projection of the project match!

Right-click on the extent layer in the Layers panel and click "Open Attribute Table." Make a note of the height and width and keep it handy and do a conversion between physical units and map units!

In my case, for example, I know I want my physical height to be 300mm. My map height is ~441133m, so my conversion is:

441133 "QGIS meters" = 300 "physical mm" ==> 1470.4m per mm

Step 7: Create Grid

With the map extent extracted, we can create a grid of lines to fill the space.

Why?

These lines will form the basis for many of the steps that we'll be doing later.

How?

Use the Create Grid tool in QGIS to do the following:

  • Grid type: Line
  • Grid extent: To the right of this box, click on the ... then 'Calculate from Layer'>'vancouver_island_extent'
  • Horizontal spacing: Make this value slightly less than the total width of your extent. Unfortunately I don't think there's a way to create just horizontal or vertical lines in QGIS, so we have to create both then delete the vertical lines. Using a big spacing makes it easy to delete the extra lines. I'm using 500,000 meters for mine.
  • Vertical spacing: Make this value equivalent to the thickness of the material that you're using to make your map. In my case, I'm using 3mm plywood, so 3mm x 1470.4m/mm (conversion from previous step) = 4411.2 meters.

I'm going to rename this layer "initial_extent_grid" so that I can reference it in later steps.

To delete the vertical lines, you need to turn on editing for the layer. There are many ways to do this, but I find that the quickest way is by right-clicking the layer, then clicking "Toggle Editing". Once the layer is editable, click on the "Select Features..." tool, select the two vertical lines by clicking the first then Shift+clicking the second, then click on the trashbin icon to delete them. After you've deleted the lines, right-click the layer>"Toggle Editing" again to save the changes.

Step 8: Translate Grid

Why?

The current grid has lines that essentially represent the top and bottom of each wood strip that will make up the final map. Instead of that, we want lines that run right along the middle of each strip.

By shifting the grid down by the equivalent of half of the width of one strip, we can easily accomplish this.

How?

Using the Translate tool, input the following:

  • Input layer: Should be your initial extent grid.
  • Offset distance (y-axis): Should be half of the grid spacing.
  • For my case, the grid spacing was 3mm=4411.2m, so the offset distance will be 1.5mm = -2205.6 meters.
  • Make sure the value is negative to shift the grid down!

I'm renaming this grid 'translated_extent_grid'.

Step 9: Clip the Grid

The next thing that we want to do is clip the grid to match the borders of our vector boundary layer.

Why?

When we sample elevation values to create the profile lines, we don't need to sample the whole region, just the area inside our boundary.

How?

To do this, use the Clip tool:

  • Input layer: This layer is the translated extent grid that you created in the previous step.
  • Overlay layer: This is your map boundary layer.

Once it's completed, you should have a grid layer that perfectly fits inside your boundary layer! I'm renaming mine 'clipped_grid_island_boundary'.

Step 10: Extract Vertices [Possibly Unnecessary]

If your map doesn't have any "dips" in it that caused the grid lines to be separated while clipping, this step is completely unnecessary.

Why?

What the next three steps do is take horizontal line segments that were separated in the clipping process and combine them back into one single line. As far as I'm aware, there is no good way to have QGIS clip just to the farthest right and left borders of a polygon layer (and ignore missing middle areas), so these steps are necessary.

This first step converts the line segments to end points. The next step turns the points back into lines. The final step simplifies the lines so that they're one continuous piece instead of being made up of multiple smaller segments. We can ensure that only lines at the same latitude stick together since there is an 'id' parameter that was created when the initial grid was created and is maintained throughout all of these different steps.

How?

First step - Extract Vertices:

  • Input layer: This is your clipped grid layer.

I'm renaming this layer as 'clipped_grid_island_boundary_vertices'.

Step 11: Points to Path [Possibly Unnecessary]

In this second possibly unnecessary step, we'll turn the points back into lines using the "Points to Path" tool. When the initial grid lines were created, a unique 'id' number was assigned to each one. This id carries through for every other operation that is done using those gridlines.

When the points were created in the previous step, each one was assigned a vertex index. Each set of vertices that lie along the same horizontal line are indexed from left to right.

How?

When creating lines from points, QGIS needs to know what order to connect them in (like a connect-the-dots!). It also needs to know if it should separate lines based on a specific attribute or not. Thankfully, we have both of those parameters, so in the "Points to path" tool, you can use the following:

  • Input point layer: Use the vertices created in the previous step.
  • Order field: "vertex_index"
  • Group field: "id"

This will connect all points into a continuous horizontal line, but each will still be made up of multiple segments (as shown in the photo - if you turn on editing and select a line, it will show you where the different segments are). In the next step, we'll turn them back into single-segment lines.

I've renamed this layer 'clipped_grid_vertices_to_path'.

Step 12: Simplify [Possibly Unnecessary]

In this third and final possibly unnecessary step, we'll turn the segmented lines back into smooth, single-segment, continuous lines using the "Simplify" tool in QGIS. This tool attempts to simplify the geometry of a feature.

Why?

This can be useful for reducing the complexity of complex shapes. In this case, it's useful since it turns a set of line segments into a single line!

How?

In the Simplify tool, all you need to do is use the previously created points to path layer as the input and leave everything else as the default values.

If I again turn on layer editing and select the lines in the simplified layer (which I renamed 'simplified_clipped_grid_island_boundary'), you can see that the only vertices are now at the far end of the line rather than at every water crossing.

Step 13: Points Along Geometry

If you didn't need to do the previous three steps, you can start again with the grid that you clipped to your boundary earlier.

The next few steps that we're going to do involve placing points along the clipped grid.

Why?

These points will be used to sample elevation values from the raster file, which will in turn inform how much they should move to generate a profile of the terrain.

How?

The number of points you use depends on how high-quality your elevation data is as well as how detailed you want your physical map to be. In my case, I'll be using a spacing of 300 meters, since that offers a significant amount of detail while not making the model too complex. If you're making a map of the whole United States, for instance, you'd likely want to use a much larger spacing to prevent your QGIS map from becoming too large.

In the Points Along Geometry tool, select your clipped grid layer and set your distance.

I've renamed my layer "points_along_clipped_gridlines_300m".

Step 14: Extract Specific Vertices

Why?

If you zoom in on the far right end of one of the clipped gridlines, you'll see that the points don't extend all the way to the very end. This isn't a huge deal, but in order for the right border of each strip of the map to be vertical, there should be a point at the very end of the line.

How?

To get this point, use the Extract Specific Vertices tool:

  • Input layer: Clipped gridlines
  • Vertex indices: 1. For the clipped gridlines, the left vertex is 0 and the right one is 1. If you somehow have a line with more than two vertices, though, you can enter a value of -1 and QGIS will extract the farthest right point.

I've renamed this layer 'clipped_gridline_right_vertex'.

Step 15: Merge Vector Layers

Why?

To create a consistent set of points to sample with, we'll want to merge the two previously created layers.

How?

When merging layers, it's important to make sure that the fields for each layer with "get along" with one another.

Fields in QGIS can have many different types (string, integer, etc.), and if you're merging layers with fields that have the same name, the field type needs to be the same as well. You can check the field type in the layer properties box (right-click the layer name>"Properties...", then click on "Fields").

Alternatively, you can open the layer's attribute table (right-click layer name>"Open Attribute Table") and hover over the field name to see its type.

When we're merging, we also want to make sure that there's a value that consistently increases or decreases for each point. This will make it easier later when we have to "connect-the-dots" again.

For this map, we're fortunate that the "distance" field for both layers is of the same type, and that the distance measurement for the "right_vertex" layer is greater than the distance measurement for each "id" in the "points_along_line" layer.

To merge the layers, use the Merge Vector Layers tool and select the two point layers as the input layers. I've renamed my layer "merged_points_along_line".

Step 16: Sample Raster Values

Finally, we can start to use the raster layer that we loaded in at the very beginning! In this step, we'll extract the elevation along each line by using the points layer that we just created to sample values from the raster layer.

Why?

The sampled elevations will be used to create the ridges along the tops of the ridgelines.

How?

To do this, open up the "Sample raster values" tool:

  • Input layer: The merged points along layer line created in the previous step.
  • Raster layer: The elevation raster layer. In my case, it's the virtual raster that I created in Step 3.
  • Output column prefix: This value doesn't really matter, but I like to change it to "elevation_" for clarity.

I've renamed this layer "sampled_elevation_point_layer". You'll notice that the points don't move at all. This layer is exactly the same as the layer created in the previous step but now has an additional field with the elevation value of each point in it.

Step 17: Translate Points

Why?

To make the points look like mountain ridgelines, we need to shift them up based on their sampled elevation value. We can do this using the "Translate" tool.

How?

When doing this step, you need to think about how tall you want your physical map to be. The vertical scale of 3D maps is often exaggerated to show the terrain in more detail, so it's good to plan for that. You can do this in one of two ways:

  • Simple scale: By doing this, you just multiply the elevation parameter by a single value and see if you think it looks good.
  • Set height: If you have a maximum height in mind that you want your physical map to be, you can find your maximum elevation value and calculate the multiplication factor you'd need to reach your desired height. This is the method that I'll use and will explain how it's done below.

In addition to increasing the elevation of most points, you may also want to consider decreasing the elevation of points that are over water. In my case, there are some inlets that I'd like to reduce the elevation of in order to make the edges of these areas more well-defined. By lowering them by 0.3mm, it will create a clearer edge to differentiate the land from the water.

Translate tool

In the Translate tool, click on the menu to the right side of the "Offset distance (y-axis)" parameter and select "Edit". What this does is allow you to use an equation to define the amount of translation, rather than just using a set value for each feature.

An expression bar will come up and you can use simple math operators or more complex conditional equations. In my case, I want to set a few conditions:

  • If the sampled elevation is equal to or less than 0, I want to shift it down by 0.3mm, which in map units is:

1470.3 x 0.3 = 441.12 meters

  • I want the maximum height of the physical map to be 4mm, which in map units is

4mm x 1470.4m/mm = 5881.6 meters

  • So I want to scale the maximum sampled elevation by a factor k such that the translated value ends up being 5881.6 meters:

maximum sampled elevation (for all points) x k = 5881.6

Therefore

k = 5881.6/maximum sampled elevation

  • I'll then use the parameter k to scale every other elevation as well such that

translated value (for each point) = sampled elevation x k

so

translated value = sampled elevation x 5881.6/maximum sampled elevation

  • So if the sampled elevation is less than or equal to zero, translate the point down by 441.12 meters, otherwise move it up by the sampled elevation times the k parameter.
  • The full expression that we want to use then is:

if("elevation_1"<=0,-441.12,"elevation_1"*5881.6/maximum("elevation_1"))

  • You can either type "elevation_1" in with quotation marks, or select it from the "Fields and Values" menu in the expression editor. Make sure you use the maximum function and not just a max function, since the maximum function looks through all of the features to find the highest value while the max function does not.
  • From what I understand, the maximum function was introduced in QGIS 3. If you don't have the function, you can calculate the k parameter by hand by sorting by elevation in the attribute table of the sampled points layer to find the maximum sampled elevation value.
  • Check the preview to make sure that your function is valid. Check for missing quotation marks, commas, or parentheses if it says the expression isn't valid!

Run the translate tool and you'll see that the points are actually starting to look like ridgelines now!

Step 18: Rewind: Translate an Earlier Layer

At this point, we're going leave our ridgeline points for a few steps and go back to create the points that will be used for the baseline of each piece of the map.

Why?

The layer that you'll need for this is the simplified clipped grid layer that we created back in Step 12. Mine is named "simplified_clipped_grid_island_boundary". We need to translate this layer down in order to create a base for each of our pieces. The base needs to be tall enough so that whatever alignment method you're using will have room to fit underneath the ridgelines.

In my case, I'm using threaded rod and nuts to hold my map together. The threaded rod that I'm using is a #2-56 thread, which has a diameter of 0.086" or ~2.2mm. Standard #2-56 hex nuts have a width across the flats of 3/16" or ~4.8mm and a width across the corners of 0.217" or ~5.5mm.

We'll create the holes for the rod and nuts later, but for now, we want to make sure that there's a little bit of room above the nut in the baseline section of each piece. With a nut height of just under 5mm, I think a 6mm base section is a good choice.

How?

In the Translate tool:

  • Input layer: Simplified clipped grid as mentioned earlier.
  • Offset distance (y-axis): 6mm x 1470.4mm/m = -8822.4 meters.

I'm going to rename this layer "translated_baseline_lines".

Step 19: More Extracted Vertices and Field Calculating!

It may seem silly that we're using points to represent the border of each of our map pieces, but it's very easy to merge point layers then make QGIS connect the dots to make outlines.

With the translated layer that you just created, use the "Extract Vertices" tool to get the endpoints. I'm going to name this layer "baseline_points".

Why?

Thinking ahead, we'll need to merge this layer with the translated sampled points layer in order to use the Points to Path tool to create a full boundary. Recall that this tool requires an order field for QGIS to follow so it knows which points to connect.

Both of the point layers that we'll be merging have a "distance" field. In both of these layers, the value of that field starts at 0 and increases as it moves to the right. In the third image, you can see a basic example of how this works.

To force QGIS to follow the points clockwise or counterclockwise, I'm going to modify the values of the points in the baseline points layer to make them negative. I'll do this with a tool called the field calculator.

How?

Select the baseline points layer, then click on the "Open Field Calculator" icon.

In the field calculator:

  • Select "Update existing field" and select the "distance" field.
  • In the expression window, use an equation like:

("distance"+1)*-1

  • This equation will take the 0 value and turn it into a -1 and will change the other distance value to a more negative number. Now when QGIS connects the dots, it will start at the right baseline point then progress clockwise around.
  • Note that when you run the field calculator, it will automatically turn on layer editing, so you'll need to turn that off again when you're finished.

Step 20: Merge Layers

Now that the baseline and ridgeline point layers are formatted properly, we can merge them!

Use the Merge Vector Layers tool to merge the layers. I'm calling mine "ridgeline_and_baseline_points".

Everything still looks quite cluttered right now, but remember that each point still has an 'id' value that we'll be used to keep all the pieces separated.

Step 21: Points to Path

We can use the Points to Path tool again to turn the points into a continuous outline:

  • Input point layer: Should be the merged baseline and ridgeline layer.
  • Check the box next to the "Close path" option.
  • Order field: Use the "distance" field that we edited earlier.
  • Group field: Use the "id" field - this will create all of the individual outlines and keep them separate!

I've renamed my layer "ridgeline_and_baseline_outlines".

Step 22: Lines to Polygons

Why?

Later, we'll be cutting out holes in these shapes. It doesn't work very well to cut holes in lines, so we need to turn the lines into solid shapes.

How?

To do that, we'll use the Lines to Polygons tool. I've renamed the resulting layer "ridgeline_and_baseline_polygons".

You'll notice that QGIS draws the polygons in a semi-random order so they're overlapping each other oddly. You can set the order that they're drawn in if you want, but it won't affect anything that we're doing.

Step 23: Translate Polygons

Why?

For cutting out holes in our shapes later, we need the different features to be separate or the holes will go through any of them that are stacked on top of each other. We'll again use the Translate tool to accomplish this.

The top shape can stay in it's place, the next layer down needs to be shifted by a certain amount, the next one by twice that amount, etc. to keep them separated. The gap needs to be wide enough to accommodate the highest "peak" and there also needs to be enough room so that the rectangles that we'll create in a future step won't interfere with the wrong features. To be safe, I'll use 3 times my maximum elevation value (recall that this was 4mm or 5881.6m) for separation.

How?

We'll again use the expression editor in the Translate tool to do a variable translation amount:

"id" x 3 x -5881.6

Run the translation tool and leave the dialog box open since we'll use it for the next step!

I'm renaming this layer "translated_polygons".

Step 24: More Translation!

How?

With the dialog box for the Translate tool the previous step still open, change the "Input layer" to the translated baseline lines layer and run the process again.

Why?

These lines will be used for multiple steps to help create the holes that we'll put in the translated polygons and their labels. I've renamed this layer "super_translated_baseline_lines".

Step 25: Alignment Lines

Time to do some drawing!

Why?

To line up the cut pieces properly, I'm going to be putting holes in them that I'll feed threaded rod through and fasten on the ends. This is an especially important step if you have an oddly-shaped boundary!

How?

To draw the lines that will be used to create the holes, we need to create a new layer in QGIS. I'll start just by creating a temporary scratch layer that I can then save as a permanent layer later if needed.

To do this, click on the "New Temporary Scratch Layer" icon:

  • Change the layer name - mine is "alignment_hole_lines".
  • Geometry type: LineString
  • Project CRS: Whatever you've been using (make sure it matches what's shown in the bottom right of the screen)

Once you've created the layer, editing mode is turned on by default. There are a couple of other toolbars that we'll want to make sure we have available to ensure that the lines are created perfectly vertically and that they snap to the existing lines. The two toolbars can be displayed by clicking View>Toolbars, then:

  • Advanced Digitizing Toolbar, and
  • Snapping Toolbar

To start creating a line:

  • Click on the "Add Line Feature" icon to create a new line.
  • Don't click on the screen yet, but instead, click on the "Enable advanced digitizing tools" icon. This will open the advanced digitizing toolbar that will snap the lines to vertical.
  • Click on the "Enable Snapping" icon to enable snapping to other features.
  • Also on the snapping toolbar, make sure that "Segment" snapping is enabled.

To actually create a line:

  • Click on one of the horizontal super translated baselines. For my map, the first point that I click will be where the nut ends up, so I need to make sure that there's enough room to the left and right of it and that it will end up being covered by the layer behind and in front of it. Don't put any holes in the first or last layers, as you can just glue them on at the end.
  • Move straight down to another horizontal line and click again.
  • To complete the line, right-click.
  • If you're partway through drawing a line and mess up, just hit Esc then right-click and you can start over.

Continue to add lines until it seems like you have enough. You can always supplement with glue to make sure that the pieces hold together. When you're satisfied, turn off editing on the layer.

If you need to make changes:

  • To move a line: Select the "Move features" tool in the advanced digitizing toolbar.
  • To delete a line: Use the selection tool to select the line then delete it.
  • To make a line longer or shorter: Use the "Vertex tool" to move the endpoint up or down.

Step 26: Line Intersections

Why?

The holes that we create in our polygon need to be lined up with the alignment lines that we just created and a specific distance above the bottom of the polygons. To accomplish this, we'll create a set of points where the alignment lines and baselines intersect.

How?

Open the "Line Intersections" tool and use the baseline layer as the "Input layer" and the alignment hole lines layer as the "Intersect layer".

This process will create a set of points at the intersections of these lines. I've called this layer "alignment_baseline_intersection_points" We'll then shift these points and use them to create holes in the polygon layer

Step 27: Even More Translating

Why?

The points that we created will be used as the midpoints that the threaded rod will pass through in my map. The threaded rods need to pass through the centers of the nuts, and the bottom flat faces of the nuts should be lined up with the bottom of each polygon. Because of that, the points should be moved up by half of the width of the nuts.

As mentioned in Step 18, the nuts are 3/16" or ~4.8mm across their flats. Half of that is 2.4mm, which in map units is:

2.4mm x 1470.4mm/m = 3529m

How?

Use the Translate tool to shift the points layer up by this amount. I've renamed the resulting layer "threaded_rod_hole_center_points".

Step 28: Buffering

Why?

The points that we just translated by themselves aren't sufficient to create holes in the polygons, so we need to create circles centered around them.

How?

We can do this by using the Buffer tool:

  • Input layer: Center points layer.
  • Distance: This should be equal to half of the diameter of the threaded rod. Since the rod is ~2.2mm in diameter, the value that we'll use is:

2.2mm/2*1470.4mm/m = 1617.4 meters

The buffer tool can't make perfect circles, but will instead approximate a circle with a series of lines which is just fine for our purposes. The other settings in the buffer dialog box control how many segments make up the circle, as well as other parameters that are useful when doing buffers of more complex shapes. Since we're just doing a basic buffer, we can leave the default values as is.

I've renamed this layer "threaded_rod_holes". It may not look much different than the point layer, but you can see by the icon next to the layer name that it's actually a polygon layer and not just a point layer.

Step 29: More Vertex Extraction

Why?

Along with the holes for the threaded rod, we need to have notches cut in the polygons that the nuts will fit into. To do this, we'll create rectangles at the end of each alignment line, but we first need to create points for the rectangles to be centered on.

How?

By extracting the vertices of the alignment lines, we can create points that will be perfect for using to make rectangles.

Open up the Extract Vertices tool and select the alignment hole lines layer. I've renamed the resultant layer "rectangle_center_points".

Step 30: Making Rectangles

Why?

The notches that we cut in the polygons for each piece need to be sized properly to fit the nuts for the threaded rod.

How?

To create these notches, we'll use the Rectangles, Ovals, Diamonds tool in QGIS.

This tool creates a shape centered on the point layer. The dimensions for the rectangle that we create, then, should have a height equivalent to twice the height of the nut, and a width equal to the nut's width across corners:

  • Input layer: Rectangle center points layer.
  • Shape: Rectangle.
  • Width: The width across the corners of the nut, as mentioned in Step 18, is ~5.5mm, so:

5.5mm x 1470.4m/mm = 8087.2 meters

  • Height: The width across the flats of the nut as indicated in Step 18 is ~4.8mm and we need the rectangle to bet twice this tall (since it's centered on the point), so:

4.8mm x 2 x 1470.44m/mm = 14115.8 meters

I'm not too worried about being a little too small on these measurements, as the kerf from the laser cutter will add a bit of extra room. I renamed this layer "rectangles".

Step 31: Making a Difference (in a Polygon)

Now that we have the ridgeline/baseline polygons, threaded rod holes, and nut rectangles, we can use QGIS to use all of these features to create single shapes. There are a couple ways to do this, but the way that I'm going to do it is to first subtract the holes from the ridgeline/baseline polygons, then subtract the rectangles.

Open the Difference tool:

  • Input layer: Ridgeline/baseline polygons (the translated ones!).
  • Overlay layer: Threaded rod holes.

Run the Difference tool again, using the result from the previous run ("polygons_with_holes") as the input layer and the rectangles layer as the overlay layer. I've renamed the resulting layer "polygons_with_holes_and_notches".

Step 32: Polygons to Lines

Why?

This step might not be necessary, but I think it makes things look a bit cleaner.

How?

Run the "Polygons to lines" tool to turn the polygons into lines, and that's it for the outlines of the map pieces! I renamed this layer "final_ridgeline_lines".

All that's left now is making labels and prepping pieces for laser cutting!

Step 33: Extracting the Last Vertex and Labels

Why?

Labels aren't a necessity for making your map, but I find that with tons of pieces, it can make things way easier for putting together the final product. With the shape of my map, it makes the most sense to put labels in the bottom right corner for the most part. To get a label there, I'm going to create a point at that location by extracting the right vertex of the super translated baselines layer. Labeling is one practice that I'm not as familiar with in QGIS, so it could very well be that there is a better way to do this.

How?

Once again, open up the Extract Specific Vertices tool, and use the super translated baseline lines layer as the input. Change the "Vertex indices" value to 1 to grab the right vertex.

We don't want the vertex to show up on the final map, so we'll add a label but hide the vertex itself. To do this, right click on the vertex layer (which I've renamed "label_vertices") and click "Properties". Then do the following:

  • Symbology: In the Symbology tab, click the dropdown and change from "Single Symbol" to "No Symbols".
  • Labels: In the Labels tab, change from "No Labels" to "Single Labels" and make sure the value is the 'id' field.
  • In the "Text" subtab, change the size to be in Millimeters and use a height that's less than the thickness of the baseline section. I'm using 4mm.
  • In the "Placement" subtab, change the "Mode" to "Offset from Point", choose the top left quadrant, and offset a few millimeters to the left.
  • In the top right corner of the properties window, click the "Automated Placement Settings" icon, then change text rendering to "Always Render Labels as Text". This will allow QGIS to export the text as a text element instead of a path element. In turn, Inkscape will recognize the text as text and allow us to convert it to a single line "Hershey Text" (described later).

Step 34: Exporting!

It's finally time to export the map from QGIS! I find the interaction between labeling and exporting to be a bit confusing, so this is the way that I've gotten it to work. Again, there might definitely be better ways of doing this!

My process:

  • Zoom in or out until it looks like the labels are in a good spot and sized well on your map.
  • Make sure you only have the label layer and final line layer selected in the layers menu.
  • Go to Project>Import/Export>Export Map to PDF.
  • In the resulting dialog box, select "Calculate from Layer" in the Extent section, and select the final line layer.
  • Uncheck the "Simplify geometries to reduce output file size" box (unless your map is massive).
  • Change the Text export to export text as text objects.
  • Save the file!

Step 35: Importing to Inkscape

Open Inkscape and open the PDF file that you saved in the last step. Use the default opening parameters.

The things that we need to do in Inkscape:

  • Get the size right.
  • Convert the text to single lines [Optional].
  • Shuffle the layout to send to the laser cutter.

Get the size right

To get the size right, we need to go all the way back to the beginning of the project where we got the height and width of the extent of the map. The ratio between the height and the width of the extent will allow us to set the width in Inkscape.

Extent height/Extent width = Physical map height/Physical map width

We know what the extent height and width are, and we decided on the physical map height early on, so we can easily calculate the physical map width. In my case, the equation becomes:

441133m/575342m = 300mm/width in mm

so the width is 391.2mm.

In Inkscape, if I click on any part of the map, then I can change the overall scale:

  • Click on the lock icon to lock the vertical/horizontal proportions.
  • Change the units to mm.
  • Type the proper width into the "W" box.

At this point, you can also ungroup the file into separate objects. To do this, make sure the map is selected, then click Object>Ungroup, then repeat twice more until each shape is separate and has its own selection box around it as shown. Click in the white space surrounding the map pieces and you'll notice that there's a white bounding box around the whole drawing. Hit Delete to get rid of this bounding box.

Step 36: Convert Text to Single Lines [Optional]

This is an optional step for converting text to single lines to make them faster to cut on the laser cutter and will only work in Inkscape 1.0 and higher. If you don't do this step, you should change your QGIS export settings to export text as paths so that the laser cutter software will import it properly.

Most laser cutter software has an option to either fill areas or just cut in a straight line. The fill function works like a printer, where the laser cutter head passes back and forth and the laser turns on and off rapidly to create solid areas. This process works great and can be used to create text, but can take a rather long time, especially if you have a large map.

Alternatively, we can trace the outlines of the text shapes. This can also be time-consuming, however, and may create unreadable text if the features are too small.

In my opinion, the best way to do things is to convert text to so-called Hershey Text, which uses a single stroke to represent text characters. It took me quite a while to figure out how to do this, but I think it's worth it!

Creating Hershey Text

  • Download the Hershey Text extension for Inkscape.
  • Save your map as a .svg file and close Inkscape.
  • Open the .svg file in a text editor, such as Notepad++
  • In the file, search for 'x="0 ' (without the single quotes, so 0 followed by a space).
    • The way that the file is saved from QGIS sets the start point of each character separated by a space. So a two-digit number (10-99) will have x="0 n", where n is the spacing value. A three digit number (from what I understand) will have x="0 n 2n".
    • The Hershey Text extension doesn't like multiple values in the x= parameter, so we need to change them all to just x="0"
    • To do this, use the find and replace function of your text editor. Start with the longest-digit numbers. So in my case:
      • The pattern is x="0 8 16" for 100 (the only three-digit number in my file), so I'll do find and replace x="0 8 16" with x="0"
      • For two-digit number, I'll find x="0 8" and replace with x="0" as well.
  • Resave the .svg file in your text editor and close it.
  • Re-open the file in Inkscape.
  • Click on any one of the text items in Inkscape.
  • In the Edit menu, click Select Same>Fill and Stroke to select all of the text elements.
  • With the text selected, click Extensions>Text>Hershey Text
    • Use the default settings and hit Apply
  • The difference might not be super obvious, but the text is now just represented by a single stroke!

Step 37: Grouping, Rearranging, and Sending to the Laser Cutter

With the file reopened in Inkscape, you can now prep it for sending to the laser cutter. To do this, I do the following:

  • Check alignment.
  • Group shapes.
  • Create boundary.
  • Rearrange shapes.
  • Sending to laser cutter.

I find this process to be one of the most tedious parts of the whole thing, but it's nice to do to try and use as little material as possible for the cutting.

Sometimes it's easiest to visualize things in Inkscape by changing the view to just see the outlines of each piece rather than the colored stroke lines. To change the view, click View>Display Mode>Outline

Check alignment

Make sure that your labels will all be covered by the pieces in front of them. If needed, shift the labels to the left or right to make sure that they'll be hidden. You should also delete the label on your last piece so that it doesn't show up! Do this before shifting things around otherwise you won't be able to easily see how the pieces line up!

Grouping shapes

To group the shapes, I select one set of lines/holes/labels at a time, then hit Ctrl+G to group them. Now I can move the whole map piece around and it will be treated as a single item in Inkscape.

Creating a boundary

I create a boundary based on the size of the material that I'm going to be cutting. In my case, I'll be cutting using 12"x12" squares. In Inkscape, I create a box that's a little smaller than that to give myself a little bit of wiggle room.

Rearranging

Shift each map piece around to try and fit as many as possible in your boundary. I ended up fitting everything in two squares.

Sending to laser cutter

Most laser cutter software accepts .svg files for import, so just save the completed .svg file from Inkscape. One thing that will probably make things easier is ensuring that the stroke color of the labels and the outlines/holes are different. That way, the laser cutter software should separate them into different cut layers. You'll want to use a very fast cutting speed and low power for the labels so they don't cut through the wood!

Step 38: Cutting and Organizing

From your laser cutter software, send the files to the laser to cut! It might take a while...

After cutting, I usually end up with a pile of pieces in no particular order. Before assembling, I like to separate into groups (here I split the pile into thirds) to make it simpler to put things in the right order later. There are often also some little bits of wood that got stuck or didn't cut all the way through that need to be pushed out.

Step 39: Assembly

Assembly is mostly done with the threaded rod and nuts, but you'll also want to use glue for a few pieces. In particular, the first and last piece will need to be glued on. In addition, sometimes it's nice to glue some of the tips of the pieces together so the wood doesn't separate.

Turn on some music and have fun putting everything together :) As long as the holes and notches are the right size and in the right place, it should go together pretty smoothly!

Step 40: Finished!

Admire your work, hang it on the wall, or give it to a friend!

There are a few things that I realized after I put my map together that I probably should have done differently, so here are my recommendations for you:

  • Make the base section a little bit taller or the notches for the nuts a little bit shorter. In some of the spots where the notch was under a section of water, the wood was really thin and prone to snapping.
  • Wherever possible, make sure you have at least two rods running through any given piece of the map. I didn't in some spots, so I had to add more glue to prevent those pieces from spinning.
  • I'm still not sure what the best order is for cutting rod vs. threading nuts on. It's really convenient to not have to thread a nut all the way up a long piece of threaded rod, but it's also sometimes difficult to thread a nut onto a cut piece of rod. Maybe if you have a higher quality cutter it wouldn't be an issue!
  • The threaded rod that I used didn't seem to have a super consistent diameter, so it felt like the nuts were slipping on some parts. Perhaps metal nuts would hold better, or maybe a different brand of threaded rod would be more consistent. Other ideas are welcome!

Please let me know if you have any comments, questions, or ideas and I'd love to hear them! Enjoy!


First Time Author Contest

Runner Up in the
First Time Author Contest