=begin
Copyright 2005-2007, TIG

Permission to use, copy, modify, and distribute this software for 
any purpose and without fee is hereby granted, provided the above
copyright notice appear in all copies.

THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#-----------------------------------------------------------------------
Name        : Slicer.rb

Description : A tool to 'Slice' up a volume - useful in real-model 
			  making and finding likely areas in master plan volumes...

Menu Item   : Plugins -> Slicer

Context Menu: See menu-section at end on how to include it here: Slicer

Author      : TIG

Usage       : First select a Group or Component that has faces that   
form a volume, then use the Plugins Menu Item 'Slicer': you can aso  
pick the right-click Context-Menu and choose 'Slicer' IF you have 
enabled it (see menu-section at end)...

A dialog asks for the Slice spacing, the Slice thickness and the 
Slice orientation (XYZ).  The units are in current units...
Entering 0 thickness makes just a face.  Entering negative 
values reverts to default.  Entering spacing less than thickness 
reverts to default.  It also asks for the the Layer and Colour 
of the Slices.  The layer choices are 'Layer0' (or <Default> in your 
local langauge), a unique name 'SLCE-nnnnnnn' (it will then make a new 
layer named 'SLCE-nnnnnnn', where nnnnnnnn is based on the date/time), 
'<Make New Layer>' (it will then open another dialog & ask for a new 
layer-name) and then it lists of all other layers in alphabetical order.
The Colour choices are all of the default colours in alphabetical order.  
Tip: To scroll beyond bottom of list type the first letter of name and 
then search from there - e.g. W >> 'Wheat', then use arrow keys to 
scroll down to 'White'...

A dialog asks if you would like the slices equalized - Yes/No - if 
'Yes' - spacing is apportioned into total dimension for even spacing 
of all slices at the spacing or just below, if 'No' then slices are 
spaced as entered and the last slice's spacing is adjusted to fit any 
remaining gap. 

A dialog asks you if you want to number the slices - Yes/No - if 
'Yes' - an incrementing number is added to the slice near its lower-
left bounding-box corner.

If you are making more than 25 slices you are warned because this 
might take some time to process.

It then makes a series of slices through the selection's faces.  
If needed to fill the volume, an unevenly spaced last slice is added.  
Volumes with punched holes will get the slices formed around them but 
only to the 'accuracy' of the slice spacing and the slice thickness.
The slices are named Slice-n-nnnnnnnn (where n is the slice-number)

All of the slice-groups are combined into a group called Slice-nnnnnnnn.

Before ending it checks if 'Xray Mode' was already switched 'on' at 
the start and if so there is no action and it exits.  Otherwise the 
original selection is 'Hidden' so you can clearly see the slice-group.  
You are then asked in a dialog if you want to leave it 'Hidden'.  
If 'Yes' then it exits leaving it 'Hidden'.  If 'No' the original 
selection is 'Unhidden' and 'Xray Mode' is then switched 'on' so you 
can see the slice-group inside of the original selection and a dialog 
asks if you want to leave 'Xray Mode' switched 'on'.  If you answer 
'No' the normal view is restored and it exits (but then the slices will 
be obscured !).  If you answer 'Yes' it exits leaving 'Xray Mode' 
switched 'on'.

You are finally asked if you would like to make a 'flattened' copy.  
Answer 'Yes' to make another group.  A dialog asks for the min. gap 
between 'flattened' slices in current units.  The flattened-slices 
group is named 'Flat-Slice-nnnnnnn' on layer FLAT-+'Your_Layer_Name'.  
It is placed below the original slice-base with all slices put down 
'flattened' with equal Zs, arranged in order, in as near a 'square' 
pattern (n x n) as possible.  Because the non-Z oriented slices have 
to be rotated 'flat' and when rotated they shouldn't overlap, you will 
find that sometimes the spacings between rows(Y) or columns(X) will 
exceed the minimum gap specified.  You can always move the flattened 
numbered slices around by editing the flattened-slice group - this 
might then further optimise any real material use etc.

