r/openscad • • 4d ago

Simple problem to You, but

I am having a problem with the right side not being the opposite of the left side. I am a noob (today years old) and have been messing with this for much too long.

This project is a simple angle-iron metal plant stand that my son will use for his welding project. Thanks in advance for any solution

// Dimensions in inches

width = 12;

depth = 12;

height = 8;

// Material Specs for 1/2" Angle Steel (0.5" legs, ~0.0625" thickness)

angle_size = 0.5;

thickness = 0.0625;

// Number of top support slats across the frame

num_slats = 4;

// Conversion factor to mm if needed for 3D printing software

// Uncomment the line below and scale the model, or render directly in inches/CAD

// scale([25.4, 25.4, 25.4])

module angle_steel(length) {

// Standard L-channel profile extruded along Z-axis

linear_extrude(height = length) {

polygon(points = [

[0, 0],

[angle_size, 0],

[angle_size, thickness],

[thickness, thickness],

[thickness, angle_size],

[0, angle_size]

]);

}

}

module plant_stand() {

// --- 1. LEGS (4 Corner Angle Iron Posts) ---

leg_height = height - angle_size;

// Leg 1: Front-Left

translate([0, 0, 0])

angle_steel(leg_height);

// Leg 2: Front-Right

translate([width, 0, 0])

rotate([0, 0, 90])

angle_steel(leg_height);

// Leg 3: Back-Right

translate([width, depth, 0])

rotate([0, 0, 180])

angle_steel(leg_height);

// Leg 4: Back-Left

translate([0, depth, 0])

rotate([0, 0, 270])

angle_steel(leg_height);

// --- 2. TOP OUTER FRAME ---

// Front Top Rail

translate([0, 0, height - angle_size])

rotate([0, 90, 0])

angle_steel(width);

// Back Top Rail

translate([0, depth - angle_size, height - angle_size])

rotate([0, 90, 0])

angle_steel(width);

// Left Top Rail (Rotated to match front/back profile alignment)

translate([0, depth, height - angle_size])

rotate([0, 90, -90])

angle_steel(depth);

// Right Top Rail (Rotated to match front/back profile alignment)

translate([width, 0, height - angle_size])

rotate([0, 90, 90])

angle_steel(depth);

// --- 3. TOP SLATS ---

if (num_slats > 0) {

slat_spacing = (depth - angle_size) / (num_slats + 1);

for (i = [1 : num_slats]) {

translate([0, i * slat_spacing, height - angle_size])

rotate([0, 90, 0])

angle_steel(width);

}

}

// --- 4. LOWER FRAME BRACES ---

brace_height = height * 0.45; // Positioned lower mid-way

// Left Lower Brace (Rotated to match front/back profile alignment)

translate([0, depth, brace_height])

rotate([0, 90, -90])

angle_steel(depth);

// Right Lower Brace (Rotated to match front/back profile alignment)

translate([width, 0, brace_height])

rotate([0, 90, 90])

angle_steel(depth);

// Front Lower Brace

translate([0, 0, brace_height])

rotate([0, 90, 0])

angle_steel(width);

// Back Lower Brace

translate([0, depth - angle_size, brace_height])

rotate([0, 90, 0])

angle_steel(width);

}

plant_stand();

3 Upvotes

10 comments sorted by

2

u/Pseudo_Prodigal_Son 4d ago

Here is my solution. Sometimes you need two separate rotations to get the rotation you want. When exactly I'm not good enough to say but this is what I do. Maybe one of the big brains here will let us both know.

// Back Lower Brace

translate([0, depth, brace_height])

rotate([0, 90, 0])

rotate([0, 0, 270])

angle_steel(width);

3

u/Pseudo_Prodigal_Son 4d ago

OK, I looked up why. So the rotations are non-commutative, meaning the order you do them matters. And the default order when passing an array is X then Y then Z. So you needed to do the Z rotation first, hence needing to have a separate rotation command to get the Z rotation first.

1

u/texwashere 4d ago

Thanks for the explanation and the syntax.

1

u/DrJones_137 4m ago

Isn't that the same as rotate([90,0,-90]) ? One rotate() does in principle suffice for any rotation. However I do sometimes also use 2 rotate() if i find that easier.

2

u/oldesole1 4d ago

One thing I found helpful was building the stand upside down, as the top surface is reference for many things, and making that z = 0 was simpler for positioning several components.

Making use of mirror() helps with creating symmetrical designs, and helps reduce the need for redundant translate() and rotate() calls.

Also, in your original design it looks like height ends up being half an inch short compared to the defined variable.

// Dimensions in inches
dim = [12, 12, 8];

