7
Designing Big Projects

In this chapter, you’ll extend the lessons you’ve learned so far to build a complex design with OpenSCAD. Specifically, you’ll employ an iterative design cycle to plan and complete a larger project. First, you’ll apply computational thinking to analyze and plan your design. Then, you’ll apply the popular walking skeleton approach to evolve a low-fidelity prototype from a basic, abstract design into a highly detailed final design. Using this method, you’ll connect all the project’s major components before fleshing out each component’s individual details. As a final step, you’ll fill in the smaller details to finish the project.

The Design Cycle

The design cycle is a common methodology with four sequential stages to help develop solutions to complex design projects:

Investigate

  1. Understand what you’re trying to accomplish. What important considerations or constraints might affect your solution? What do you need in order to accomplish your goals? Can you picture what you’re trying to build?

Plan

  1. Divide the process for building your solution into a series of steps. Because you’re designing with OpenSCAD (a programming language), you can apply computational thinking concepts (decomposition, abstraction, finding patterns, and algorithms) at this stage of the design cycle to identify the best approach to accomplish your goals.

Create

  1. Follow your plan. Creation often reveals new problems, so it’s better to build big-picture solutions before focusing on the details. Using a walking skeleton approach to develop a complex design can help make it easier to repeat the Create stage several times. Each repetition of the Create stage (called a design iteration) adds more detail to the overall design, allowing you to focus on the most important structural details first.

Evaluate

  1. Compare each iteration of the Create stage (what you’ve actually built) with the original problem (what you intended to build). Identify areas of concern and then repeat any step of the design cycle as needed.

Keep in mind that the stages of the design cycle are more like a looping cycle. You will probably revisit stages several times throughout the process until you are satisfied with your final design.

Leaning Tower of Pisa Model

Let’s follow the design cycle to create a model of Italy’s famous Leaning Tower of Pisa (Figure 7-1).

The focus of this project is to combine the design process with computational thinking, so we’ll create a recognizable likeness of this famous building, rather than an architecturally accurate scale model.

f07001

Figure 7-1: The Leaning Tower of Pisa (photo by Svetlana Tikhonova, covered by the CC0 1.0 Universal [CC0 1.0] Public Domain Dedication license; replicated in Figures 7-2 to 7-4)

Step 1: Investigate—Define Multiple Views

The first step is to search for photos of the Leaning Tower of Pisa to help visualize the final design. We collected images showing different views to provide a sense of what the building looks like from every angle, including front, back, left, right, and top. We (unsurprisingly) couldn’t find a photo of the bottom view, but we looked for photos that clearly show how the tower interacts with the ground.

The Investigate step of the design cycle is important even if you want to build something of your own invention. If you can’t find an exact picture of what you want to build, look for something similar. If you don’t have any luck, sketch a rough draft of your intended design by hand. Visualizing your design before you code it will save you much time and frustration. The idea is to draw a map of your development process before typing a single line of code.

Step 2: Plan—Apply Computational Thinking

With a firm understanding of what the Leaning Tower of Pisa looks like, you’ll analyze the building to identify where you can apply the principles of computational thinking: decomposition, patterns, abstraction, and algorithms. Applying these principles when creating designs with OpenSCAD (or any other programming language for that matter) will help you work smarter, not harder, and will allow the computer to do the tedious work for you.

Decomposition

Decomposition is the process of breaking a large, complex problem into smaller, easier-to-describe subproblems, which helps you recognize when to create modules and separate files for a large project. One way to decompose the Leaning Tower of Pisa is to divide the building into three distinct sections (bottom, middle, and top), all of which are “leaning” at the same angle. You then can break those three sections into smaller subcomponents, like columns, levels, fences, and archways (Figure 7-2).

f07002

Figure 7-2: Using basic decomposition to break the tower into smaller components

Patterns

Finding patterns in a design is a bit like decomposition, because the goal is to break a complex design into smaller, more manageable pieces. However, the objective with patterns is to summarize the process by which elements repeat (Figure 7-3).

