Assembling complex components with hollow parts

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Assembling complex components with hollow parts

Msquare
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 [hidden email]
+--+
| M |
+--+
Reply | Threaded
Open this post in threaded view
|

Re: Assembling complex components with hollow parts

nophead
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 <[hidden email]> 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 [hidden email]

_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to [hidden email]
Reply | Threaded
Open this post in threaded view
|

Re: Assembling complex components with hollow parts

acwest
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, <[hidden email]> 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 <[hidden email]> 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 [hidden email]
_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to [hidden email]

_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to [hidden email]
Reply | Threaded
Open this post in threaded view
|

Re: Assembling complex components with hollow parts

Msquare
In reply to this post by nophead
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 <[hidden email]>:
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 <[hidden email]> 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 [hidden email]
_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to [hidden email]

_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to [hidden email]
+--+
| M |
+--+
Reply | Threaded
Open this post in threaded view
|

Re: Assembling complex components with hollow parts

LenStruttmann
This post was updated on .
In reply to this post by nophead
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/
_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org