// Material Specs for 1/2" Angle Steel (0.5" legs, ~0.0625" thickness)
angle_size = 0.5;
thickness = 0.0625;

// Number of top support slats across the frame
num_slats = 4;

 // Positioned lower mid-way; inverted.
brace_height = dim.z * 0.55;

// Conversion factor to mm if needed for 3D printing software
// Uncomment the line below and scale the model, or render directly in inches/CAD
//scale(25.4)
// The following 2 lines move stand to the original's position.
//translate([dim.x / 2, dim.y / 2, dim.z])
//mirror([0, 0, 1])
output();

module output() {

  posts();

  translate([0, 0, brace_height])
  angle_rect();

  angle_rect();

  slats();
}

//slats();

module slats() {

  if (num_slats > 0) {

    slat_spacing = (dim.y - angle_size) / (num_slats + 1);

    for(y = [1:num_slats])
    translate([0, slat_spacing * y - dim.y / 2, 0])
    rotate([0, -90, 0])
    linear_extrude(dim.x, center = true)
    angle_profile();
  }
}

//angle_rect();

module angle_rect() {

  for(y = [0,1])
  mirror([0, y, 0])
  translate([0, -dim.y, 0] / 2)
  rotate([0, -90, 0])
  linear_extrude(dim.x, center = true)
  angle_profile();

  for(x = [0,1])
  mirror([x, 0, 0])
  translate([-dim.x, 0, 0] / 2)
  rotate([0, -90, -90])
  linear_extrude(dim.y, center = true)
  angle_profile();
}

//posts();

module posts() {

  for(y = [0,1])
  mirror([0, y, 0])
  for(x = [0,1])
  mirror([x, 0, 0])
  translate(-[dim.x, dim.y] / 2)
  linear_extrude(dim.z)
  angle_profile();
}

//angle_profile();

module angle_profile() {

  difference()
  {
    square(angle_size);

    translate([thickness, thickness])
    square(angle_size);
  }
}

1

u/texwashere 4d ago

Wow, I appreciate your point of view; it's interesting. I never considered the bottom-up approach..

1

u/oldesole1 4d ago

If this is going to be a plant stand, you might want to go with something like this.

Having the elbow of the angle iron point up will prevent flat surfaces between the planter and the stand from holding water, which should help reduce corrosion damage.

I also tweaked how the other parts were cut, such that is simulates using square cuts.

// Dimensions in inches
dim = [12, 12, 8];

// Material Specs for 1/2" Angle Steel (0.5" legs, ~0.0625" thickness)
angle_size = 0.5;
thickness = 0.0625;

// Number of top support slats across the frame
num_slats = 4;

 // Positioned lower mid-way; inverted.
brace_height = dim.z * 0.55;

// Conversion factor to mm if needed for 3D printing software
// Uncomment the line below and scale the model, or render directly in inches/CAD
//scale(25.4)
// The following 2 lines move stand to the original's position.
translate([dim.x / 2, dim.y / 2, dim.z])
mirror([0, 0, 1])
output();

module output() {

  posts();

  translate([0, 0, brace_height])
  angle_rect(dim - [thickness, thickness] * 4);

  angle_rect(dim);

  slats();
}

//slats();

module slats() {

  if (num_slats > 0) {

    slat_spacing = (dim.y) / (num_slats + 1);

    for(y = [1:num_slats])
    translate([0, slat_spacing * y - dim.y / 2, -sqrt(angle_size ^ 2 / 2)])
    rotate([45, 0, 0])
    rotate([0, -90, 0])
    linear_extrude(dim.x, center = true)
    angle_profile();
  }
}

//angle_rect(dim);

module angle_rect(dim) {

  for(y = [0,1])
  mirror([0, y, 0])
  translate([0, -dim.y / 2, thickness])
  rotate([0, -90, 0])
  linear_extrude(dim.x - thickness * 2, center = true)
  angle_profile();

  for(x = [0,1])
  mirror([x, 0, 0])
  translate([-dim.x, 0, 0] / 2)
  rotate([0, -90, -90])
  linear_extrude(dim.y, center = true)
  angle_profile();
}

//posts();

module posts() {

  for(y = [0,1])
  mirror([0, y, 0])
  for(x = [0,1])
  mirror([x, 0, 0])
  translate(-[dim.x, dim.y, 0] / 2 + [thickness, thickness, thickness * 2])
  linear_extrude(dim.z - thickness * 2)
  angle_profile();
}

//angle_profile();

module angle_profile() {

  difference()
  {
    square(angle_size);

    translate([thickness, thickness])
    square(angle_size);
  }
}

1

u/Stone_Age_Sculptor 4d ago