f07003

Figure 7-3: Patterns of repeating shapes

For instance, the middle section of the Leaning Tower of Pisa is composed of essentially the same group of shapes repeated six times. Each of those “levels” also includes repeated arches/columns around its outside circumference. In fact, both the bottom and the top sections also contain repeated arches/columns (although at different sizes and intervals from the middle section). Additionally, the top section has two fences with repeated posts, as well as a repeated archway shape in numerous sizes.

Abstraction

Abstraction is the process of summarizing smaller details with higher-level descriptions in order to communicate big-picture information. Rendering each section of the Leaning Tower of Pisa as a cylinder is a general abstraction that omits a lot of detail (Figure 7-4).

f07004

Figure 7-4: Diagram of the Leaning Tower of Pisa abstracted as three cylinders

Abstracting the three sections as cylinders allows you to focus on larger elements (like the angle of the tower’s lean and each section’s proportional sizing) before considering the smaller, less consequential features.

Algorithms

Because so much repetition exists within the Leaning Tower of Pisa’s architecture, our design algorithm for creating the tower requires numerous loops. For instance, the columns around the tower’s perimeter involve a loop that repeatedly increments the angle of rotation. The looping columns occur in all three sections (bottom, middle, and top), although each section contains different numbers of repeating columns of various sizes.

The multiple use cases for the different sizes of columns around the tower’s perimeter suggest that a parameterized column module would be an appropriate algorithmic choice; incorporating parameters in the module allows you to reuse the same basic code for each section of the tower. In fact, the design for this project provides many opportunities to use modules in your code. Each of the basic components you identify during a project’s Decomposition and Patterns analysis will likely be a candidate for a module. In this case, you can create modules for the top section, middle section, bottom section, level, column, archway, and fence.

Step 3: Create—Use a Walking Skeleton Approach

The goals of the first two steps of the design cycle are understanding what you want to build and creating a well-defined strategy for breaking a large, complex project into a collection of manageable pieces. In step 3, you start coding by using the walking skeleton development process, allowing you to evolve the design from rough building blocks into a final highly detailed finished piece. You’ll use this approach to create several versions of the tower, making incremental improvements with each design iteration (Figure 7-5).

f07005

Figure 7-5: Using the walking skeleton approach for the evolution of the Leaning Tower of Pisa

The first versions of the top, middle, and bottom sections in Figure 7-5 are rough abstractions of the final, detailed versions of those same sections. The design’s main pieces are connected first as an architectural skeleton, then fleshed out over time in an evolutionary process—hence the name, walking skeleton.

Step 4: Evaluate—Decide Which Design Process Steps to Repeat

The “final” step of the design cycle is more of a question than anything else. Does your design accomplish what you intended? Based on the answer, decide which steps of the design process you need to revisit.

To answer that question for the tower example, you’ll visually compare the rendered OpenSCAD model of the tower with a photograph of the real Leaning Tower of Pisa. In fact, you’ll apply the Evaluate step after each iteration of the walking skeleton to determine which features to add for the next iteration.

Walking Skeleton: Building the Leaning Tower of Pisa

For the remainder of this chapter, you’ll build several versions of the Leaning Tower of Pisa in a series of design iterations to demonstrate the walking skeleton development process. Each version will add more details, so you’ll compare each iteration with the reference photo and reconsider your plan and algorithms as you go. This approach allows you to apply the design cycle to each iteration without having to worry too much about the way the code is organized or connected.

Iteration 1: Connecting the Tower’s Basic Building Blocks

The goal for the first version of the tower design is to create and connect the building’s three sections: top, middle, and bottom. You’ll also include a platform for stability (the tower is leaning, after all).

Decomposing the building’s overall design into smaller pieces provides the setup to evolve the design in stages, as you’ll be able to edit the tower’s various sections independently. Initially, you’ll generate only basic cylinders as big-picture approximations of each section’s design, because the first stage of a walking skeleton focuses solely on connecting the project’s separate building blocks (Figure 7-6).