'Slicer' can't be expected to be 100% foolproof !  It treats an open 
topped object as it if were filled with water, taking slices from the 
outer 'skin' inwards to work out which are the solid and which are the 
hollow volumes.  With a little ingenuity you will be able to contrive
a form with complex linked holes punched in, or a suitable array of 
thin volumes spaced apart so as to miss the sampling slices - which 
because it uses a series of slices, can produce unexpected results.
Keep forms simple and build them up in bits for safety...

Date        : 12/2005

Type        : Tool

Verison     :	
1.0	18/12/05	First issue.
1.1	18/12/05	Inches --> inch typo fixed.
1.2	18/12/05	Circle def moved into class (Mac).
1.3	19/12/05	X orienatation and last slice glitch fixed.
1.4	19/12/05	Decimal . AND , trapped...
1.5	19/12/05	Disc made larger...
1.6	20/12/05	Pushpull made compatible with earlier version.
				Glitch with groups on -ve axes fixed.
				Option to equalize slice spacings added.
1.7	20/12/05pm	v5+ program only error added.
1.8	21/12/05	Undo text corrected.
1.9	22/12/05	Slice numbering option added.
2.0	24/12/05	Glitches in number locations fixed.
				Slices and their Numbers are now grouped 
				individually inside one bigger group.
				Option to make a 'flattened' copy added.
2.1	16/12/06	'Layer0' removed - Spanish versions etc, now 
				makes active_layer the default, whatever it's name - 
				& puts text/slices on it before layering groups.
3.0 09/10/07	Choose / make Layer on fly and select any 'Colour' 
				options added.  All geometry now on 'default' layer.
3.1 16/10/07	Menu error corrected = for all to use...

#-----------------------------------------------------------------------
=end

require 'sketchup.rb'

###

class Slicer

###---------------------------------------

def Slicer::calculate
 
### version error
if (Sketchup.version.split(".")[0].to_i<5)
     UI.beep
     UI.messagebox("Sorry.  This is Version 5+ program only !")
     return nil
end#if
###
model = Sketchup.active_model
model.active_layer = nil###16/12
layer = nil ###6/12 now Layer0 capa0 etc ###v3.0 = default
entities = model.entities
definitions = model.definitions
model.start_operation "Slicer"
ss = model.selection
view = model.active_view
sfix = Time::now.to_i.to_s[3..-1]

  if ss.empty?
     UI.beep
     UI.messagebox("NO Selection !")
     return nil
  end#if
  if ss[1]
     UI.beep
     UI.messagebox("Selection MUST be ONE Group or Component !")
     return nil
  end#if
  if ss[0].typename != "Group" and ss[0].typename != "ComponentInstance"
     UI.beep
     UI.messagebox("Selection is NOT a Group or Component !")
  end#if

###
selected = ss[0]
###

# -------------- set up @spacing, @thickness and @xyz in def dialog for later...
# -------------- make cutting disc face at xy bounds
###
# ----------- dialog ----------------
### show VCB and status info
  Sketchup::set_status_text(("SLICER PARAMETERS..." ), SB_PROMPT)
  Sketchup::set_status_text(" ", SB_VCB_LABEL)
  Sketchup::set_status_text(" ", SB_VCB_VALUE)
  return nil if not Slicer.dialog
###
bb = selected.bounds
xmin = bb.min.x
xmax = bb.max.x
ymin = bb.min.y
ymax = bb.max.y
zmin = bb.min.z
zmax = bb.max.z
###
#### ------- slice, thickness & xyz inc ------------------------------
### orientation ?
pnt1 = [xmin,ymin,zmin] if @xyz == "Z"
pnt2 = [xmax,ymax,zmin] if @xyz == "Z"
dist = ([0,0,zmin].distance [0,0,zmax]) if @xyz == "Z"
#
pnt1 = [xmin,ymin,zmin] if @xyz == "Y"
pnt2 = [xmax,ymin,zmax] if @xyz == "Y"
dist = ([0,ymin,0].distance [0,ymax,0]) if @xyz == "Y"
#
pnt1 = [xmin,ymin,zmin] if @xyz == "X"
pnt2 = [xmin,ymax,zmax] if @xyz == "X"
dist = ([xmin,0,0].distance [xmax,0,0]) if @xyz == "X"
#
###v1.6 uses dist rather than max & min where -ve values interfer !!!
#
### ask if equalized spacing v1.6
  Sketchup::set_status_text(("EQUALIZE SLICE SPACINGS ?" ), SB_PROMPT)
  Sketchup::set_status_text(" ", SB_VCB_LABEL)
  Sketchup::set_status_text(" ", SB_VCB_VALUE)
  evenup=1
  evenup=0 if UI.messagebox("Equalize the slice spacings to fit ?\n\n(Remember slice spacings might then be made less than specified)   \n",MB_YESNO,"Equalize ?")==7 ##=NO
  if evenup == 1
     spacing = (dist-@thickness)/((dist-@thickness)/@spacing).ceil
  else
     spacing = @spacing
  end#if even
