I know this is an old issue. I think it was asked back in 2012 when I was
new then. The question then was if one could create "negative" pieces, ie.
one which subtracts in CSG. This would ease the contortions in code to get
everything aligned for difference().
The issue is if you want to merge two pipes, ie. hollow cylinders, you need
to do the difference bit AFTER you have merged (translate/rotated into
position) the pipes. Or it's just me that can't get a good idea.
Here is a "complex"(?) object. It consists of half cylinders with a
hollowed out part. I join these in a marble track construction. The
transform is non-trivial, the pieces "Track" are perhaps trivial, but the
argument applies even more if they, too, are complex
If I create the individual pieces as hollowed out cylinders and join them
for the track, the walls partially block the track in corners. I need to
repeat the (complex) placement transform on the hollowed out part.
To ease this, I have my piece module take the argument "PM" (for Plus or
Minus).
I am wondering if there is an easier program structure or idiom. I have
returned to this list after 6 years of absence, so a smart answer might
already be common knowledge.
Msquare
Marbletrack example:
K=25.4 ; // Marblesize
C=0.7 ; // clearance, marble
T=2 ; // wall thickness
Dy = K+C+2*T ;// Outer diameter of tracks
Di = K+C ; // Inner -"-
module Polar(P) {
// Rotate childern to P (polar vector)
x = P[0] ; y = P[1] ; z = P[2] ;
l = norm([x,y,z]) ;
v = acos(z/l); // inclination angle
w = atan2(y,x); // azimuthal angle
rotate([0,v,w]) children() ;
}
module Cylrund(D,H) {
// Cylinder with rounded end
// D=Diameter, H=height (total height=H+D/2)
difference() {
union() {
cylinder(d=D,h=H+1) ;
sphere(d=D) ;
}
translate([0,0,H]) cylinder(d=D*1.001,h=D/2) ; // trunctates sphere if
cylinder shorter
}
}
module Track(PM,H=100) {
// single track piece (stands up)
// PM is true for "plus" (Solid outer), false for "minus", (hollow bit) -
use for difference in callling module
difference() {
if ( PM ) Cylrund(Dy,H) ;
else Cylrund(Di,H) ;
translate([-K*(PM?1:2),-K/2-T-C/2,-K/2-T-C]) cube([Di,Dy,Dy+H]) ;
}
}
module BallTrack(SP,SD=K/3) {
// Track with several sections, and support cylinders
// SP defines track path as xyz triplets (2 dim. array)
// SD can be value, list (1:1 with SP list) or 2D list:
SDlist = is_list(SD[0]) ;// SD is 2 dim. array of x,y,height placements
SDdia = is_list(SD) ; // SD is single list of diameter at each "corner"
(0=no cylinder)
// SD omitted/single value: diameter at each "corner" (0= no support)
if ( SDlist ) echo ("SDlist") ;
if ( SDdia ) echo ("SDdia") ;
difference() {
union() {
for ( n = [0:len(SP)-1] ) {
if ( n > 0 ) { // Skip first corner as track is between n and n-1
corner
ES = [ SP[n][0]-SP[n-1][0], // single segment, "normalized"
SP[n][1]-SP[n-1][1],
SP[n][2]-SP[n-1][2] ] ;
translate(SP[n-1]) // move to start point
Polar(ES) // rotate to fit next point
Track(true,norm(ES)) ;
}
// Place support cylinder at "corners"
if ( ! SDlist ) {
if ( SDdia ) { // take diameter from SD list, skip if =0
if ( SD[n] > 0 ) translate([SP[n][0],SP[n][1],0])
cylinder(d=SD[n], SP[n][2]) ;
} else { // same diameter for all cylinders
if ( SD > 0 ) translate([SP[n][0],SP[n][1],0])
cylinder(d=SD, SP[n][2]) ;
}
}
}
// independent cylinder placement x,y,height
if ( SDlist ) for ( n = [0:len(SD)-1] ) {
translate([SD[n][0],SD[n][1],0]) cylinder(d=K/2,h=SD[n][2]) ;
}
}
// Repeat tracklist, but now subtract inside
for ( n = [1:len(SP)-1] ) {
ES = [ SP[n][0]-SP[n-1][0], // single segment, "normalized"
SP[n][1]-SP[n-1][1],
SP[n][2]-SP[n-1][2] ] ;
translate(SP[n-1]) // move to start point
Polar(ES) // rotate to fit next point
Track(false,norm(ES)) ;
}
}
}
BallTrack( [
[0, 0, 90], [110, 0, 74], [120, 15, 72],
[110,30,70],[20,30,57],[10,15,53],
[20,0,50],[95,0,42],[110,25,40],
[73,50,35],[73,70,30]
]
,[20,20,0,0,10,0,0,0,10,0,0] // Few support cylinders, some slimmer
// ,10 // Support cylinders each corner
// ,[ [32,12,80],[90,12,70],[73,60,35] ] // Independent support cylinders
// ,0 // None
) ;
NB: I've 3D printed this and it works fine. 3D-Support is a nightmare.
If I need to place two things in the same place, e.g. a screw and a screw
hole, or in your case the outside and the inside I just make the
placement a module that translates and rotates its children so I never
repeat code.
On Fri, 14 May 2021 at 13:46, Michael Möller private2michael@gmail.com
wrote:
I know this is an old issue. I think it was asked back in 2012 when I was
new then. The question then was if one could create "negative" pieces, ie.
one which subtracts in CSG. This would ease the contortions in code to get
everything aligned for difference().
The issue is if you want to merge two pipes, ie. hollow cylinders, you
need to do the difference bit AFTER you have merged (translate/rotated into
position) the pipes. Or it's just me that can't get a good idea.
Here is a "complex"(?) object. It consists of half cylinders with a
hollowed out part. I join these in a marble track construction. The
transform is non-trivial, the pieces "Track" are perhaps trivial, but the
argument applies even more if they, too, are complex
If I create the individual pieces as hollowed out cylinders and join them
for the track, the walls partially block the track in corners. I need to
repeat the (complex) placement transform on the hollowed out part.
To ease this, I have my piece module take the argument "PM" (for Plus or
Minus).
I am wondering if there is an easier program structure or idiom. I have
returned to this list after 6 years of absence, so a smart answer might
already be common knowledge.
Msquare
Marbletrack example:
K=25.4 ; // Marblesize
C=0.7 ; // clearance, marble
T=2 ; // wall thickness
Dy = K+C+2*T ;// Outer diameter of tracks
Di = K+C ; // Inner -"-
module Polar(P) {
// Rotate childern to P (polar vector)
x = P[0] ; y = P[1] ; z = P[2] ;
l = norm([x,y,z]) ;
v = acos(z/l); // inclination angle
w = atan2(y,x); // azimuthal angle
rotate([0,v,w]) children() ;
}
module Cylrund(D,H) {
// Cylinder with rounded end
// D=Diameter, H=height (total height=H+D/2)
difference() {
union() {
cylinder(d=D,h=H+1) ;
sphere(d=D) ;
}
translate([0,0,H]) cylinder(d=D*1.001,h=D/2) ; // trunctates sphere if
cylinder shorter
}
}
module Track(PM,H=100) {
// single track piece (stands up)
// PM is true for "plus" (Solid outer), false for "minus", (hollow bit) -
use for difference in callling module
difference() {
if ( PM ) Cylrund(Dy,H) ;
else Cylrund(Di,H) ;
translate([-K*(PM?1:2),-K/2-T-C/2,-K/2-T-C]) cube([Di,Dy,Dy+H]) ;
}
}
module BallTrack(SP,SD=K/3) {
// Track with several sections, and support cylinders
// SP defines track path as xyz triplets (2 dim. array)
// SD can be value, list (1:1 with SP list) or 2D list:
SDlist = is_list(SD[0]) ;// SD is 2 dim. array of x,y,height placements
SDdia = is_list(SD) ; // SD is single list of diameter at each "corner"
(0=no cylinder)
// SD omitted/single value: diameter at each "corner" (0= no support)
if ( SDlist ) echo ("SDlist") ;
if ( SDdia ) echo ("SDdia") ;
difference() {
union() {
for ( n = [0:len(SP)-1] ) {
if ( n > 0 ) { // Skip first corner as track is between n and n-1
corner
ES = [ SP[n][0]-SP[n-1][0], // single segment, "normalized"
SP[n][1]-SP[n-1][1],
SP[n][2]-SP[n-1][2] ] ;
translate(SP[n-1]) // move to start point
Polar(ES) // rotate to fit next point
Track(true,norm(ES)) ;
}
// Place support cylinder at "corners"
if ( ! SDlist ) {
if ( SDdia ) { // take diameter from SD list, skip if =0
if ( SD[n] > 0 ) translate([SP[n][0],SP[n][1],0])
cylinder(d=SD[n], SP[n][2]) ;
} else { // same diameter for all cylinders
if ( SD > 0 ) translate([SP[n][0],SP[n][1],0])
cylinder(d=SD, SP[n][2]) ;
}
}
}
// independent cylinder placement x,y,height
if ( SDlist ) for ( n = [0:len(SD)-1] ) {
translate([SD[n][0],SD[n][1],0]) cylinder(d=K/2,h=SD[n][2]) ;
}
}
// Repeat tracklist, but now subtract inside
for ( n = [1:len(SP)-1] ) {
ES = [ SP[n][0]-SP[n-1][0], // single segment, "normalized"
SP[n][1]-SP[n-1][1],
SP[n][2]-SP[n-1][2] ] ;
translate(SP[n-1]) // move to start point
Polar(ES) // rotate to fit next point
Track(false,norm(ES)) ;
}
}
}
BallTrack( [
[0, 0, 90], [110, 0, 74], [120, 15, 72],
[110,30,70],[20,30,57],[10,15,53],
[20,0,50],[95,0,42],[110,25,40],
[73,50,35],[73,70,30]
]
,[20,20,0,0,10,0,0,0,10,0,0] // Few support cylinders, some slimmer
// ,10 // Support cylinders each corner
// ,[ [32,12,80],[90,12,70],[73,60,35] ] // Independent support
cylinders
// ,0 // None
) ;
NB: I've 3D printed this and it works fine. 3D-Support is a nightmare.
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Using a module for positioning is something I really need to use more. I
think I have modules stuck in my head as objects, I really need to make
more use of children()
On Fri, 14 May 2021, 08:53 nop head, nop.head@gmail.com wrote:
If I need to place two things in the same place, e.g. a screw and a screw
hole, or in your case the outside and the inside I just make the
placement a module that translates and rotates its children so I never
repeat code.
On Fri, 14 May 2021 at 13:46, Michael Möller private2michael@gmail.com
wrote:
I know this is an old issue. I think it was asked back in 2012 when I was
new then. The question then was if one could create "negative" pieces, ie.
one which subtracts in CSG. This would ease the contortions in code to get
everything aligned for difference().
The issue is if you want to merge two pipes, ie. hollow cylinders, you
need to do the difference bit AFTER you have merged (translate/rotated into
position) the pipes. Or it's just me that can't get a good idea.
Here is a "complex"(?) object. It consists of half cylinders with a
hollowed out part. I join these in a marble track construction. The
transform is non-trivial, the pieces "Track" are perhaps trivial, but the
argument applies even more if they, too, are complex
If I create the individual pieces as hollowed out cylinders and join them
for the track, the walls partially block the track in corners. I need to
repeat the (complex) placement transform on the hollowed out part.
To ease this, I have my piece module take the argument "PM" (for Plus or
Minus).
I am wondering if there is an easier program structure or idiom. I have
returned to this list after 6 years of absence, so a smart answer might
already be common knowledge.
Msquare
Marbletrack example:
K=25.4 ; // Marblesize
C=0.7 ; // clearance, marble
T=2 ; // wall thickness
Dy = K+C+2*T ;// Outer diameter of tracks
Di = K+C ; // Inner -"-
module Polar(P) {
// Rotate childern to P (polar vector)
x = P[0] ; y = P[1] ; z = P[2] ;
l = norm([x,y,z]) ;
v = acos(z/l); // inclination angle
w = atan2(y,x); // azimuthal angle
rotate([0,v,w]) children() ;
}
module Cylrund(D,H) {
// Cylinder with rounded end
// D=Diameter, H=height (total height=H+D/2)
difference() {
union() {
cylinder(d=D,h=H+1) ;
sphere(d=D) ;
}
translate([0,0,H]) cylinder(d=D*1.001,h=D/2) ; // trunctates sphere
if cylinder shorter
}
}
module Track(PM,H=100) {
// single track piece (stands up)
// PM is true for "plus" (Solid outer), false for "minus", (hollow bit) -
use for difference in callling module
difference() {
if ( PM ) Cylrund(Dy,H) ;
else Cylrund(Di,H) ;
translate([-K*(PM?1:2),-K/2-T-C/2,-K/2-T-C]) cube([Di,Dy,Dy+H]) ;
}
}
module BallTrack(SP,SD=K/3) {
// Track with several sections, and support cylinders
// SP defines track path as xyz triplets (2 dim. array)
// SD can be value, list (1:1 with SP list) or 2D list:
SDlist = is_list(SD[0]) ;// SD is 2 dim. array of x,y,height placements
SDdia = is_list(SD) ; // SD is single list of diameter at each "corner"
(0=no cylinder)
// SD omitted/single value: diameter at each "corner" (0= no support)
if ( SDlist ) echo ("SDlist") ;
if ( SDdia ) echo ("SDdia") ;
difference() {
union() {
for ( n = [0:len(SP)-1] ) {
if ( n > 0 ) { // Skip first corner as track is between n and n-1
corner
ES = [ SP[n][0]-SP[n-1][0], // single segment, "normalized"
SP[n][1]-SP[n-1][1],
SP[n][2]-SP[n-1][2] ] ;
translate(SP[n-1]) // move to start point
Polar(ES) // rotate to fit next point
Track(true,norm(ES)) ;
}
// Place support cylinder at "corners"
if ( ! SDlist ) {
if ( SDdia ) { // take diameter from SD list, skip if =0
if ( SD[n] > 0 ) translate([SP[n][0],SP[n][1],0])
cylinder(d=SD[n], SP[n][2]) ;
} else { // same diameter for all cylinders
if ( SD > 0 ) translate([SP[n][0],SP[n][1],0])
cylinder(d=SD, SP[n][2]) ;
}
}
}
// independent cylinder placement x,y,height
if ( SDlist ) for ( n = [0:len(SD)-1] ) {
translate([SD[n][0],SD[n][1],0]) cylinder(d=K/2,h=SD[n][2]) ;
}
}
// Repeat tracklist, but now subtract inside
for ( n = [1:len(SP)-1] ) {
ES = [ SP[n][0]-SP[n-1][0], // single segment, "normalized"
SP[n][1]-SP[n-1][1],
SP[n][2]-SP[n-1][2] ] ;
translate(SP[n-1]) // move to start point
Polar(ES) // rotate to fit next point
Track(false,norm(ES)) ;
}
}
}
BallTrack( [
[0, 0, 90], [110, 0, 74], [120, 15, 72],
[110,30,70],[20,30,57],[10,15,53],
[20,0,50],[95,0,42],[110,25,40],
[73,50,35],[73,70,30]
]
,[20,20,0,0,10,0,0,0,10,0,0] // Few support cylinders, some slimmer
// ,10 // Support cylinders each corner
// ,[ [32,12,80],[90,12,70],[73,60,35] ] // Independent support
cylinders
// ,0 // None
) ;
NB: I've 3D printed this and it works fine. 3D-Support is a nightmare.
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, good advice.
So I still need to keep track of my inside and outside part/version in the
right place of my compound object difference function.
Michael, from mobile
fre. 14. maj 2021 14.53 skrev nop head nop.head@gmail.com:
If I need to place two things in the same place, e.g. a screw and a screw
hole, or in your case the outside and the inside I just make the
placement a module that translates and rotates its children so I never
repeat code.
On Fri, 14 May 2021 at 13:46, Michael Möller private2michael@gmail.com
wrote:
I know this is an old issue. I think it was asked back in 2012 when I was
new then. The question then was if one could create "negative" pieces, ie.
one which subtracts in CSG. This would ease the contortions in code to get
everything aligned for difference().
The issue is if you want to merge two pipes, ie. hollow cylinders, you
need to do the difference bit AFTER you have merged (translate/rotated into
position) the pipes. Or it's just me that can't get a good idea.
Here is a "complex"(?) object. It consists of half cylinders with a
hollowed out part. I join these in a marble track construction. The
transform is non-trivial, the pieces "Track" are perhaps trivial, but the
argument applies even more if they, too, are complex
If I create the individual pieces as hollowed out cylinders and join them
for the track, the walls partially block the track in corners. I need to
repeat the (complex) placement transform on the hollowed out part.
To ease this, I have my piece module take the argument "PM" (for Plus or
Minus).
I am wondering if there is an easier program structure or idiom. I have
returned to this list after 6 years of absence, so a smart answer might
already be common knowledge.
Msquare
Marbletrack example:
K=25.4 ; // Marblesize
C=0.7 ; // clearance, marble
T=2 ; // wall thickness
Dy = K+C+2*T ;// Outer diameter of tracks
Di = K+C ; // Inner -"-
module Polar(P) {
// Rotate childern to P (polar vector)
x = P[0] ; y = P[1] ; z = P[2] ;
l = norm([x,y,z]) ;
v = acos(z/l); // inclination angle
w = atan2(y,x); // azimuthal angle
rotate([0,v,w]) children() ;
}
module Cylrund(D,H) {
// Cylinder with rounded end
// D=Diameter, H=height (total height=H+D/2)
difference() {
union() {
cylinder(d=D,h=H+1) ;
sphere(d=D) ;
}
translate([0,0,H]) cylinder(d=D*1.001,h=D/2) ; // trunctates sphere
if cylinder shorter
}
}
module Track(PM,H=100) {
// single track piece (stands up)
// PM is true for "plus" (Solid outer), false for "minus", (hollow bit) -
use for difference in callling module
difference() {
if ( PM ) Cylrund(Dy,H) ;
else Cylrund(Di,H) ;
translate([-K*(PM?1:2),-K/2-T-C/2,-K/2-T-C]) cube([Di,Dy,Dy+H]) ;
}
}
module BallTrack(SP,SD=K/3) {
// Track with several sections, and support cylinders
// SP defines track path as xyz triplets (2 dim. array)
// SD can be value, list (1:1 with SP list) or 2D list:
SDlist = is_list(SD[0]) ;// SD is 2 dim. array of x,y,height placements
SDdia = is_list(SD) ; // SD is single list of diameter at each "corner"
(0=no cylinder)
// SD omitted/single value: diameter at each "corner" (0= no support)
if ( SDlist ) echo ("SDlist") ;
if ( SDdia ) echo ("SDdia") ;
difference() {
union() {
for ( n = [0:len(SP)-1] ) {
if ( n > 0 ) { // Skip first corner as track is between n and n-1
corner
ES = [ SP[n][0]-SP[n-1][0], // single segment, "normalized"
SP[n][1]-SP[n-1][1],
SP[n][2]-SP[n-1][2] ] ;
translate(SP[n-1]) // move to start point
Polar(ES) // rotate to fit next point
Track(true,norm(ES)) ;
}
// Place support cylinder at "corners"
if ( ! SDlist ) {
if ( SDdia ) { // take diameter from SD list, skip if =0
if ( SD[n] > 0 ) translate([SP[n][0],SP[n][1],0])
cylinder(d=SD[n], SP[n][2]) ;
} else { // same diameter for all cylinders
if ( SD > 0 ) translate([SP[n][0],SP[n][1],0])
cylinder(d=SD, SP[n][2]) ;
}
}
}
// independent cylinder placement x,y,height
if ( SDlist ) for ( n = [0:len(SD)-1] ) {
translate([SD[n][0],SD[n][1],0]) cylinder(d=K/2,h=SD[n][2]) ;
}
}
// Repeat tracklist, but now subtract inside
for ( n = [1:len(SP)-1] ) {
ES = [ SP[n][0]-SP[n-1][0], // single segment, "normalized"
SP[n][1]-SP[n-1][1],
SP[n][2]-SP[n-1][2] ] ;
translate(SP[n-1]) // move to start point
Polar(ES) // rotate to fit next point
Track(false,norm(ES)) ;
}
}
}
BallTrack( [
[0, 0, 90], [110, 0, 74], [120, 15, 72],
[110,30,70],[20,30,57],[10,15,53],
[20,0,50],[95,0,42],[110,25,40],
[73,50,35],[73,70,30]
]
,[20,20,0,0,10,0,0,0,10,0,0] // Few support cylinders, some slimmer
// ,10 // Support cylinders each corner
// ,[ [32,12,80],[90,12,70],[73,60,35] ] // Independent support
cylinders
// ,0 // None
) ;
NB: I've 3D printed this and it works fine. 3D-Support is a nightmare.
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
If I need to place two things in the same place, e.g. a screw and a screw
hole, or in your case the outside and the inside I just make the placement a
module that translates and rotates its children so I never repeat code.
I do something similar with a module called adjust() that performs rotations
and translations. adjust() is part of a file of utilities that I "use <>" in
every part.
Example:
screwAdjustments = [[0,0,90],[5,10,-5]]; // [rotations,translations]
adjust(screwAdjustments)
screws();
adjust(screwAdjustments)
screwHoless();
--
Sent from: http://forum.openscad.org/