f07006

Figure 7-6: An abstract tower with three sections

Although you could use a series of modules contained within one very large file, you’ll instead separate these sections into stand-alone files (bottom.scad, middle.scad, and top.scad) and create one connector file (tower.scad). Having the code in separate files allows you to create, find, and edit relevant modules for each section easily. You could also use this multi-file approach to collaborate with others, so each person could focus on a different file simultaneously.

The trickiest part of this first step is considering how the different components of the design interact with each other. Usually, this means identifying the crucial information each piece of the design needs in order to be drawn. For instance, to draw an abstract, cylinder-based representation of each section, you need, at minimum, a height and radius for that section. The main project file (tower.scad) will communicate that information to each section via module parameters.

Because the top, middle, and bottom sections all use a cylinder as an abstract representation of the final design, creating those files first is relatively easy. The code for each section looks very similar at this stage of the design, which is another advantage of abstraction. You don’t need to worry about small details at the moment, so you can copy and paste code in the three files with only minimal changes.

The bottom.scad file defines a cylinder to create a simple version of the tower’s lowest section:

// bottom.scad v1
1 module bottom_section(width, height) {
    radius = 0.5 * width;
    cylinder(h=height, r=radius);
}

The tower.scad file communicates the dimensions for the bottom section to the bottom_section module via the width and height parameters 1.

Next, the middle.scad file defines a starting version of the middle section:

// middle.scad v1
1 module middle_section(width, height) {
    radius = 0.5 * width;
    cylinder(h=height, r=radius);
}

Again, the tower.scad file communicates the width and height to the middle_section module via the width and height parameters 1.

Similarly, the top.scad file defines a basic cylinder to represent the tower’s top section:

// top.scad v1
1 module top_section(width, height) {
    radius = 0.5 * width;
  2 cylinder(h=height, r=radius);
}

As with the bottom and middle sections, the tower.scad file uses parameters to supply needed dimensions to the top_section module 1. The order and number of parameters in each of the three modules is the same. This is a deliberate choice to simplify the design’s architecture. As the complexity of the design increases, this consistent interface between top.scad, bottom.scad, middle.scad, and tower.scad will make adjusting the proportions of each section easier. The decision to think of each cylinder’s measurements in terms of the structure’s radius rather than its diameter 2 was also deliberate (though somewhat arbitrary). At this stage, using width as the cylinder’s diameter would also make sense.

Next we create tower.scad, which provides the necessary dimensions and connects the tower’s three sections with the platform:

// tower.scad v1
1 use <bottom.scad>
use <middle.scad>
use <top.scad>

2 tower_height = 100;
tower_width = 0.3 * tower_height;
bottom_height = 0.2 * tower_height;
middle_height = 0.65 * tower_height;
top_height = 0.15 * tower_height;

base_width = 2 * tower_width;
base_height = 0.1 * tower_width;

lean_angle = 4;

3 $fn = 20;

4 rotate([lean_angle, 0, 0]) {
    color("grey") {
        bottom_section(tower_width, bottom_height);
    }
    color("lightgrey") {
        translate([0, 0, bottom_height])
            middle_section(tower_width, middle_height);
    }
    color("white") {
        translate([0, 0, bottom_height + middle_height])
          5 top_section(tower_width, top_height);
    }
}

color("lightgreen") {
 6 cube([base_width, base_width, base_height], center=true);
}

The first section of the tower.scad file links to the three files described previously that define the tower’s top, middle, and bottom sections 1. The next section defines variables to help organize the tower’s important characteristics 2.

Since the design includes not only the tower but also a platform for stability, you create variables to organize the overall tower’s height and width (tower_height and tower_width), the height of each section of the tower (bottom_height, middle_height, and top_height), the height and width of the platform (base_height and base_width), and the overall angle of the “lean” of the tower (lean_angle). You initially set the tower_height variable to an arbitrary value, and then use it as part of the definition for most of the other variables. For instance, the height of the bottom section is 20 percent of the tower_height variable, so if you want to change the size of the entire design, you need to change only the tower_height variable’s value.

