# finalVer.slf
# Code for sculpture of 12 cylinders that are just touching each other
# WM 6/1/2001
#######################################################################

tclinit {
    set winName .slfWindow

    source SLIDEUI.tcl
    source MATH.tcl

    set to_rad [expr $SLF_PI/180.0 ]

    CreateGroupUI $winName gRoot
} 

tclinit {

  ### Calculate the angle alpha that makes the cylinder just touch the z-axis

  proc update { value } { 
    global  to_rad   base_cl base_cr base_sr base_alf base_scal base_hh base_ss base_delta base_s2 base_angleW base_s3 base_angleV 

    #### CALCULATING THE ANGLE ALPHA WHERE 2 CYLINDERS JUST TOUCH EACH OTHER
    set dd [expr $base_sr + $base_cr ]
    set uu [expr sqrt( $dd*$dd - $base_cr*$base_cr )* $base_cr / $dd ]
    set d2 [expr ( $dd*$dd - $base_cr*$base_cr )/ $dd ]
    set qq [expr $d2 / tan(30*$to_rad) ]
    set rat [expr $uu / $qq ]

    puts ""
    puts "INFORMATION ABOUT THE 2 CYLINDERS THAT ARE JUST TOUCHING"
    puts "========================================================"

    set base_alf [expr asin($uu/$qq)/$to_rad ]
    puts "Angle alpha rotation of the cylinders = $base_alf (ALPHA)"

    #### HEIGHT IN THE Z-AXIS WHERE THE 2 CYLINDERS JUST TOUCH
    set base_hh [expr (($dd*$dd)-($base_cr*$base_cr))/($dd*cos(60*$to_rad))]
    puts "Height in z-axis of the touching point = $base_hh"

    #### THE SIDE LENGTH OF THE CUBE
    set base_scal [expr $base_hh/0.707]

    #### LENGTH OF A CYLINDER WHERE THE 2 CYLINDERS JUST TOUCH
    #### THIS LENGTH IS MEASURED FROM CENTER OF CYLINDER
    set base_ss [expr sqrt( ($base_hh*$base_hh)-($dd*$dd)+($base_cr*$base_cr))]
    puts "Distance from the cylinder's center to the touching point= $base_ss (S1)"

    #### ANGLE ROTATION OF THE CYLINDER RADIUS TO THE POSITION WHERE THE 2 CYLINDERS
    #### JUST TOUCH
    set base_delta [expr -(180+(asin(-$base_ss*tan($base_alf*$to_rad)/$base_cr)/$to_rad))]
    puts "Angle delta rotation of cylinder's radius = $base_delta (DELTA)"

    #### CALCULATING THE POINTS THAT HAVE THE SHORTEST DISTANCE THAT CONNECTED 
    #### BETWEEN 2 CYLINDERS
    set p1x [expr $base_cl*cos((35.24-$base_alf)*$to_rad)]
    set p1y [expr (-($base_sr + $base_cr)*cos(45*$to_rad))+($base_cl*sin(45*$to_rad)*sin((35.24-$base_alf)*$to_rad)) ]
    set p1z [expr (-($base_sr + $base_cr)*sin(45*$to_rad))-($base_cl*cos(45*$to_rad)*sin((35.24-$base_alf)*$to_rad)) ]

    set p2x [expr -$base_cl*cos((35.24-$base_alf)*$to_rad)]
    set p2y [expr (-($base_sr + $base_cr)*cos(45*$to_rad))-($base_cl*sin(45*$to_rad)*sin((35.24-$base_alf)*$to_rad)) ]
    set p2z [expr (-($base_sr + $base_cr)*sin(45*$to_rad))+($base_cl*cos(45*$to_rad)*sin((35.24-$base_alf)*$to_rad)) ]

    set rx3 [expr ($dd*cos(-30*$to_rad))+($base_cl*sin(-30*$to_rad)*cos($base_alf*$to_rad))]
    set ry3 [expr (-$dd*sin(-30*$to_rad))+($base_cl*cos(-30*$to_rad)*cos($base_alf*$to_rad))]
    set rz3 [expr $base_cl*sin($base_alf*$to_rad)]

    set p3x [expr ($rx3*cos(35.24*$to_rad))+($rz3*sin(35.24*$to_rad))]
    set p3y [expr ($ry3*cos(-45*$to_rad))-(sin(-45*$to_rad)*((-$rx3*sin(35.24*$to_rad))+($rz3*cos(35.24*$to_rad))))]
    set p3z [expr ($ry3*sin(-45*$to_rad))+(cos(-45*$to_rad)*((-$rx3*sin(35.24*$to_rad))+($rz3*cos(35.24*$to_rad))))]

    set rx4 [expr ($dd*cos(-30*$to_rad))-($base_cl*sin(-30*$to_rad)*cos($base_alf*$to_rad))]
    set ry4 [expr (-$dd*sin(-30*$to_rad))-($base_cl*cos(-30*$to_rad)*cos($base_alf*$to_rad))]
    set rz4 [expr -$base_cl*sin($base_alf*$to_rad)]

    set p4x [expr ($rx4*cos(35.24*$to_rad))+($rz4*sin(35.24*$to_rad))]
    set p4y [expr ($ry4*cos(-45*$to_rad))-(sin(-45*$to_rad)*((-$rx4*sin(35.24*$to_rad))+($rz4*cos(35.24*$to_rad))))]
    set p4z [expr ($ry4*sin(-45*$to_rad))+(cos(-45*$to_rad)*((-$rx4*sin(35.24*$to_rad))+($rz4*cos(35.24*$to_rad))))]

    set d1343 [expr (($p1x-$p3x)*($p4x-$p3x))+(($p1y-$p3y)*($p4y-$p3y))+(($p1z-$p3z)*($p4z-$p3z))]
    set d4321 [expr (($p4x-$p3x)*($p2x-$p1x))+(($p4y-$p3y)*($p2y-$p1y))+(($p4z-$p3z)*($p2z-$p1z))]
    set d1321 [expr (($p1x-$p3x)*($p2x-$p1x))+(($p1y-$p3y)*($p2y-$p1y))+(($p1z-$p3z)*($p2z-$p1z))]
    set d4343 [expr (($p4x-$p3x)*($p4x-$p3x))+(($p4y-$p3y)*($p4y-$p3y))+(($p4z-$p3z)*($p4z-$p3z))]
    set d2121 [expr (($p2x-$p1x)*($p2x-$p1x))+(($p2y-$p1y)*($p2y-$p1y))+(($p2z-$p1z)*($p2z-$p1z))]

    set mua [expr (($d1343*$d4321)-($d1321*$d4343))/(($d2121*$d4343)-($d4321*$d4321))]
    set mub [expr ($d1343 + ($mua * $d4321))/$d4343]

    puts "INFORMATION ABOUT THE SHORTEST DISTANCE BETWEEN 2 CYLINDERS"
    puts "==========================================================="

    set pax [expr $p1x + ($mua*($p2x-$p1x))]
    set pay [expr $p1y + ($mua*($p2y-$p1y))]
    set paz [expr $p1z + ($mua*($p2z-$p1z))]
    #puts "The first point = ($pax, $pay, $paz)"

    set pbx [expr $p3x + ($mub*($p4x-$p3x))]
    set pby [expr $p3y + ($mub*($p4y-$p3y))]
    set pbz [expr $p3z + ($mub*($p4z-$p3z))]
    #puts "The second point = ($pbx, $pby, $pbz)"

    set dt [expr sqrt(($pax-$pbx)*($pax-$pbx)+($pay-$pby)*($pay-$pby)+($paz-$pbz)*($paz-$pbz))]
    puts "The shortest distance between 2 cylinders = $dt"

    puts "The old cylinder radius = $base_cr"    
    set base_cr [expr $dt/2]
    puts "The new cylinder radius = $base_cr"

    #### THE MIDDLE POINT OF THE SHORTEST LINE
    set mx [expr $pax - (0.5 * ($pax-$pbx))]
    set my [expr $pay - (0.5 * ($pay-$pby))]
    set mz [expr $paz - (0.5 * ($paz-$pbz))]
    #puts "The middle point = ($mx, $my, $mz)"

    ##### THE FIRST TOUCHING POINT
    puts "First Touching Point -->"
    ##### FINDING DISTANCE OF THE SHORTEST LINE THAT CONNECTED ANY 2 CYLINDERS 
    ##### THIS DISTANCE IS FROM THE CENTER OF CYLINDER
    set dist2_x [expr ($mua*($p2x-$p1x))]
    set dist2_y [expr ($mua*($p2y-$p1y))]
    set dist2_z [expr ($mua*($p2z-$p1z))]
    
    set base_s3 [expr -(sqrt(($dist2_x*$dist2_x)+($dist2_y*$dist2_y)+($dist2_z*$dist2_z))-$base_cl)]
    puts "Distance from cylinder's center = $base_s3 (S3)"

    ##### FINDING ANGLE W OF THE SHORTEST LINE THAT CONNECTED ANY 2 CYLINDERS
    ##### THIS ANGLE IS CALCULATED WITH RESPECT TO X-AXIS OF THE CYLINDER
    set p1x [expr ($base_s3*cos(-$base_alf*$to_rad)*cos(35.24*$to_rad))-($base_s3*sin(-$base_alf*$to_rad)*sin(35.24*$to_rad))]
    set p1y [expr (-($base_cr+$dd)*cos(45*$to_rad))+($base_s3*cos(-$base_alf*$to_rad)*sin(35.24*$to_rad)*sin(45*$to_rad))+($base_s3*sin(-$base_alf*$to_rad)*cos(35.24*$to_rad)*sin(45*$to_rad))]
    set p1z [expr (-($base_cr+$dd)*sin(45*$to_rad))-($base_s3*cos(-$base_alf*$to_rad)*sin(35.24*$to_rad)*cos(45*$to_rad))-($base_s3*sin(-$base_alf*$to_rad)*cos(35.24*$to_rad)*cos(45*$to_rad))]

    set A [expr sqrt(($mx-$pax)*($mx-$pax)+($my-$pay)*($my-$pay)+($mz-$paz)*($mz-$paz))]
    set B [expr sqrt(($mx-$p1x)*($mx-$p1x)+($my-$p1y)*($my-$p1y)+($mz-$p1z)*($mz-$p1z))]
    set C [expr sqrt(($p1x-$pax)*($p1x-$pax)+($p1y-$pay)*($p1y-$pay)+($p1z-$paz)*($p1z-$paz))]

    set base_angleV [expr (acos((($A*$A)+($C*$C)-($B*$B))/(2*$A*$C))/$to_rad)]
    puts "Angle v rotation of the cylinder's radius = $base_angleV (V)"

    ##### THE SECOND TOUCHING POINT
    puts "Second Touching Point -->"
    ##### FINDING DISTANCE OF THE SHORTEST LINE THAT CONNECTED ANY 2 CYLINDERS 
    ##### THIS DISTANCE IS FROM THE CENTER OF CYLINDER
    set dist_x [expr ($mub*($p4x-$p3x))]
    set dist_y [expr ($mub*($p4y-$p3y))]
    set dist_z [expr ($mub*($p4z-$p3z))]

    set base_s2 [expr -(sqrt(($dist_x*$dist_x)+($dist_y*$dist_y)+($dist_z*$dist_z))-$base_cl)]
    puts "Distance from cylinder's center = $base_s2 (S2)"

    ##### FINDING ANGLE W OF THE SHORTEST LINE THAT CONNECTED ANY 2 CYLINDERS
    ##### THIS ANGLE IS CALCULATED WITH RESPECT TO X-AXIS OF THE CYLINDER
    set rx [expr (cos(-30*$to_rad)*($base_cr+$dd))+($base_s2*cos($base_alf*$to_rad)*sin(-30*$to_rad))]
    set ry [expr (-sin(-30*$to_rad)*($base_cr+$dd))+($base_s2*cos($base_alf*$to_rad)*cos(-30*$to_rad))]
    set rz [expr $base_s2*sin($base_alf*$to_rad)]

    set p0x [expr ($rx*cos(35.24*$to_rad))+($rz*(sin(35.24*$to_rad)))]
    set p0y [expr ($ry*cos(-45*$to_rad))-(sin(-45*$to_rad)*((-$rx*sin(35.24*$to_rad))+($rz*cos(35.24*$to_rad))))]
    set p0z [expr ($ry*sin(-45*$to_rad))+(cos(-45*$to_rad)*((-$rx*sin(35.24*$to_rad))+($rz*cos(35.24*$to_rad))))]

    set A [expr sqrt(($mx-$pbx)*($mx-$pbx)+($my-$pby)*($my-$pby)+($mz-$pbz)*($mz-$pbz))]
    set B [expr sqrt(($mx-$p0x)*($mx-$p0x)+($my-$p0y)*($my-$p0y)+($mz-$p0z)*($mz-$p0z))]
    set C [expr sqrt(($p0x-$pbx)*($p0x-$pbx)+($p0y-$pby)*($p0y-$pby)+($p0z-$pbz)*($p0z-$pbz))]

    set base_angleW [expr -acos((($A*$A)+($C*$C)-($B*$B))/(2*$A*$C))/$to_rad]
    puts "Angle w rotation of the cylinder's radius = $base_angleW (W)"
  }

  proc CreateBaseUI { parent name } {
    set subname "slf_[subst $name]"

    if { $parent == {} } {
	set root .$subname
    } elseif { $parent == "." } {
	set root .$subname
    } else {
  	set root $parent.$subname
    }

    toplevel $root

    set sr [CreateScaleCmd $name $root sr "sphere radius"        1  0.1 2.0  0.01 1 horizontal update]
    set cl [CreateScaleCmd $name $root cl "cylinder length"   1.25  0.2 5.0  0.01 1 horizontal update]
    set cr [CreateScaleCmd $name $root cr "cylinder radius"  0.265  0.1 2.0 0.001 1 horizontal update] 
    
    set alf [CreateScale $name $root alf "rot angle alpha"       0  -90  90     1 1 horizontal]
    set slices [CreateScale $name $root slices "slices"         10   10 100     1 1 horizontal]
    set scal [CreateScaleCmd $name $root scal "scale factor"   0.1    0  10 0.001 1 horizontal update]
       
    set hh [CreateScaleCmd $name $root hh "height"             0.1    0   5   0.1 1 horizontal update]
    set ss [CreateScaleCmd $name $root ss "length1"            0.1   -5   5  0.01 1 horizontal update]
    set delta [CreateScaleCmd $name $root delta "angle1"       0   -180 180     1 1 horizontal update]
    set s2 [CreateScaleCmd $name $root s2 "length2"            0.1  -10  10  0.01 1 horizontal update]
    set angleW [CreateScaleCmd $name $root angleW "angle2"     0   -180 180     1 1 horizontal update]
    set s3 [CreateScaleCmd $name $root s3 "length3"            0.1  -10  10  0.01 1 horizontal update]
    set angleV [CreateScaleCmd $name $root angleV "angle3"     0   -180 180     1 1 horizontal update]

    pack $sr $cl $cr $alf $slices $scal $hh $ss $delta $s2 $angleW $s3 $angleV -side top -fill x
  }
  CreateBaseUI $winName base
}