###
### ask if number slices v1.9
  Sketchup::set_status_text(("ADD A NUMBER TO EACH SLICE ?" ), SB_PROMPT)
  Sketchup::set_status_text(" ", SB_VCB_LABEL)
  Sketchup::set_status_text(" ", SB_VCB_VALUE)
  num=1
  num=0 if UI.messagebox("Add a Number to each Slice ?   ",MB_YESNO,"Number ?")==7 ##=NO
###
### check if too many slices !
q=(dist/spacing).ceil+1
if q > 25 ### max number of slices that don't take too long...
### show VCB and status info
  Sketchup::set_status_text(("LARGE NUMBER OF SLICES ? " ), SB_PROMPT)
  Sketchup::set_status_text(" ", SB_VCB_LABEL)
  Sketchup::set_status_text(" ", SB_VCB_VALUE)
  (return nil if UI.messagebox("This will make #{q.to_s} slices !   \nDo you want to continue ?   ",MB_YESNO,"Slice Count !")==7) if evenup==0 ##=NO
  (return nil if UI.messagebox("This will make #{(q-1).to_s} slices !   \nDo you want to continue ?   ",MB_YESNO,"Slice Count !")==7) if evenup==1 ##=NO
###v2.0
end#if
#
ctr = Geom.linear_combination(0.5,pnt1,0.5,pnt2)
rad = (pnt1.distance pnt2) ### make a LOT bigger than bb
###
disc = entities.add_group
discentities = disc.entities
disccircle = Slicer.circle(ctr,[0,0,-1],rad,24) if @xyz == "Z"
disccircle = Slicer.circle(ctr,[0,-1,0],rad,24) if @xyz == "Y"
disccircle = Slicer.circle(ctr,[-1,0,0],rad,24) if @xyz == "X"
#
discentities.add_face disccircle

### parent group
pslice = entities.add_group
psliceentities = pslice.entities
pslice.name= "Slice-"+sfix

# ------------------------ do each of slice
###
### intersect disc and selected
###
### The intersect_with method is used to intersect entities, a component instance, or group
### with an entities object.
###
### entities.intersect_with recurse, transformation1, entities1, transformation2, hidden, entities2
###
### recurse - true if you want this entities object to be recursed 
###   (intersection lines will be put inside of groups and components within this entities object)
### transformation1 - the transformation for this entities object
### entities1 - the entities (group etc) where you want the intersection lines to appear
### transformation2 - the transformation for entities1
### hidden - true if you want hidden geometry in this entities object to be used in the intersection
###   (it's false in section cuts)
### entities2 - an entities object (or an array of entities ?)
###
### loop through all possible slices - bottom up
###
t = @thickness * 1.5 ###v2.0
m = spacing * 1      ###v2.0
s = 0.05.mm
c = 1
slices=[]
################################################
######################
while c < q ### v1.6

slice = psliceentities.add_group ### add into parent group ### v2.0
sliceentities = slice.entities
slice.name= "Slice-"+(c.to_s)+"-"+sfix

### show VCB and status info
  Sketchup::set_status_text(("MAKING SLICE EDGES #{c} of #{q}"), SB_PROMPT) if evenup==0
  Sketchup::set_status_text(("MAKING SLICE EDGES #{c} of #{q-1}"), SB_PROMPT) if evenup==1
  Sketchup::set_status_text(" ", SB_VCB_LABEL)
  Sketchup::set_status_text(" ", SB_VCB_VALUE)