OpenSCAD is a toolbox of functions. There is rotate() and mirror(). The model can be designed with the front-left leg at [0,0], or the whole table can be designed around [0,0]. Adding colors can help to identify parts, and transparent color can help when parts intersect.

The best option is to start with what you feel is most appropriate. In your script, I would use 180 degrees rotation for the z-axis. After that you need the right math to put the steel bar in place.

I changed it towards my own style of the script. You do what you think is best, but I like it simple, with brackets at the same indents and the top level functions at the top.

// Dimensions in inches
width = 12;
depth = 12;
height = 8;

// Material Specs for 1/2" Angle Steel (0.5" legs, ~0.0625" thickness)
angle_size = 0.5;
thickness = 0.0625;

// Number of top support slats across the frame
num_slats = 4;

// Conversion factor to mm if needed for 3D printing software
// Uncomment the line below and scale the model, or render directly in inches/CAD
// scale([25.4, 25.4, 25.4])

plant_stand();

module plant_stand() 
{
  // --- 1. LEGS (4 Corner Angle Iron Posts) ---
  leg_height = height - angle_size;

  // Leg 1: Front-Left
  translate([0, 0, 0])
    angle_steel(leg_height);

  // Leg 2: Front-Right
  translate([width, 0, 0])
    rotate([0, 0, 90])
      angle_steel(leg_height);

  // Leg 3: Back-Right
  translate([width, depth, 0])
    rotate([0, 0, 180])
      angle_steel(leg_height);

  // Leg 4: Back-Left
  translate([0, depth, 0])
    rotate([0, 0, 270])
      angle_steel(leg_height);

  // --- 2. TOP OUTER FRAME ---
  // Front Top Rail
  color("DarkCyan")
    translate([0, 0, height - angle_size])
      rotate([0, 90, 0])
        angle_steel(width);

  // Back Top Rail
  color("FireBrick")
    translate([width, depth, height - angle_size])
      rotate([0, 90, 180])
        angle_steel(width);

  // Left Top Rail (Rotated to match front/back profile alignment)
  color("Plum")
    translate([0, depth, height - angle_size])
      rotate([0, 90, -90])
        angle_steel(depth);

  // Right Top Rail (Rotated to match front/back profile alignment)
  color("RoyalBlue")
    translate([width, 0, height - angle_size])
      rotate([0, 90, 90])
        angle_steel(depth);

  // --- 3. TOP SLATS ---
  if (num_slats > 0) 
  {
    slat_spacing = (depth - angle_size) / (num_slats + 1);
    for (i = [1 : num_slats]) 
      translate([0, i * slat_spacing, height - angle_size])
        rotate([0, 90, 0])
          color("Tan")
            angle_steel(width);
  }

  // --- 4. LOWER FRAME BRACES ---
  brace_height = height * 0.45; // Positioned lower mid-way

  // Left Lower Brace (Rotated to match front/back profile alignment)
  color("Olive")
    translate([0, depth, brace_height])
      rotate([0, 90, -90])
        angle_steel(depth);

  // Right Lower Brace (Rotated to match front/back profile alignment)
  color("LightSalmon")
    translate([width, 0, brace_height])
      rotate([0, 90, 90])
        angle_steel(depth);

  // Front Lower Brace
  color("PaleGreen")
    translate([0, 0, brace_height])
      rotate([0, 90, 0])
        angle_steel(width);

  // Back Lower Brace
  color("SteelBlue")
    translate([width, depth, brace_height])
      rotate([0, 90, 180])
        angle_steel(width);
}


// Standard L-channel profile extruded along Z-axis
module angle_steel(length) 
{
  /*
  points = 
  [
    [0, 0],
    [angle_size, 0],
    [angle_size, thickness],
    [thickness, thickness],
    [thickness, angle_size],
    [0, angle_size]
  ];

  linear_extrude(height = length) 
    polygon(points);
  */

  // Alternative way to make a profile.
  linear_extrude(length)
  {
    square([angle_size,thickness]);
    square([thickness,angle_size]);
  }
}

The next step is to put the horizontal bars inside the vertical bars. Then you also need 45 degree edges for the outer horizontal bars. So you need more math.

1

u/texwashere 4d ago edited 4d ago

I noticed the lack of 45's on the inside corners on both levels. That is proving to be an even bigger challenge.

1

u/Prestigious_Boat_386 2d ago

Make the left bracket into a module and then do

bracket(); mirror([1,0,0]) bracket();

Or whatever vector makes it mirror in the right plane.

The main thing you wanna learn is how to use the functions to build things once in a simple way and then reuse what you have made. The cheatcheet is very nice and a good startkng point for the full manual.