surface BLU
  color (0.7 0.9 1.0)
endsurface

surface RED
  color (1 0 0)
endsurface

surface GREEN
  color (0 1 0)
endsurface

surface PURPLE
  color (1 0 1)
endsurface

cylinder cyl
  radius   {expr $base_cr}
  zmin     {expr -2*$base_cl}
  zmax     {expr 2*$base_cl}
  begincap 1
  endcap 1
  thetaslices {expr $base_slices }
endcylinder

cylinder cyl2
  radius   {expr $base_cr}
  zmin     0
  zmax     {expr $base_cl}
  begincap 1
  endcap 1
  thetaslices {expr $base_slices }
endcylinder

sphere sph
    radius {expr $base_sr}
    zslices {expr $base_slices }
    thetaslices {expr $base_slices }
endsphere

cylinder cyl3
  radius   {expr $base_cr}
  zmin     0
  zmax     {expr $base_cr}
  begincap 1
  endcap   1
  thetaslices {expr $base_slices}
endcylinder

cylinder cyl4
  radius   {expr $base_cr}
  zmin     0
  zmax     {expr $base_ss}
  begincap 1
  endcap   1
  thetaslices {expr $base_slices}
endcylinder

###1 cylinders with all its touching point (there are 6 points in total)
group oneCylinder
    ###the cylinder
    instance cyl
      translate ( {expr $base_sr + $base_cr} 0 0)
      rotate ( 1 0 0 ) ({expr $base_alf})
      rotate ( 0 1 0 ) ({expr -30})
    endinstance  

    ###distance from center of cylinders to the touching point (first end)
    instance cyl4
      scale (0.02 0.02 1)
      translate ( {expr $base_sr + $base_cr} 0 0)
      rotate ( 1 0 0 ) ({expr $base_alf})
      rotate ( 0 1 0 ) (-30)
    endinstance

    ###the point where the 2 cylinders touch (first touching point)
    instance cyl3
      scale (0.02 0.02 1)
      rotate (1 0 0) ({expr $base_delta})  
      rotate (0 1 0) (90)
      translate ( { expr $base_sr + $base_cr} 0 {expr $base_ss})
      rotate (1 0 0) ({expr $base_alf})
      rotate (0 1 0) (-30)
    endinstance

    ###distance from center of cylinders to the touching point (second end)
    instance cyl4
      scale (0.02 0.02 1)
      rotate ( 1 0 0) (180)
      translate ( {expr $base_sr + $base_cr} 0 0)
      rotate ( 1 0 0 ) ({expr $base_alf})
      rotate ( 0 1 0 ) (-30)
    endinstance

    ###the point where the 2 cylinders touch (second touching point)
    instance cyl3
      scale (0.02 0.02 1)
      rotate (1 0 0) ({expr -$base_delta})  
      rotate (0 1 0) (90)
      translate ( { expr $base_sr + $base_cr} 0 {expr -$base_ss})
      rotate (1 0 0) ({expr $base_alf})
      rotate (0 1 0) (-30)
    endinstance

    ###the point where the shortest distance between 2 cylinders are 2*cylinder's radius
    ###(third touching point)
    instance cyl3
      scale (0.01 0.01 1)
      #rotate (0 1 0) (180)
      rotate (1 0 0) ({expr -$base_angleW})  
      rotate (0 1 0) (90)
      translate ( { expr $base_sr + $base_cr} 0 {expr -$base_s2})
      rotate (1 0 0) ({expr $base_alf})
      rotate (0 1 0) (-30)
    endinstance

    ###the point where the shortest distance between 2 cylinders are 2*cylinder's radius
    ###(forth touching point)
    instance cyl3
      scale (0.01 0.01 1)
      rotate (1 0 0) ({expr $base_angleW})  
      rotate (0 1 0) (90)
      translate ( { expr $base_sr + $base_cr} 0 {expr $base_s2})
      rotate (1 0 0) ({expr $base_alf})
      rotate (0 1 0) (-30)
    endinstance

    ###the point where the shortest distance between 2 cylinders are 2*cylinder's radius
    ###(fifth touching point)
    instance cyl3
      scale (0.01 0.01 1)
      rotate (1 0 0) ({expr -$base_angleV})  
      rotate (0 1 0) (90)
      translate ( { expr $base_sr + $base_cr} 0 {expr -$base_s3})
      rotate (1 0 0) ({expr $base_alf})
      rotate (0 1 0) (-30)
    endinstance

    ###the point where the shortest distance between 2 cylinders are 2*cylinder's radius
    ###(sixth touching point)
    instance cyl3
      scale (0.01 0.01 1)
      rotate (1 0 0) ({expr $base_angleV})  
      rotate (0 1 0) (90)
      translate ( { expr $base_sr + $base_cr} 0 {expr $base_s3})
      rotate (1 0 0) ({expr $base_alf})
      rotate (0 1 0) (-30)
    endinstance