### do cut
  disc.move! Geom::Transformation.new [0,0,s] if @xyz == "Z"
  disc.move! Geom::Transformation.new [0,s,0] if @xyz == "Y"
  disc.move! Geom::Transformation.new [s,0,0] if @xyz == "X"
###
  discentities.intersect_with true, disc.transformation, slice, slice.transformation, true, selected
###
### do last slice at dist ### v1.6
  if s+spacing >= dist and evenup==0
     ###
     dslice = psliceentities.add_group ### add into parent group
     dsliceentities = dslice.entities
     dslice.name= "Slice-"+((c+1).to_s)+"-"+sfix
     ###
     d=dist-@thickness ### v1.6
     d=dist-0.05.mm if @thickness == 0 ### to make a cut v1.6
   ### do cut
     disc.move! Geom::Transformation.new [0,0,d] if @xyz == "Z"
     disc.move! Geom::Transformation.new [0,d,0] if @xyz == "Y"
     disc.move! Geom::Transformation.new [d,0,0] if @xyz == "X"
   ###
     discentities.intersect_with true, disc.transformation, dslice, dslice.transformation, true, selected
   ###
  bb=dslice.bounds
  zmin=bb.min.z
  ymin=bb.min.y
  xmin=bb.min.x
   ###
     dtt=dsliceentities.add_text((c+1).to_s, [xmin+m,ymin+m,zmin+t]) if num==1 and @xyz == "Z" and evenup==0
     dtt=dsliceentities.add_text((c+1).to_s, [xmin+m,ymin+t,zmin+m]) if num==1 and @xyz == "Y" and evenup==0
     dtt=dsliceentities.add_text((c+1).to_s, [xmin+t,ymin+m,zmin+m]) if num==1 and @xyz == "X" and evenup==0
   ###
     dtt.layer= layer if dtt
     dslice.layer= layer if dslice
   ###
     slices=slices.push(dslice) ### keep list of slices for later use
   ###
  end#if
###
  bb=slice.bounds
  zmin=bb.min.z
  ymin=bb.min.y
  xmin=bb.min.x
###
  tt=sliceentities.add_text(c.to_s, [xmin+m,ymin+m,zmin+t]) if num==1 and @xyz == "Z"
  tt=sliceentities.add_text(c.to_s, [xmin+m,ymin+t,zmin+m]) if num==1 and @xyz == "Y"
  tt=sliceentities.add_text(c.to_s, [xmin+t,ymin+m,zmin+m]) if num==1 and @xyz == "X"
###
  tt.layer= layer if tt
  slice.layer= layer if slice
###
  slices=slices.push(slice) ### keep list of slices for later use
###
  s = s+spacing
  c = c+1
###

end#while
#####################

### delete disc
disc.erase!

### loop through all slices
k=1
j=slices.length
area=0
###
for slice in slices

sliceentities=slice.entities
### show VCB and status info
  Sketchup::set_status_text(("PROCESSING SLICES #{k} of #{j}" ), SB_PROMPT)
  Sketchup::set_status_text(" ", SB_VCB_LABEL)
  Sketchup::set_status_text(" ", SB_VCB_VALUE)
k=k+1
###
### face the slices
c = 1
q=sliceentities.length
for e in sliceentities
  e.find_faces if e.typename == "Edge"
  c = c+1
end#for e
###
c = 1
q=sliceentities.length
faces = []
for f in sliceentities
   if f.typename == "Face"
      faces = faces.push(f)
   end
   c = c+1
end#for f
faces = faces.uniq
###
c = 1
q=faces.length
for face in faces
   face.reverse! if face.normal == [0,0,-1]  if  @xyz == "Z"
   face.reverse! if face.normal == [0,-1,0]  if  @xyz == "Y"
   face.reverse! if face.normal == [-1,0,0]  if  @xyz == "X"
   c = c+1
