Coloring faces of terrain using Ruby

This is last step I would like to do with my terrain in SU 8.

In the old model I used one color for one level of terrain / contour. The terrain height is from 600m ASL to 789m. One level usually have 3m. So in this model there should be 3m gaps between the horizontal faces.

exploded.skp (2.4 MB)

In new model I have created the hills and I would like to apply colour to them on the logic of old model. So when the faces are on 600-602m ASL, material “600” should be applied to any faces in this level. If the faces are on 603 to 605m of elevation then it should have material “603”, etc.
Notice there is some exception on some of the tops/vertexes, where this may not fit the step of 3m.

This the model, where the material should be applied on faces:
terrain_ready.skp (4.1 MB)

Hopefully you can help me with this.

1 Like

The contours faces don’t stop and start exactly level so there’s some overlap of colours.

I might have messed around with your scenes a bit:
exploded gm.skp (5.3 MB)

If you get the Ruby working you can tweak the results yourself. It doesn’t handle missing materials very well yet.

# encoding: UTF-8
module GM
  module ContourColour
    extend self

    def set_material(face, material)
      face.material = material
        @bad_materials += 1
    def colour_contours
      puts ("colour_contours")
      model = Sketchup.active_model
      model.start_operation("Contour Colour", true)
      ents = model.active_entities
      faces = ents.grep(Sketchup::Face)
      puts ("Contour Colour found #{faces.size} faces")
      @bad_materials = 0
      use_centre = false
      faces.each do |f|
        if use_centre
          #Find height of centre of bounding box of each face
          centre =
          centre_height = centre.z
          height_m = centre_height.to_m.to_i
        else #Use lowest vertex
          lowest = 10000.m
          f.vertices.each do |v|
            lowest = v.position.z if v.position.z < lowest
          end #f.vertices.each
          height_m = lowest.to_m.to_i
        # height_m contains the height in m of the centre of the face
        # Now needs rounded to nearest 3m
        rounded_height = (height_m - 600) / 3 * 3 + 600
        material_name = rounded_height.to_s
        set_material(f, material_name)
      end #faces.each
      puts ("#{@bad_materials} materials missing")
    end #colour_contours
    # Run Once at startup block here:
    this_file = Module::nesting[0].name << ':'<< File.basename(__FILE__)
    unless file_loaded?( this_file )
    menu ="Plugins").add_item("Contour Colour") {self.colour_contours}
    file_loaded( this_file )
    end #unless
  end #ContourColour
end #GM

Psychedelic early attempt:


Wow. It is wonderful! Thank you very much!
How to you execute such code in file from Ruby console? Do you save it into file? I

Put the file in your Plugins folder then in the console:

load 'ContourColour.rb'

Or just restart SketchUp.
ContourColour.rb (1.6 KB)
Open the contour group for editing, then choose “Contour Colour” from the Plugins menu.

1 Like

I tested the code and it works for me.

I have a note.

Something changed because some* edges were hidden and now they are visible. Which looks ugly. But it would be great to keep the original countour edges (horizontal ones). So can you yet modify this code to keep the countour lines (horizontal edges) visible, but to keep the “vertical”* edges hidden? As vertical* edge I mean any edge which does not have starting and ending point y axis same value.

So it would be perfect result if the original black countours stay untouched and rest of edges are hidden.

You could just superimpose the original contour lines back on top of the surface that the sandbox tools created like this:

Contour with edges.skp (3.1 MB)

The problem is that the sandbox faces don’t include the origin contour lines, they’ve been smoothed out. The contour lines sometimes disappear inside the surface and the colours go above and below the lines. To make it better, you could try one or all of the lofting extensions available.

If the surface could be formed while still preserving the original contour lines, it would look much tidier. Maybe some of the lofting extensions would give better results for this. If the faces didn’t overlap into the next or previous contour, this extension would colour them in separate layers that won’t overlap in the z-axis (blue).

Now I see why the material 678 was missing. I have renamed it by mistake as 378. So I have fixed the material with the values from 378. So I have finished everything. Thanks for the job.

You may want to have a look at FredoTools::ColorByAltitude.

The coloring of faces is done with a single texture (instead of painting face by face), so that you get continuous iso-borders between colors. You can also design your palette of colors.

Here is a quick trial.

I guess you should clean up the out-borders of the terrain, may be make a clean skirt.


1 Like

While I was at it, I cleaned up the contour lines and processed it with TopoShaper, and then applied the colors. I also generated the 2D color map and the legend, as well as the generated isocontours.

Barracuda - terrain_ready …and clean.skp (7.8 MB)

And here is the video about FredoTools::ColorByAltitude


Hello Fredo,
is it possible to install these plugins on SU8?

One advantage of the colors in original model is that I can get height of the terrain by picking the color. I see the height when I see the color name. I’ll look on it

But your solution looks clear and nice.

ColorByAltitude runs on Sketchup 2018 and above.

Sorry, but I cannot open your file, I use SU8 and your file is newer.

Here is the skp file in SU8

Barracuda - terrain_ready …and clean - SU8.skp (7.2 MB)

Thank you. So I have exchanged the black countours and I use the ones you added to separated group. My opinion is that the rainbow color is not so nice as the colors I have used before because my colors make it easier to distinguish the countours by color while the rainbow makes the color tones too fine. But I appreciate more details in the terrain.