Next, you use a relatively small number of segments (20) to approximate curved shapes to speed up the rendering of the initial designs 3. The last design iteration increases the number of segments to 100 in order to generate smoother curved surfaces in the final design.

To avoid duplicating the same rotate operation for all three sections, you use a single operation to apply a consistent angle of rotation to each of the three sections 4. Each section is called via the appropriate module, with parameters to adjust its width and height. The translate operation moves the middle and top sections along the z-axis 5.

Finally, you draw the platform as a simple cuboid 6. You also apply different colors to the ground and each section to signify basic proportionality.

From this point on, you won’t need to make major changes to the tower.scad file. Your initial efforts to size and place each section correctly will form the architectural “skeleton” of the tower design, while your next design iterations will fill in missing details for the tower’s top, middle, and bottom sections. The only changes you might need to make to this file in the future would involve adjusting parameters to tweak proportionality as your design evolves, or changing $fn to increase the rendered model’s smoothness. You’d simply swap out numerical values rather than write new code statements to make those changes.

Iteration 2: Finding Repetition in the Middle Section

Let’s take a closer look at the tower’s middle section (middle.scad) for the second iteration and apply some computational thinking techniques from the planning stage—namely, decomposition and finding patterns. In the middle section, the same collection of shapes (or levels) repeats vertically six times (Figure 7-7).

f07007

Figure 7-7: Abstract Leaning Tower of Pisa with a looping middle section

Figure 7-8 shows just one of those repeated level shapes.

f07008

Figure 7-8: A single level shape

To create these repeated levels, you need to make the following changes to the middle.scad file:

// middle.scad v2
level(50, 25);

module middle_section(width, height) {
   level_height = height / 6;
   level_radius = 0.5 * width;

 1 for (h=[0:1:5]) {
     floor_offset = h * level_height;
       
     translate([0, 0, floor_offset]) 
       level(level_radius, level_height);
   }
} 

2 module level(level_radius, level_height) {
    lip_height = 0.1 * level_height;
    inner_radius = 0.7 * level_radius;
    overhang_height = 0.3 * level_height;
  3 overhang_radius = 0.95 * level_radius;
    
    // lip
    translate([0, 0, level_height - lip_height])
      cylinder(h=lip_height, r=level_radius);
    
    // overhang
    translate([0, 0, level_height - lip_height - overhang_height]) 
       cylinder(h=overhang_height, r=overhang_radius); 
    
    // inner structure
    cylinder(h=level_height, r=inner_radius);
}

These changes add more detail to the middle section so it’s no longer an abstract cylinder. The level module 2 organizes all the shapes that construct each floor of the middle section, and a for loop 1 creates a new level shape repeatedly for each of the six floors in the section. Each level of this section now includes a lip that extends to the full radius of the tower, an overhang that provides a ceiling for columns, and an inner structure to house stairs, doors, and so forth. You create several variables to relate the size of each level feature (lip_height, inner_radius, overhang_height, and overhang_radius) to the level module parameters (level_radius and level_height) 3.

With this repeating level module, you can simultaneously update all six floors at once by making a change in exactly one place. For instance, if you want to make each level’s lip a little thicker or change the overhang radius to provide more room for columns, you can make a single, simple change to the level module definition. Because you are adding detail to only the middle_section module in this phase of our walking skeleton approach, middle.scad is the only file you needed to update for the second iteration of the tower design.

To see these new changes reflected in the overall design (Figure 7-7), save middle.scad, and then preview the entire design in tower.scad. In addition to making your design changes permanent, saving the middle.scad file lets OpenSCAD know you want other files to use the updated code. If you want to see the middle_section or level shapes in isolation, create the shape at the top of middle.scad and then preview that file. You can include a statement to draw a middle_section or level shape in middle.scad without worrying that the shape will also automatically show up in other files. Connecting another file with middle.scad with a use directive simply means that module definitions from middle.scad will be accessible in tower.scad. No drawn shapes from middle.scad will be shown unless the connected file uses a module from middle.scad.