endgroup

###group of 3 cylinders
group threeCylinder
   instance oneCylinder
     ###extra rotation
     rotate ( 1 0 0) (-90)
   endinstance

   instance oneCylinder
     rotate (0 0 1) (180)
     ###extra rotation
     rotate ( 1 0 0) (-90)
   endinstance

   instance oneCylinder
     rotate (0 1 0) (30)
     rotate (1 0 0) ({expr -$base_alf})
     translate ( {expr -($base_sr+$base_cr)} 0 0)
     rotate ( 0 1 0 ) (90)
     translate ( 0 0 {expr -($base_sr + $base_cr)} )
     rotate ( 0 0 1) ({expr -$base_alf})
     ###extra rotation
     rotate ( 1 0 0) (-90)
   endinstance
endgroup

###the cube
point p1 ( {expr 0.5*$base_scal}  {expr 0.5*$base_scal}  {expr 0.5*$base_scal}  ) endpoint
point p2 ( {expr -0.5*$base_scal} {expr 0.5*$base_scal}  {expr 0.5*$base_scal}  ) endpoint
point p3 ( {expr 0.5*$base_scal}  {expr -0.5*$base_scal} {expr 0.5*$base_scal}  ) endpoint
point p4 ( {expr -0.5*$base_scal} {expr -0.5*$base_scal} {expr 0.5*$base_scal}  ) endpoint
point p5 ( {expr 0.5*$base_scal}  {expr 0.5*$base_scal}  {expr -0.5*$base_scal} ) endpoint
point p6 ( {expr -0.5*$base_scal} {expr 0.5*$base_scal}  {expr -0.5*$base_scal} ) endpoint
point p7 ( {expr 0.5*$base_scal}  {expr -0.5*$base_scal} {expr -0.5*$base_scal} ) endpoint
point p8 ( {expr -0.5*$base_scal} {expr -0.5*$base_scal} {expr -0.5*$base_scal} ) endpoint