end#for face
###
### now work out which is which...
keptfaces = []
(faces.length-1).times do |this|
   c=1
   q=faces.length
   for face in faces
    c=c+1
    ###
    if face.valid?
      for edgeuse in face.outer_loop.edgeuses
         if not edgeuse.partners[0] ### outermost face
            keptfaces = keptfaces.push(face)
            faces = faces - [face]
            loops = face.loops
            for loop in loops
               for fac in faces
                  if fac.valid? and (fac.outer_loop.edges - loop.edges) == []
                     faces = faces - [fac]
                     fac.erase!### fac abutts kept face so it must be erased...
                  end #if fac
               end #for fac
            end #for loop
         end #if outermost
      end #for edgeuse
    end #if valid
   end #for face
end#times
###
### -------------- now give slices thickness
faces=[]
for f in sliceentities
  faces=faces.push(f) if f.typename == "Face"
end#for f
c = 1
q=faces.length
for f in faces
  ### v3.0
  if @material=="<Default>"
    f.material=nil
  else
    f.material= @material
  end#if
  ### v3.0
  f.layer= layer
  for e in f.edges
     e.layer= layer
  end#for e
  area = (area+f.area)
  c = c+1
end#for f
###
c = 1
q=faces.length
for f in faces
  (f.pushpull @thickness) if @thickness != 0
  f.reverse! if @thickness == 0 and @xyz == "Y"
  c = c+1
end#for f
###
### clear VCB and status info
  Sketchup::set_status_text((" " ), SB_PROMPT)
  Sketchup::set_status_text(" ", SB_VCB_LABEL)
  Sketchup::set_status_text(" ", SB_VCB_VALUE)
###

end###for slice in slices
###
if area == 0
   UI.beep
   UI.messagebox("There is NO Volume to Slice !")
   pslice.erase! if pslice.valid?
   return nil
end#if
###
###
#----------- sort Layer settings etc
###layerSlice = ("SLCE-"+sfix)###v3.0
layerSlice = model.layers.add(@layerSlice) ### v3.0
#layerSlice.page_behavior=(LAYER_IS_HIDDEN_ON_NEW_PAGES | LAYER_HIDDEN_BY_DEFAULT)
layerSlice.visible=true
pslice.layer=layerSlice

### unselected...
model.selection.clear
###
### hide selected
xray = 0
if not model.rendering_options["ModelTransparency"] ### NOT xray mode
   selected.hidden= true
   if UI.messagebox("Do you want to leave the Original Selection 'Hidden' for now ?  ",MB_YESNO,"Volume Hidden ?") == 7 ### 6=YES 7=NO
      xray = 1
      selected.hidden= false
   end#if
end#if
### xray ?
xrayq= 0
if not model.rendering_options["ModelTransparency"]
   xrayq = 1
   model.rendering_options["ModelTransparency"]=true if xray == 1
end#if
###
### ---- undo xray IF was not on already
if xray == 1 and xrayq == 1
  model.rendering_options["ModelTransparency"]=false if UI.messagebox("Do you want to leave 'Xray Mode' on for now ?  ",MB_YESNO,"Volume Xray ?")==7 ###7=NO
end#if
###

### Flattern ?
return nil if UI.messagebox("Do you want to make a 'Flattened' copy of the Slices ?  ",MB_YESNO,"Flatten ?") == 7 ### 6=YES 7=NO
### VCB and status info
  Sketchup::set_status_text(("FLATTENING SLICES..." ), SB_PROMPT)
  Sketchup::set_status_text(" ", SB_VCB_LABEL)
  Sketchup::set_status_text(" ", SB_VCB_VALUE)
###
return nil if not Slicer.gap ### get gap
gap=@gap
fslice=pslice.copy
fslice.name="Flat-"+pslice.name
fents=fslice.entities
fs=fents.length
fb=pslice.bounds
z=fb.min.z
y=fb.min.y
x=fb.min.x
if @xyz=="Z"
   y=fb.max.y-fb.min.y 
else
   ym=fb.max.z-fb.min.z
end#if z
if @xyz=="X"
   xm=fb.max.z-fb.min.z
   yg=fb.max.y-fb.min.y
   xs=x
