Terrain generation for laser cutting

Hi everyone,

I am working on a Grasshopper script to generate physical terrain layers for laser cutting. I am stuck on filtering the correct surfaces.

The Workflow:

  1. I have a base bounding rectangle (“Curve”).

  2. I have topography contour curves positioned at various Z-levels.

  3. I create a planar surface from the bounding rectangle at each Z-level.

  4. I use the Surface Split component to cut these rectangular surfaces with the contour curves.

The Problem:
The Surface Split component outputs all fragments: the “terrain islands” (inside the contours) and the “waste” (the rest of the bounding rectangle). I need to remove the “waste” part and keep only the terrain.

What I have tried (and why it failed):

  1. Sorting by Area: I tried sorting the fragments by Area and culling the largest one. This fails because at certain elevations (e.g., z=350 in my file), the terrain area is actually larger than the waste border, so the script deletes the wrong geometry.

  2. List Item: I cannot simply select index 0 or 1, because some levels have multiple contour islands, resulting in a variable number of surfaces per branch.

The Question:
What is the most robust way to filter the Surface Split results to keep only the surfaces that represent the interior of the contour curves?

I have attached a simplified definition with the data. Any help would be appreciated!

terrain_generation_for_laser_cutting.gh (44.9 KB)

It looks like most of your layers will generate two surfaces and you’ll want to remove the bottom left one (so it has a lower X and Y value)

Thanks for the suggestion, but I am afraid relying on X/Y coordinates or the “bottom-left” logic won’t be robust enough for this definition.

The main issue is that the terrain geometry varies significantly across different Z-levels:

  1. Multiple Islands: Some levels have multiple disconnected terrain islands. In these cases, the Surface Split results in 3 or more fragments. Removing just one based on position would either leave waste behind or delete valid terrain parts.

  2. Shape complexity: The terrain isn’t always centered. A strict coordinate filter might fail if the terrain shape is concave or positioned near the “waste” edge.

I am looking for a universal solution.

I’m not sure there is one robust way to do this that will work in every case.

in this case one way can be:

1-pick the highest layer (i think it will be cleaner to sort the tree branches by height)

2-select the actual terrain (in this case it is the one with smaller area, but what if in another case is the bigger?)

3-pick a point inside it

4-in the other layers, pick the surfaces where this point falls inside (works if your model has only one hill)

this works in a model with one hill and n valleys.

if you have n hills and only one valley do the opposite, start from bottom and go up.

if you have n hills and valleys I don’t know

Yeah, me too, for the last 8 years :rofl:

I would consider making a patch/mesh approximation of the terrain and extrude it down - any surface centers that are inside the mesh can be kept then

1 Like

In my experience, trying to determine which curves are which is a losing game. Instead, I do it the dumb way: Make a brep of the terrain and slice it to reveal flat surfaces.


terrain_generation_TN.gh (55.6 KB)

(If it’s dumb and it works, it ain’t dumb, right? :smiley: )

This uses Patch to make the terrain surface. Increase the Spans for better accuracy.
It also uses Planar to tease out the result, which is quite slow. There may be a faster way, but this is reliable.

EDIT: I see @Artstep had the same intuition, but you can’t check for surface centres. A C-shaped surface would have a centre outside its boundary. Pop Geo might work to get a testing point, but I can imagine some edge cases slipping through at the edge of tolerance.

2 Likes

I took some inspiration and came up with this

terrain_generation_for_laser_cutting_FF.gh (51.7 KB)

key points:

-approximate global terrain

-popgeo 1 point each cutted srf in each layer

-take only srf that have the point below the terrain approximation

BUT:

terrain approximation and popgeo can lead to a point near edge, actually above terrain when not wanted

so, the terrain approximation and the srf must be builded on the exact same points/borders

to achieve this i convert the layers in meshes and use their vertexes to build a delaunay mesh for the terrain approximation

the popgeo is done on the meshed srf so the comparison between the point and the terrain should be consistent (i hope)

