One of the really cool things about METAFONT/METAPOST is that one can assign some variables and have the program solve an equation.
I tried to do something along those lines at:
https://forum.makerforums.info/t/using-openscad-in-lieu-of-a-geometric-solver/91726
and sort of hacked together some workable code:
//!OpenSCAD
beamwidth = 10;
beamheight = 100;
beamthickness = 1;
beamspacing = 40;
module beam(bw, bh, bt) {
cube([bw, bh, bt], center=false);
}
union(){
beam(beamwidth, beamheight, beamthickness);
translate([(beamspacing + beamwidth), 0, 0]){
beam(beamwidth, beamheight, beamthickness);
}
for (i = [1 : abs(1) : 90]) {
if (beamheight >= sin(i) * beamwidth + (beamspacing - cos(i) * beamwidth) / tan(i) && beamheight * 0.9 <= sin((i + 1)) * beamwidth + (beamspacing - cos((i + 1)) * beamwidth) / tan((i + 1))) {
translate([((beamspacing + beamwidth) - cos(i) * beamwidth), 0, i]){
rotate([0, 0, i]){
beam(beamwidth, beamheight, beamthickness);
}
}
}
}
}
would there be some elegant way to ensure that only one instance is found/returned?
I guess if I was using OpenPythonSCAD I could have broken out of the loop, but then I wouldn't've been able to use BlockSCAD for coding:
https://www.blockscad3d.com/community/projects/1845977
William
Use recursion instead of iteration.
On Tue, Oct 29, 2024 at 8:56 PM William F. Adams via Discuss <
discuss@lists.openscad.org> wrote:
One of the really cool things about METAFONT/METAPOST is that one can
assign some variables and have the program solve an equation.
I tried to do something along those lines at:
https://forum.makerforums.info/t/using-openscad-in-lieu-of-a-geometric-solver/91726
and sort of hacked together some workable code:
//!OpenSCAD
beamwidth = 10;
beamheight = 100;
beamthickness = 1;
beamspacing = 40;
module beam(bw, bh, bt) {
cube([bw, bh, bt], center=false);
}
union(){
beam(beamwidth, beamheight, beamthickness);
translate([(beamspacing + beamwidth), 0, 0]){
beam(beamwidth, beamheight, beamthickness);
}
for (i = [1 : abs(1) : 90]) {
if (beamheight >= sin(i) * beamwidth + (beamspacing - cos(i) *
beamwidth) / tan(i) && beamheight * 0.9 <= sin((i + 1)) * beamwidth +
(beamspacing - cos((i + 1)) * beamwidth) / tan((i + 1))) {
translate([((beamspacing + beamwidth) - cos(i) * beamwidth), 0, i]){
rotate([0, 0, i]){
beam(beamwidth, beamheight, beamthickness);
}
}
}
}
}
would there be some elegant way to ensure that only one instance is
found/returned?
I guess if I was using OpenPythonSCAD I could have broken out of the loop,
but then I wouldn't've been able to use BlockSCAD for coding:
https://www.blockscad3d.com/community/projects/1845977
William
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
I didn't try to understand it, but a for() loop just builds a tree of geometry.
Just use an if(<whatever criteria>) before your beam() to include or exclude that branch.
-----Original Message-----
From: William F. Adams via Discuss [mailto:discuss@lists.openscad.org]
Sent: Wed, 30 Oct 2024 12:56
To: OpenSCAD General Discussion
Cc: William F. Adams
Subject: [OpenSCAD] General approach/technique/code for using OpenSCAD as a solver?
One of the really cool things about METAFONT/METAPOST is that one can assign some
variables and have the program solve an equation.
I tried to do something along those lines at:
https://forum.makerforums.info/t/using-openscad-in-lieu-of-a-geometric-solver/91726
and sort of hacked together some workable code:
//!OpenSCAD
beamwidth = 10;
beamheight = 100;
beamthickness = 1;
beamspacing = 40;
module beam(bw, bh, bt) {
cube([bw, bh, bt], center=false);
}
union(){
beam(beamwidth, beamheight, beamthickness);
translate([(beamspacing + beamwidth), 0, 0]){
beam(beamwidth, beamheight, beamthickness);
}
for (i = [1 : abs(1) : 90]) {
if (beamheight >= sin(i) * beamwidth + (beamspacing - cos(i) * beamwidth) / tan(i) &&
beamheight * 0.9 <= sin((i + 1)) * beamwidth + (beamspacing - cos((i + 1)) * beamwidth) /
tan((i + 1))) {
translate([((beamspacing + beamwidth) - cos(i) * beamwidth), 0, i]){
rotate([0, 0, i]){
beam(beamwidth, beamheight, beamthickness);
}
}
}
}
}
would there be some elegant way to ensure that only one instance is found/returned?
I guess if I was using OpenPythonSCAD I could have broken out of the loop, but then I
wouldn't've been able to use BlockSCAD for coding:
https://www.blockscad3d.com/community/projects/1845977
William
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
I agree that the right way to solve a problem like this in OpenSCAD is with
recursion. Any algorithm that involves iterating and changing the
variables as you iterate should be done either with recursion (which is
easier) or with the C-style for() construction, which is hard to use
compared to recursion, but may possibly be faster. I have written a
generic root finder for 1d function in openscad (root_find() in BOSL2) as
well as a function that finds all the roots of a polynomial. Both use
iterative algorithms that I implemented in OpenSCAD using recursion.
I also can say that like Michael Marx, I didn't try to figure out the code,
which seemed pretty mystifying. It looks like you're trying to solve the
problem by testing every point on a grid, which is a very inefficient sover
alogorithm and not how these things are generally done. But if you really
want to use that kind of algorithm you should do it with a for loop as
follows:
Write your for loop and have it calculate the error, so something like
error_list = [for ( L=..., theta=...) error(L,theta)] and then you find the
minimum error and figure out from the index value which parameter(s) gave
rise to that value. Then you'll have just one solution (because you can
take the first one that has the minimum value). To simplify the index
referencing you can include the parameters in the output of the loop. That
does add an extra step of forming an array of only error values to pass to
min(). And either way you'll want to use search() to track down which
index is actually equal to the min that you find.
On Tue, Oct 29, 2024 at 10:06 PM Father Horton via Discuss <
discuss@lists.openscad.org> wrote:
Use recursion instead of iteration.
On Tue, Oct 29, 2024 at 8:56 PM William F. Adams via Discuss <
discuss@lists.openscad.org> wrote:
One of the really cool things about METAFONT/METAPOST is that one can
assign some variables and have the program solve an equation.
I tried to do something along those lines at:
https://forum.makerforums.info/t/using-openscad-in-lieu-of-a-geometric-solver/91726
and sort of hacked together some workable code:
//!OpenSCAD
beamwidth = 10;
beamheight = 100;
beamthickness = 1;
beamspacing = 40;
module beam(bw, bh, bt) {
cube([bw, bh, bt], center=false);
}
union(){
beam(beamwidth, beamheight, beamthickness);
translate([(beamspacing + beamwidth), 0, 0]){
beam(beamwidth, beamheight, beamthickness);
}
for (i = [1 : abs(1) : 90]) {
if (beamheight >= sin(i) * beamwidth + (beamspacing - cos(i) *
beamwidth) / tan(i) && beamheight * 0.9 <= sin((i + 1)) * beamwidth +
(beamspacing - cos((i + 1)) * beamwidth) / tan((i + 1))) {
translate([((beamspacing + beamwidth) - cos(i) * beamwidth), 0, i]){
rotate([0, 0, i]){
beam(beamwidth, beamheight, beamthickness);
}
}
}
}
}
would there be some elegant way to ensure that only one instance is
found/returned?
I guess if I was using OpenPythonSCAD I could have broken out of the
loop, but then I wouldn't've been able to use BlockSCAD for coding:
https://www.blockscad3d.com/community/projects/1845977
William
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Thanks!
I'll have to dig through this later. Doing recursion where each copy calls itself until the value matches seems straight-forward enough, and I think that's something I can do in BlockSCAD:
https://www.blockscad3d.com/community/projects/1845977
I did have one correction to the code --- forgot to include the formula for the rotated beam length, so change the translate line to:
translate([((beamspacing + beamwidth) - cos(i) * beamwidth), 0, 0]){
William
On Tuesday, October 29, 2024 at 10:28:00 PM EDT, Adrian Mariano via Discuss discuss@lists.openscad.org wrote:
I agree that the right way to solve a problem like this in OpenSCAD is with recursion. Any algorithm that involves iterating and changing the variables as you iterate should be done either with recursion (which is easier) or with the C-style for() construction, which is hard to use compared to recursion, but may possibly be faster. I have written a generic root finder for 1d function in openscad (root_find() in BOSL2) as well as a function that finds all the roots of a polynomial. Both use iterative algorithms that I implemented in OpenSCAD using recursion.
I also can say that like Michael Marx, I didn't try to figure out the code, which seemed pretty mystifying. It looks like you're trying to solve the problem by testing every point on a grid, which is a very inefficient sover alogorithm and not how these things are generally done. But if you really want to use that kind of algorithm you should do it with a for loop as follows:
Write your for loop and have it calculate the error, so something like error_list = [for ( L=..., theta=...) error(L,theta)] and then you find the minimum error and figure out from the index value which parameter(s) gave rise to that value. Then you'll have just one solution (because you can take the first one that has the minimum value). To simplify the index referencing you can include the parameters in the output of the loop. That does add an extra step of forming an array of only error values to pass to min(). And either way you'll want to use search() to track down which index is actually equal to the min that you find.
On Tue, Oct 29, 2024 at 10:06 PM Father Horton via Discuss discuss@lists.openscad.org wrote:
Use recursion instead of iteration.
On Tue, Oct 29, 2024 at 8:56 PM William F. Adams via Discuss discuss@lists.openscad.org wrote:
One of the really cool things about METAFONT/METAPOST is that one can assign some variables and have the program solve an equation.
I tried to do something along those lines at:
https://forum.makerforums.info/t/using-openscad-in-lieu-of-a-geometric-solver/91726
and sort of hacked together some workable code:
//!OpenSCAD
beamwidth = 10;
beamheight = 100;
beamthickness = 1;
beamspacing = 40;
module beam(bw, bh, bt) {
cube([bw, bh, bt], center=false);
}
union(){
beam(beamwidth, beamheight, beamthickness);
translate([(beamspacing + beamwidth), 0, 0]){
beam(beamwidth, beamheight, beamthickness);
}
for (i = [1 : abs(1) : 90]) {
if (beamheight >= sin(i) * beamwidth + (beamspacing - cos(i) * beamwidth) / tan(i) && beamheight * 0.9 <= sin((i + 1)) * beamwidth + (beamspacing - cos((i + 1)) * beamwidth) / tan((i + 1))) {
translate([((beamspacing + beamwidth) - cos(i) * beamwidth), 0, i]){
rotate([0, 0, i]){
beam(beamwidth, beamheight, beamthickness);
}
}
}
}
}
would there be some elegant way to ensure that only one instance is found/returned?
I guess if I was using OpenPythonSCAD I could have broken out of the loop, but then I wouldn't've been able to use BlockSCAD for coding:
https://www.blockscad3d.com/community/projects/1845977
William
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
and I was able to puzzle out a recursive version pretty easily:
https://www.blockscad3d.com/community/projects/1845977
click on "Create my own" and then "Render"
The if check might need to be updated, but it seemed to work for all the values I tested with.
William
A question to the general list. Is "blockscad3d.com" a known/trusted URL?
On Wed, Oct 30, 2024 at 1:07 PM William F. Adams via Discuss <
discuss@lists.openscad.org> wrote:
and I was able to puzzle out a recursive version pretty easily:
https://www.blockscad3d.com/community/projects/1845977
click on "Create my own" and then "Render"
The if check might need to be updated, but it seemed to work for all the
values I tested with.
William
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Here's a direct solution to the problem using a function solver, which is
really the right way to do this kind of problem:
include<BOSL2/std.scad>
width = 8;
height = 12;
beamwidth=3;
// Length of beam so that it achieves the desired width at specified angle
function length(theta) = (width-beamwidth*sin(theta))/cos(theta);
// Height of beam at angle theta with the length chosen to match target
width
function height(theta) = length(theta) * sin(theta) + beamwidth*cos(theta);
ang = root_find(function (theta) height(theta) - height, 1, 89);
echo(ang);
rect([width,height]);
zrot(90-ang)color("red")rect([beamwidth, length(ang)]);
On Wed, Oct 30, 2024 at 1:58 PM John David via Discuss <
discuss@lists.openscad.org> wrote:
A question to the general list. Is "blockscad3d.com" a known/trusted URL?
On Wed, Oct 30, 2024 at 1:07 PM William F. Adams via Discuss <
discuss@lists.openscad.org> wrote:
and I was able to puzzle out a recursive version pretty easily:
https://www.blockscad3d.com/community/projects/1845977
click on "Create my own" and then "Render"
The if check might need to be updated, but it seemed to work for all the
values I tested with.
William
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
On 10/30/2024 10:57 AM, John David via Discuss wrote:
A question to the general list. Is "blockscad3d.com
http://blockscad3d.com" a known/trusted URL?
It offers a graphical OpenSCAD-like designer that might well use
OpenSCAD under the covers; I don't know.
Does it also host bad stuff? No idea. It sure doesn't look like a
site that would be trying to distribute malware.
Elegantly done!
I hope you don't mind that I posted it (with attribution) to:
As noted there, a big problem with approaching this angularly is that even a quite small angle can result in a quite large deviation.
William
On Wednesday, October 30, 2024 at 04:36:32 PM EDT, Adrian Mariano via Discuss discuss@lists.openscad.org wrote:
Here's a direct solution to the problem using a function solver, which is really the right way to do this kind of problem:
include<BOSL2/std.scad>
width = 8;
height = 12;
beamwidth=3;
// Length of beam so that it achieves the desired width at specified angle
function length(theta) = (width-beamwidth*sin(theta))/cos(theta);
// Height of beam at angle theta with the length chosen to match target width
function height(theta) = length(theta) * sin(theta) + beamwidth*cos(theta);
ang = root_find(function (theta) height(theta) - height, 1, 89);
echo(ang);
rect([width,height]);
zrot(90-ang)color("red")rect([beamwidth, length(ang)]);
On Wed, Oct 30, 2024 at 1:58 PM John David via Discuss discuss@lists.openscad.org wrote:
A question to the general list. Is "blockscad3d.com" a known/trusted URL?
On Wed, Oct 30, 2024 at 1:07 PM William F. Adams via Discuss discuss@lists.openscad.org wrote:
and I was able to puzzle out a recursive version pretty easily:
https://www.blockscad3d.com/community/projects/1845977
click on "Create my own" and then "Render"
The if check might need to be updated, but it seemed to work for all the values I tested with.
William
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org