Iteration 3: Adding More Details to the Middle Section

The next pattern to consider in your computational thinking is the repetition of columns and arches along each floor’s perimeter in the middle section (Figure 7-9).

f07009

Figure 7-9: A level with repeated columns

To apply these new patterns to the design, you create a column shape and repeat that new shape along the circumference of the level module. This means you need to modify the middle.scad file again, as that’s where the level module is defined. To create a column shape, you also define a column module in a new column.scad file.

In the design cycle’s planning phase, you noticed that columns and arches repeat around the circumference of each of the tower’s three sections. Because you need to include column shapes in multiple files, defining the column module in a separate file makes it easier for different sections to use that new shape definition. Columns and arches repeat in different patterns in each section, and they also vary in their ornamentation. That’s why at this initial stage, you’ll focus on creating an abstract column with basic components (Figure 7-10). You can then update this basic definition of a column in a later design iteration.

f07010

Figure 7-10: An abstract column

Creating a column module in a separate file called column.scad makes it easier to share and evolve your use of columns in the future as needed:

// column.scad v3
1 module column(col_width, col_height) { 
    col_radius = 0.5 * col_width;
  2 orn_height = 0.05 * col_height; 
     
    translate([-col_radius, -col_radius, col_height - orn_height]) 
        cube([col_width, col_width, orn_height]);
    cylinder(h=col_height, r=col_radius);
    translate([-col_radius, -col_radius, 0]) 
        cube([col_width, col_width, orn_height]);
} 

As with other modules, you include two parameters (col_width and col_height) in the column module 1 to provide the necessary information to create a column shape. Based on the column height and column width, variables are created (col_radius and orn_height) to describe the column’s radius and the ornamentation’s height included at both the top and bottom of a column 2. While it may seem to make the module definition more complicated, defining and using these variables rather than placing repeated arithmetic calculations as module parameters or inside operations reduces the number of possibilities for error, groups all of the design assumptions at the top of the module, and makes it easier to update all uses of a measurement.

To invoke this new column module, you then modify the level module in middle.scad to draw repeating columns and arches around the circumference of each level:

// middle.scad v3
1 use <column.scad>
...
module level(level_radius, level_height) {
  2 lip_height = 0.1 * level_height;
    inner_radius = 0.7 * level_radius;
    overhang_height = 0.3 * level_height;
    overhang_radius = 0.95 * level_radius;
    
    num_cols = 24;
    angle_size = 360 / num_cols;
    
    col_height = 0.65 * level_height;
    col_width = 0.2 * col_height;  
    
    arch_depth = 2 * (level_radius - inner_radius); 
    
    // lip
    translate([0, 0, level_height - lip_height])
        cylinder(h=lip_height, r=level_radius);

    translate([0, 0, col_height]) {
        difference() {
            // overhang
            cylinder(h=overhang_height, r=overhang_radius); 
           
            // arches
            3 for (i=[0:1:num_cols-1]) {
                angle = i * angle_size + angle_size/2;
                rotate([0, 0, angle])
                    translate([inner_radius, 0, 0]) 
                        rotate([0, 90, 0]) 
                            cylinder(h=arch_depth, r=col_width, center=true);
            }
        }
    }

    // inner structure
    cylinder(h=level_height, r=inner_radius);
    
    // columns
    4 for (i=[0:1:num_cols-1]) {
        angle = i * angle_size;
        rotate([0, 0, angle])
            translate([overhang_radius - 0.5 * col_width, 0, 0]) 
                column(col_width, col_height);
    }
}

