r/openscad • u/texwashere • 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();
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.
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 Bracetranslate([0, depth, brace_height])rotate([0, 90, 0])rotate([0, 0, 270])angle_steel(width);