end#if x
xx=0
yy=0
zz=0
sq=Math::sqrt(fs).to_i###round
sqq=sq
c=0
###
for e in fents
   e.layer= layer
   p=e.bounds.min
   px=p.x
   py=p.y
   pz=p.z
   pp=e.bounds.max
   pxx=pp.x
   pyy=pp.y
   pzz=pp.z
   pt=[xx,yy,z-pz] if @xyz=="Z" 
   pt=[xx,y-py,z-pz] if @xyz=="Y"
   pt=[xx,y-py,z-pz] if @xyz=="X"
   tr=Geom::Transformation.new pt
   e.transform! tr
   xx=xx+(pxx-px)+gap if @xyz=="Z" or @xyz=="Y"
   xx=xx+xm+gap if @xyz=="X"
   if c==sqq and @xyz=="Z"
      yy=yy+(y+gap)
      xx=0
      sqq=sqq+sq+1
   elsif c==sqq and @xyz !="Z"
      y=y+(ym+gap) if @xyz=="Y"
      y=y+(yg+gap) if @xyz=="X"
      xx=0 if @xyz=="Y"
      xx=xs-px if @xyz=="X"
      sqq=sqq+sq+1
   end#if
   c=c+1
end#for e
### this forces bb to correct itself...
tmp=fents.add_line fents[0].bounds.min,fents[fents.length-1].bounds.max
tmp.erase!
###
### rotation for XY versions
if @xyz !="Z"
 r = Math::PI / 2
 for e in fents
  eb=e.bounds.min
  p=[eb.x,eb.y,fb.min.z]
  v=Geom::Vector3d.new 0,-1,0 if @xyz=="X"
  v=Geom::Vector3d.new -1,0,0 if @xyz=="Y"
  rotate=Geom::Transformation.rotation p,v,r
  e.transform! rotate
 end#for e
end#if !=Z
###
### this forces bb to correct itself...
tmp=fents.add_line fents[0].bounds.min,fents[fents.length-1].bounds.max
tmp.erase!
#----------- sort Layer settings etc for 'flat' layer...
layerSlice = ("FLAT-"+@layerSlice) ### v3.0
layerSlice = model.layers.add(layerSlice)
#layerSlice.page_behavior=(LAYER_IS_HIDDEN_ON_NEW_PAGES | LAYER_HIDDEN_BY_DEFAULT)
layerSlice.visible=true
fslice.layer=layerSlice
#########
### update view
view.invalidate

# ---------------------- Close/commit group
model.commit_operation

#-----------------------
end#def

###################################################
def Slicer::dialog

### get current units ----------------------
currentunits1=Sketchup.format_length 120000
currentunits2=Sketchup.format_length 1
units = "???" ### default
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "120000"
   units = "inches"
end
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "10000"
   units = "feet"
end
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "3048000"
   units = "mm"
end
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "304800"
   units = "cm"
end
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "3048"
   units = "m"
end
if currentunits2 == "1\""
   units = "inches or ' \" "
end
### ---------------
if units[-1,1] == "m" ### metric units so these are in metres
         xspacing = 50.mm
         xthickness = 3.mm
      else ### not metric so these are in feet
         xspacing = 2.inch
         xthickness = 0.125.inch
      end #if
###
   xyz="X|Y|Z"
### v3.0
   mlayers=Sketchup.active_model.layers
   layers=[]
   mlayers.each{|e|layers.push e.name}
   dlayer=layers[0]
   layers=layers-[dlayer]
   layers.sort!
   #----------- sort possible special Layer...
   @sfix=Time::now.to_i.to_s[3..-1]
   layerSlice=("SLCE-"+@sfix)
   @makelayer="<Make New Layer>"
   layers=[dlayer]+[layerSlice]+[@makelayer]+layers
   layers.uniq!
   layers=layers.join('|')
   ###
   mcolours=Sketchup.active_model.materials
   colours=[]
   mcolours.each{|e|colours.push e.name}
   colours.sort!
   colours=["<Default>"]+colours+(Sketchup::Color.names.sort!)
   colours.uniq!
   colours=colours.join('|')
### v3.0
### get info
   prompts = ["Slice Spacing ("+units+"): ","Slice Thickness ("+units+"): ","Slice Orientation: ","Layer: ","Colour: "]
   types = ["","",xyz,layers,colours]
   title = "Slicer Parameters"
   @spacing = xspacing if not @spacing
   @thickness = xthickness if not @thickness
   @xyz = "Z" if not @xyz
   @layerSlice = dlayer if not @layerSlice
   @material = "<Default>" if not @material
   values = [@spacing,@thickness,@xyz,@layerSlice,@material]
   popups = ["","",xyz,layers,colours]
   results = inputbox( prompts, values, popups, title )
   return nil if not results