Comparing this updated version of middle.scad with the version from your second design iteration reveals three major additions to the level module. First, column.scad is connected to this file 1 with a use directive so that you can use the new column module to draw column shapes in this file. Next, variables are defined to describe the number of columns per level (num_cols), the angle at which the columns should be repeated along the circumference of the tower (angle_size), the width and height of each column (col_width and col_height), and the depth of the arch connecting every two columns that will be carved away from the overhang of each level (arch_depth) 2.

After creating the overhang, you include a for loop within a difference operation to carve away arches between the location of each column 3. A final for loop repeats columns along the level’s circumference 4. You could combine these two loops into a single for loop that uses an if statement; however, the loops are separated here to make the logic clearer.

As before, to see these new changes reflected in the overall design, save both middle.scad and column.scad; then preview the entire tower design in tower.scad. To see only the middle section without the rest of the tower, include a statement to draw a middle_section shape at the top of middle.scad; then preview the design in middle.scad. You can also easily see only a column shape by including a statement to draw a column shape at the top of column.scad and then previewing the design in that file.

After using a relatively small amount of code to add a large number of repeating columns and arches to the middle section, that section of the tower (Figure 7-11) is now more recognizably similar to our reference photo of the Leaning Tower of Pisa (Figure 7-1).

However, as you can see in Figure 7-11, the top and bottom sections are still abstract simplifications. Applying the design cycle’s Evaluate step after each iteration of the walking skeleton helps identify missing details that might offer the most noticeable improvements to a design. After this iteration, you should once again consult the reference photo (Figure 7-1) to decide which section of the tower now most needs improvement.

f07011

Figure 7-11: Leaning Tower of Pisa with modularized columns

Iteration 4: Adding Details to the Top Section

The top of the tower is missing fences, repeating columns, and archways (windows and doors), so the next iteration focuses on adding those details. You’ll add two fences to the top section, as well as alternating archways of different sizes and heights (Figure 7-12), so you’ll modify top.scad by adding a fence module and an archway module. You’ll draw the archway module in different sizes to create the doors and windows shown in the top section of our reference photograph (Figure 7-1).

f07012

Figure 7-12: Fenced-in top section with alternating archways of different sizes

This updated version of the top.scad file adds the fence and archway details to the tower’s top section:

// top.scad v4

module top_section(width, height) {
  1 top_radius = 0.4 * width;
    room_radius = 0.75 * top_radius;
        
    num_doors= 5;
    door_angle= 360 / num_doors;
    
    overhang_height = 0.1 * height;
    overhang_width = 1.1 * top_radius;
    
    door_height = 0.6 * height;
    door_width = 0.35 * height;
    
    window_height = 0.25 * height;
    window_width = 0.15 * height; 
    
    // overhang
    translate([0, 0, height - overhang_height])
        cylinder(h=overhang_height, r=overhang_width);  
    
    //inner structure
    difference() {
        cylinder(h=height, r=top_radius);  
        
        translate([0, 0, 1]) {
            cylinder(h=height-2, r=room_radius);
            
            2 for (i=[0:1:num_doors-1]) {
                angle = i * door_angle;
                rotate([0, 0, angle])
                    translate([top_radius-2, 0, 0.25*height]) 
                        // doors
                        archway(door_height, door_width, room_radius);
                rotate([0, 0, angle+0.5*door_angle])
                    translate([top_radius - 2, 0, 0.6*height]) 
                        // windows
                        archway(window_height, window_width, room_radius);
            }
        }
    }
    
    //fencing
    translate([0, 0, height]) 
        fence(15, 3, top_radius, 1);
  3 fence(20, 3, 0.5*width, 1); 
}

4 module fence(num_posts, fence_height, fence_radius, post_width) { 
    post_radius = 0.5 * post_width;
    angle_size = 360/num_posts;
    ring_height = 0.5;
    post_height = fence_height - ring_height;

    translate([0, 0, post_height])
        ring(fence_radius - post_width, fence_radius, ring_height); 
    translate([0, 0, post_height / 2])
        ring(fence_radius - post_width, fence_radius, ring_height);

    for (i=[0:1:num_posts-1]) {
        angle = i * angle_size;
        rotate([0, 0, angle])
            translate([fence_radius - post_radius, 0, 0])
                cylinder(h=post_height, r=post_radius);
    }
}