face f1 ( p1 p3 p7 p5 ) endface
face f2 ( p2 p6 p8 p4 ) endface
face f3 ( p1 p5 p6 p2 ) endface
face f4 ( p3 p4 p8 p7 ) endface
face f5 ( p1 p2 p4 p3 ) endface
face f6 ( p5 p7 p8 p6 ) endface

object cube 
    ( f1 f2 f3 f4 f5 f6) 
endobject

###the instance of 4 triangles of cylinders
group finalResult
    instance threeCylinder
      surface RED
      rotate (0 1 0) (35.24)
      rotate (1 0 0) (45)
    endinstance

    instance threeCylinder
      surface BLU
      rotate (0 1 0) (35.24)
      rotate (1 0 0) (-45)
    endinstance

    instance threeCylinder
      surface PURPLE
      rotate (0 0 1) (90) 
      rotate (1 0 0) (-35.24)
      rotate (0 1 0) (-45)
    endinstance

    instance threeCylinder
      surface GREEN
      rotate (0 0 1) (-90) 
      rotate (1 0 0) (35.24)
      rotate (0 1 0) (-45)
    endinstance

    instance cube
      shading SLF_WIRE
    endinstance
endgroup

group assembly
    ### final version
    instance finalResult
      shading SLF_WIRE
    endinstance
endgroup

#####################################
include "viewing.slf"
#####################################