### do processing of results
@spacing = results[0]
@thickness = results[1]
@xyz = results[2]
@layerSlice = results[3]###v3.0
@material = results[4]###v3.0
###
if @spacing <= 0
   UI.beep
   UI.messagebox("Spacing CAN'T be <= 0 !  \nMade default = #{xspacing} #{units}")
   @spacing = xspacing
end#if
###
if @thickness > @spacing
   UI.beep
   if xthickness < @spacing
      UI.messagebox("Thickness CANNOT > Spacing !  \nThickness = default = #{xthickness} #{units}")
      @thickness = xthickness 
   else
      UI.messagebox("Thickness CANNOT > Spacing !  \nThickness = Spacing = #{@spacing} #{units}")
      @thickness = @spacing
   end#if
end#if
###
### v3.0
### make layer dialog
if @layerSlice==@makelayer
   results2=inputbox(["New Slices Layer Name: "],["????"],"New Layer Name")
   if results2
      @layerSlice=results2[0]
   else
      @layerSlice=nil ### default layer
	  return nil ### cancel everything
   end#if
end#if
### v3.0

true

end #def dialog
###################

###################################################
def Slicer::gap

### get current units ----------------------
currentunits1=Sketchup.format_length 120000
currentunits2=Sketchup.format_length 1
units = "???" ### default
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "120000"
   units = "inches"
end
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "10000"
   units = "feet"
end
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "3048000"
   units = "mm"
end
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "304800"
   units = "cm"
end
if currentunits1.to_s.split(".")[0].split(",")[0].split("'")[0].split("\"")[0].split("c")[0].split("m")[0] == "3048"
   units = "m"
end
if currentunits2 == "1\""
   units = "inches or ' \" "
end
### ---------------
if units[-1,1] == "m" ### metric units so these are in mm
         xgap = 10.0.mm
      else ### not metric so these are in inches
         xgap = 0.5.inch
      end #if
### get info
   prompts = ["#{units}: "]
   types = [""]
   title = "Minimum Gap"
   @gap = xgap if not @gap
   values = [@gap]
   popups = [""]
   results = inputbox( prompts, values, popups, title )
   return nil if not results

### do processing of results
@gap = results[0]
###

true

end #def gap
###################

# --- Function for generating points on a circle
def Slicer::circle(center,normal,radius,numseg)
    # Get the x and y axes
    axes = Geom::Vector3d.new(normal).axes
    center = Geom::Point3d.new(center)
    xaxis = axes[0]
    yaxis = axes[1]
    xaxis.length = radius
    yaxis.length = radius
    # compute the points
    da = (Math::PI * 2) / numseg
    pts = []
    for i in 0...numseg do
        angle = i * da
        cosa = Math.cos(angle)
        sina = Math.sin(angle)
        vec = Geom::Vector3d.linear_combination(cosa,xaxis,sina,yaxis)
        pts.push(center + vec)
    end
    # close the circle
    pts.push(pts[0].clone)
    pts
end#def
##########################

#-----------------------
end#class
#-----------------------


#--------- menu -----------------------------
if( not file_loaded?("Slicer.rb") )
###if( not file_loaded?("58-Slicer.rb") )
   add_separator_to_menu("Plugins")###
   UI.menu("Plugins").add_item("Slicer") { Slicer.calculate }###
   ###$submenu5.add_item("Slicer") { Slicer.calculate }###
### remove ### in front of 6 lines below if to display in context-menu...
   ###UI.add_context_menu_handler do | menu |
   ###   if Sketchup.active_model.selection[0].typename == "Group" or Sketchup.active_model.selection[0].typename == "ComponentInstance"
   ###      menu.add_separator
   ###      menu.add_item("Slicer") { Slicer.calculate }
   ###   end #if ok
   ###end #do menu
  
end#if
###file_loaded("58-Slicer.rb")
file_loaded("Slicer.rb")
#---------------------------------