5 module ring(inner_radius, outer_radius, height) { 
    difference() {
        cylinder(h=height, r=outer_radius);
        translate([0, 0, 1])
            cylinder(h=height+2, r=inner_radius, center=true);
    }
}

6 module archway(height, width, depth) { 
    radius = 0.5 * width;
    
    rotate([90, 0, -90]) {
        translate([0, (height - radius) / 2, -depth / 2])
            cylinder(h=depth, r=radius);
        cube([width, height - radius, depth], center=true);
    }
}

As with the other module definitions, you begin by defining variables to describe the top section’s various features 1. You base the number of windows on the number of doors (num_doors), but otherwise, you deliberately choose variable names that are self-documenting. A for loop contained within a difference operation subtracts repeated windows and doors from the top section’s inner structure 2. Windows and doors have similar shapes, so you define a single archway module that lets you vary the size of window and door shapes with the height, width, and depth parameters 6.

The top_section module ends by drawing two fence shapes 3. These fences are basically the same shape but different sizes, so you define a fence module to construct them 4. You also include a ring module to make it easier to create various fencing rings 5. This definition of a ring module is transferred from a previous Design Time activity (see Chapter 5). Reusing modules from prior projects can save a lot of time and effort.

To simplify the project’s organization, you include the fence, ring, and archway modules only in the top.scad file since no other section contains those shapes. As with previous design iterations, save your updates to top.scad; then preview the design to see those changes in other files.

The top_section module now produces a more detailed version of the top of the tower (Figure 7-13).

f07013

Figure 7-13: Fenced-in top section with alternating archways, detail view

Comparing this design iteration with the tower’s reference photo (Figure 7-1), your evaluation suggests that the bottom section now needs the most attention.

Iteration 5: Adding Details to the Bottom Section

This update modifies the bottom.scad file to include the major missing features (columns and arches):

// bottom.scad v5

1 use <column.scad> 

module bottom_section(width, height) {
    radius = 0.5 * width;
    inner_radius = 0.9 * radius;
    lip_radius = 1.05 * radius;
    lip_height = 0.05 * height;
    overhang_height = 0.2 * height;
    
    num_cols = 14;
    angle_size = 360 / num_cols;
    col_height = height - overhang_height;
    col_width = 0.1 * col_height;
 
    // lip
    translate([0, 0, height - lip_height])
        cylinder(h=lip_height, r=lip_radius);
    
    // inner structure
    cylinder(h=height, r=inner_radius);
    
    // columns
  2 for (i=[0:1:num_cols-1]) {
        angle = i * angle_size;
        rotate([0, 0, angle])
            translate([radius - 0.5*col_width, 0, 0])
                column(col_width, col_height);
    }
    
    // arches
    translate([0, 0, col_height]) 
        difference( ) {
          // overhang
          cylinder(h=overhang_height, r=radius);        
        
          // arches  
          3 for (i=[0:1:num_cols-1]) {
            angle = i * angle_size + angle_size/2;
            rotate([0, 0, angle]) 
                translate([inner_radius, 0, 0])
                    rotate([0, 90, 0])
                      cylinder(h=radius-inner_radius, r=col_width);
        }
    }
}

You first include column.scad in order to access the column module 1. This allows you to use a for loop to draw columns around the bottom section’s perimeter 2. Columns in the bottom section are bigger than those in the middle section, so parameters for drawing a column are set accordingly. You add the arches next, also with a for loop 3.

Save bottom.scad and then preview the design to reveal new details in the tower’s bottom section (Figure 7-14).

f07014

Figure 7-14: Tower with the updated bottom section

The tower is now visually similar to the actual Leaning Tower of Pisa. You can apply the Evaluate stage one more time, but adding more details might not produce much benefit if you intend to make a small 3D print of the model.