2 Likes

Ah yes of course a mesh is much better way of going about it! Good work :slight_smile:

Thank you all for the incredible support and the variety of approaches. It seems that a flawless, “universal” vector-based solution using Surface Split—one that handles every edge case (like coincident boundaries) without complex data management—is quite elusive.

Here is a summary of the results for my specific case:

@Tom_Newsom
Thank you for the mesh-based approach. While I was initially hesitant to switch from exact NURBS curves to a Mesh approximation (due to the slight deviation in the final laser path), I have to admit this is the most robust solution. It handles islands, holes, and complex topologies without breaking. I will likely proceed with this method for production.

@Fabio_Franchetti
Your definition is extremely close to a perfect exact solution! The logic is elegant. However, I found that it fails in specific edge cases where the contour curves touch or coincide with the boundary of the working area. If those edge conditions were resolved, it would be the perfect vector solution.

Thank you for the effort!

@Artstep
Thank you for kicking off the discussion and for your suggestions regarding the surface filtering logic.

I really appreciate the help from this community!

1 Like

I have to say though, if you’re laser cutting and you’re not overly concerned with wastage, why not just separate each Z-level’s curves into an array and cut them all next to each other? Then use your clever human eyes to figure out which bits are solid and which are void during assembly.

You can even use the void parts as a jig to line everything up while gluing.

2 Likes

I understand your logic and in this specific case it would be the way. But this case is just for the testing. For the laser cut the final model is much more complex with much more layers.

Here’s another idea:
terrain_generation_for_laser_cutting.gh (56.5 KB)

@sajmy11,

Can you test or is there a way for you to share the actual contours so we can test ideas on that instead? :cowboy_hat_face: I guess I’d be concerned about overall orientation of your actual file. The example I share uses BoundingBox, for which specific ‘local’ planes might be needed if you’re not parallel to Rhino XY.

Cheers

1 Like

Sure. Here you are.

terrain_generation_for_laser_cutting.gh (2.7 MB)

1 Like

Understood. Some advice from experience: Make sure each “peak” has at least two, preferably more, registration holes cut into it, from the second-highest layer all the way to the bottom, so you can thread the layers onto rods for perfect alignment.

Ok, the scale of this data makes things quite a bit more difficult. My patch surface method is going to choke to death on it, and the mesh version is likewise going to struggle. The mesh version also won’t adequately capture all the vertical detail.

I’ll see what I can come up with but this looks very challenging!

1 Like

Agree :thought_balloon:

Also these contours are more problematic, some of them do not really intersect the provided ‘plane’, so splitting won’t work, each contour might require its own ‘local’ bounding rectangle.

Before I stay up all night trying to implement this, I think the method would go something like this:

  1. Surface Split every plane to get fragments
  2. Starting at the bottom, take a point on each curve and project it upwards
  3. Every fragment it hits must be a void (the very top level should be peppered with hits)
  4. Cull voids

Quite how you structure that in terms of GH data I don’t know.

I’m also not 100% sure if it would need “seeding” with manual identification of the lowest voids. Haven’t fully wrapped my head around it.

2 Likes

Here’s the bones of it. Expert tree wranglers, assemble!

terrain_generation_draft.gh (2.8 MB)

Need to create a new tree where each branch #n contains every item from the source tree where the path is #<=n, if that makes any sense.

3 Likes

terrain_generation_for_laser_cutting_jt.gh (96.4 KB)

2 Likes

Thanks—nice challenge!

Tried my best for a bit, it’s not where I thought it’d be, but maybe it’s a start!

I thought the fragment with the most edges (segments) per set (after split) would correspond to the required/needed contour.

Also, not sure if the white group (or any elevation-based sorting, really) is needed for the operation, but left it there anyway.

Here’s the attempt (split takes ~1.5 minutes). Maybe I’ll revisit with fresh eyes:
terrain_generation_sort-by-segment-count.gh (2.8 MB)



1 Like