Final Evaluation of the Design Cycle

At this stage, the tower looks very similar to the Leaning Tower of Pisa. Making a slight modification to $fn in tower.scad increases the design’s smoothness, providing an even closer likeness (Figure 7-15).

f07015

Figure 7-15: Smoother tower with $fn=100 instead of $fn=20

You left the smallest details for last, which is a deliberate feature of the walking skeleton approach to project development. Every design iteration focuses on one major area, specifically chosen to provide the most noticeable improvement to the overall tower design. As mentioned previously, because you plan to 3D-print this model, you omit especially small details, but could have included the following:

  • The missing columns and arches from the top section.
  • The missing rectangular doorways from the middle and bottom sections.
  • The different ornamentation of columns and arches in each section.
  • Columns are not basic cylinders, so you could have given the top of a column a smaller radius than the bottom.

We mention these missing features as potential exercises for readers who want to continue doing design iterations of this model. Larger 3D prints potentially could reveal those smaller design features.

Design Organization Overview

For your first design iteration, you split the building into three low-fidelity sections, each having a separate .scad file. This way, all you needed to do was preview only one file (tower.scad), because that file connected together the three other files. Figure 7-16 shows the initial project’s organization, which reduced the amount of code in any one file, making it easier to find and modify specific parts.

f07016

Figure 7-16: Initial architecture for the Leaning Tower of Pisa project

Throughout the design process, you used decomposition to find opportunities to break larger components of the tower into smaller pieces. After your last iteration, the project organization evolved to contain many modules and an additional file (Figure 7-17). This final project organization illustrates the main principle of the walking skeleton approach to development. Your initial project organization focused on connecting big pieces of the project, while your final organization reveals all of the smaller details you added incrementally during each iteration.

The organization and development process described here is only one way to build this project. Aside from organizing the project into a different collection of separate .scad files (or even one massive .scad file), you could have created a different set of modules to decompose the tower into smaller building blocks.

We also missed several opportunities to reduce the need for repeating code by including additional if statements or for loops. For instance, you could have created a separate column_ring module to “factor out” the inclusion of columns and arches around the tower’s circumference. With careful use of if statements and parameters, you could have used the column_ring module to draw both the columns and arches in all three sections, greatly simplifying the code required in the top_section, middle_section, and bottom_section modules.

f07017

Figure 7-17: Final architecture for the Leaning Tower of Pisa

A design can evolve over time without major changes to the overall project’s organization. You don’t need to know all the modules or files you’ll need to create at the beginning of a project; you can make those decisions as you gain a better understanding of what you’re building. Each time you apply the Evaluate stage of the design cycle, you have an opportunity to reconsider which changes to make to your design.

Summary

This chapter introduced the benefits of deliberately following the design cycle when building a complex project. You applied computational thinking to guide the planning phase and a walking skeleton approach to combine the Build and Evaluate stages into a looping procedure. You connected the design’s most important features first and then incrementally developed each component’s major features. Only during the final stages of development did you consider the smaller, more nuanced details.

To recap, keep these concepts in mind when designing a complex project:

  • Draw a sketch of the project you want to build, and label it with patterns, abstractions, and decompositions to help you understand how to organize your code.
  • Describing the minimum information needed to draw a new shape can help guide you to understand which parameters might be necessary for a new module.
  • Using self-documenting naming conventions will help organize your code by revealing the purpose of each new variable or module.
  • Use color to help organize different pieces of an evolving design.
  • Make sure to save individual files when you make any changes, so other files can use the newest version of that file.
  • Connect your project’s most important pieces first, even if those pieces are big-picture abstractions.
  • Design a project’s smallest details in the final stages of your walking skeleton development approach.

The design cycle and walking skeleton development model are common approaches, and you can find abundant material online for further reading. We encourage you to explore these concepts further as you create new designs with OpenSCAD.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.90.35.86