=begin
___________________________________________________________________________
TIG (c) 2011 - 2016
All Rights Reserved.
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.
___________________________________________________________________________
Script: CADup.rb
___________________________________________________________________________
Usage:

This makes lines drawings of views of a Group or Component-Instance ready 
for use in a CAD program.
It is best to use this tool in an uncluttered SKP so that the intersections 
of entities needed to do the complex geometry calculations are not 
compromised by other unrelated entities [even if they might be 'hidden'].
Also place your Component-Instance OR Group with its insert-point at the 
ORIGIN.  If it is not located there then a copy of it is placed there, 
however, ensure there is nothing else in the vicinity of the ORIGIN, 
including any 'misplaced' Component/Group itself.
It's recommended that you select your component and right-click save_as to 
process it as an external isolated component if possible.
Do NOT try and process a whole building with furnishings and fittings - the 
amount of data in that collection of things will just 'kill' Sketchup!

So, select your Component-Instance OR Group [and nothing else].
Pick 'CADup' off the 'Tools' menu [or type 'cadup' or 'skad' in the 
Ruby Console]
If there is not one Component-Instance OR Group selected there is an error-
message.
'CompoName' is the Component-Instance-Definition's name, OR if a Group is 
selected then the Group's name [or 'Group' if the Group is 'un-named'].
It runs with information displayed in the Status Bar and the view refreshed 
after each step [v7+ only].
It creates a new Component called 'CompoName[SKAD]' on layer 'SKAD'.
If that name is already used it's incremented with a #1, #2... suffix...
Within that it makes a temporary grouped and exploded version of the 
selected Component/Group located on the ORIGIN.  At the end this temporary 
group is erased and the selected Component/Group is replaced where it was.
It has a flat 3d-text label which reads '3D' on layer 'SKAD.TEXT' 
[it's name is 'TEXT'].
It then creates the 6 flat 2D orthogonal views of the Component/Group 
within the 'CompoName[SKAD]', in turn: they are named:-
TOP
BOTTOM
FRONT
BACK
RIGHT
LEFT
[Equivalent to the Plan and Reflected-Plan, and the South, North, East and 
West Elevations respectively]

These are each grouped and named 'SKAD-TOP', 'SKAD-BOTTOM' etc [each is on 
Layer0].
Within each view's group there are sub-groups:-
a) 'TEXT' on layer 'SKAD.TEXT' which is a flat 3d-text label which reads 
'TOP', 'BOTTOM' etc.
b) 'TOP-CONT', 'BOTTOM-CONT' etc [each on layer 'SKAD.CONT'] which contains 
all of the CONTinuous solid edges that would be seen in each view.
c) 'TOP-HIDN', 'BOTTOM-HIDN' etc [each on layer 'SKAD.HIDN'] which contains 
all of the HIDdeN edges that would be obscured in each view, also has any 
hidden/soft/smooth edges in it - e.g. the curved surface of a cylinder.
d) 'TOP-CIRC', 'BOTTOM-CIRC' etc [each on layer 'SKAD.CIRC'] which contains 
all of the CIRCles [and arcs] that are perpendicular to each view with a 
small + at their centers - the + is on a layer called 'SKAD.CPTS'.  
Note that the segments of the circles/arcs are also shown in the 'CONT' 
version as individual lines - however, exporting a 3D DXF/DWG will export 
the separate layer's entities as Circles/Arcs and these will be identified 
as those types of object in the CAD program - useful for 'drilling' etc.

A collection of 6 SECTions is added - similar to the 'view' but with it 
cutting the selected object at its center and having an additional grouped 
set of lines 'SECT'.  The are name after the direction of the section-view 
not like the views them selves - so the view 'TOP' shows the top looking 
down but the 'SECT-TOP' shows the underside of the top looking up.  
The SECTions are named:-
SECT-BOTTOM
SECT-TOP
SECT-FRONT
SECT-BACK
SECT-RIGHT
SECT-LEFT
[Equivalent to the Internal-Plan and True-Ceiling-Plan, and the 
Sections looking South, North, East and West respectively]

These are grouped/layered etc in a similar way to the 'views'

A collection of the 4 flattened AXOnometric views is added.  
They do not show hidden lines or separate circles, but are otherwise 
similar to the 'views'.  
Each is dimesionally correct in the Y and lines that are at 45 degrees to 
the main axes.  The AXOnometrics are named:-
AXO-NW
AXO-SW
AXO-SE
AXO-NE

These flat 2D view-groups are arranged on the z=0 plane.
They are arranged logically around the 3D version, oriented consistently.
They are spaced equally using the variable '@gap' which is set to 100mm at 
the start of the code - it can be adjusted - note that it must be > 0...
The 3d-text labels' height is default @gap/2 - i.e. default is 50mm.
The Circles' '+' cpt-marker is default @gap/4 - i.e. default is 25mm.
The CADup default @skadname="SKAD" is also set at the start of the code, and 
this can be changed if desired...

It's a good idea to have your current Style set to use 'Material by Layer' 
and color the various layers to mimic CAD colors etc - see below...***

Be patient - there are lots of operations to complete...

You can of course edit the separate view-group parts - e.g. erasing some 
lines etc that you think are not needed.
Once the set is complete to your satisfaction you can export the new 
collection to a separate SKP [right-click 'Save-AS...'] and thence as a 
DWG or DXF to use in a CAD program.

***The layering of the parts is specifically tailored to suit this CAD use.
If your CAD template file has the plotting pens set be 'by layer', then 
you can set the layer 'SKAD.CONT' to be a medium/thin solid pen-style, the 
layer 'SKAD.HIDN' to be a fine dash/dot/hidden pen-style.  The 'SKAD-CIRC' 
layer can also be used for hole-drilling etc or merged with an edited CONT 
layer as desired.  The 'SKAD-SECT' layer should be set to a thick solid 
pen-style to display the section-cut appropriately.
Once you have a set of layers set up for this you can save a CAD DWG as a 
template [DWT] and reuse that to make new DWGs of this type, inserting the
individual SKP>DWG files as Blocks and arranging and editing then as 
desired...
___________________________________________________________________________
Donations: By PayPal.com to info @ revitrev.org
___________________________________________________________________________
Version:
1.0 20110215 First Beta Release.
1.1 20110218 A Group OR an Instance now processed.
             Edges within any Groups/Instances within the Selected Object 
             are now reproduced on appropriate layers.
             Edges that are hidden/smooth/soft in the Selected Object are 
             now reproduced on the HIDN layer.
             Spacing of Views etc improved.
             Has a trial version of SECT-BOTTOM only - for feed-back...
             Has a trial version of AXO-SW only - for feed-back...
1.2 20110221 Container now made into a Component for easier export to SKP.
             All SECTion and AXOnonmetric views added.
             Arrangement of parts adjusted and the use of the original 
             selected object has be modified to minimize 'clashes'.
             Default name 2CAD becomes SKAD.
1.3 20110315 Various glitches addressed. Dialog to select which 2D views 
             are made and if CAD format auto-exported etc.
___________________________________________________________________________
=end
###
require 'sketchup.rb'
###

###
class SKAD
  
  def initialize()
    ###
    @gap=100.mm if not @gap ### @gap MUST be > 0. 
    @tht=50.mm if not @tht  ### The text-height is @gap/2
    @cmk=25.mm if not @cmk  ### The circle cpt marker @gp/4
    @skadname="SKAD" if not @skadname
    ###
    model=Sketchup.active_model()
    path=model.path
    if not path or path==""
      UI.messagebox(@skadname+":\nSKP must be saved!\nExiting...")
      return nil
    end#if
    folder=File.join(File.dirname(path),@skadname).tr("\\","/")
    ss=model.selection
    if not ss[0] or ss[1] or not (ss[0].class==Sketchup::Group or ss[0].class==Sketchup::ComponentInstance)
      UI.messagebox(@skadname+":\nSelect ONE Group OR Component Instance!\nExiting...")
      return nil
    end#if
    sinst=ss[0]
    ###
    return nil if not self.dialog()
    ###
    ss.clear
    begin
      model.start_operation(@skadname, true)
    rescue
      model.start_operation(@skadname)
    end
    GC.start
    view=model.active_view
    ### remember original sinst info.....................
    smat=sinst.material
    slay=sinst.layer
    attrdicts=sinst.attribute_dictionaries
    str=sinst.transformation
    oents=sinst.parent.entities
    ### GROUP--------------------------------------------------------------
    defn=sinst.definition
    dents=defn.entities
    if sinst.class==Sketchup::Group
      name=sinst.name
      name="Group" if not name or name==""
    else
      name=defn.name
    end
    layers=model.layers
    layer2CAD=layers.add(@skadname)
    layerCONT=layers.add(@skadname+"-CONT")
    layerHIDN=layers.add(@skadname+"-HIDN")
    layerCIRC=layers.add(@skadname+"-CIRC")
    layerCPTS=layers.add(@skadname+"-CPTS")
    layerTEXT=layers.add(@skadname+"-TEXT")
    layerSECT=layers.add(@skadname+"-SECT")
    ents=model.active_entities
    gp=ents.add_group()
    gname=name+"["+@skadname+"]"
    gp.name=gname
    gp.layer=layer2CAD
    gents=gp.entities
    ### temp 3D------------------------------------------------------------
    inst=gents.add_group()
    ients=inst.entities
    Sketchup::set_status_text(gname+": Making Temporary Exploded Copy...",SB_PROMPT)
    ins=ients.add_instance(defn, str)
    ovec=ins.transformation.origin.vector_to(ORIGIN)
    tr=Geom::Transformation.translation(ovec)
    ins.transform!(tr)
    ###
    def xplode(ents)
      ents.to_a.each{|ent|
        if ent.class==Sketchup::Group or ent.class==Sketchup::ComponentInstance
          ent.explode
          ents.to_a.each{|e|xplode(ents)}
        end#if
      }
    end#def
    ###
    xplode(ients)
    ###
    ### erase original temporarily..................
    sinst.erase!
    ###
    ### get bounds................
    inst.definition.invalidate_bounds
    bb=inst.bounds
    max=bb.max
    min=bb.min
    maxx=max.x+@gap
    maxy=max.y+@gap
    maxz=max.z+@gap
    minx=min.x-@gap
    miny=min.y-@gap
    minz=min.z-@gap
    bbx=bb.width
    bby=bb.height
    bbz=bb.depth
    cen=bb.center
    cenx=cen.x
    ceny=cen.y
    cenz=cen.z
    dx=bb.width
    dy=bb.height
    dz=bb.depth
    ###
    txtgp=gents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("3D", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0.0, false, 0.0)
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new([0, miny, 0])
    txtgp.move!(tr)
    begin
      view.refresh
    rescue
    end
    ### TOP----------------------------------------------------------------
    Sketchup::set_status_text(gname+": Making Top View...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-TOP"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,miny,maxz],[maxx,miny,maxz],[maxx,maxy,maxz],[minx,maxy,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="TOP-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="TOP-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].z.abs>0.9999 ### no verticals
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.z=es.z-1
        ee.z=ee.z-1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, Z_AXIS]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, Z_AXIS)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, Z_AXIS)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="TOP-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    fgp.erase!
    ###
    ### move to z=0
    tr=Geom::Transformation.translation([0, 0, -maxz])
    tents.transform_entities(tr, tents.to_a)
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("TOP", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new([0, miny, 0])
    txtgp.transform!(tr)
    ### move up
    tr=Geom::Transformation.translation([0, maxy-miny, 0])
    tents.transform_entities(tr, tents.to_a)
    begin
      view.refresh
    rescue
    end
    ### BOTTOM ------------------------------------------------------------
    Sketchup::set_status_text(gname+": Making Bottom View...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-BOTTOM"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,miny,minz],[maxx,miny,minz],[maxx,maxy,minz],[minx,maxy,minz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="BOTTOM-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="BOTTOM-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].z.abs>0.9999 ### no verticals
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.z=es.z+1
        ee.z=ee.z+1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, Z_AXIS.reverse]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, Z_AXIS.reverse)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, Z_AXIS.reverse)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="BOTTOM-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    fgp.erase!
    ###
    ### flip
    tr=Geom::Transformation.rotation(tgp.bounds.center, X_AXIS, 180.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### place at z=0
    tr=Geom::Transformation.translation([0, 0, -minz])
    tents.transform_entities(tr, tents.to_a)
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("BOTTOM", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new([0, miny, 0])
    txtgp.transform!(tr)
    ### move up
    tr=Geom::Transformation.translation([0, maxy-miny+maxy-miny, 0])
    tents.transform_entities(tr, tents.to_a)
    begin
      view.refresh
    rescue
    end
    ### FRONT [S] ---------------------------------------------------------
    Sketchup::set_status_text(gname+": Making Front View...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-FRONT"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,miny,minz],[maxx,miny,minz],[maxx,miny,maxz],[minx,miny,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="FRONT-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="FRONT-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].y.abs>0.9999 ### no horiz in Y
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.y=es.y+1
        ee.y=ee.y+1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, Y_AXIS.reverse]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, Y_AXIS.reverse)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, Y_AXIS.reverse)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="FRONT-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    fgp.erase!
    ###
    ### lay down
    tr=Geom::Transformation.rotation([min.x, min.y, 0], X_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### slide to axis
    tr=Geom::Transformation.translation([0, -min.y, -@gap])
    tents.transform_entities(tr, tents.to_a)
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("FRONT", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.translation([0, minz, 0])
    txtgp.transform!(tr)
    ### place
    tr=Geom::Transformation.translation([maxx-min.y+maxy-min.x, 0, 0])
    tents.transform_entities(tr, tents.to_a)
    begin
      view.refresh
    rescue
    end
    ### BACK [N] ---------------------------------------------------------
    Sketchup::set_status_text(gname+": Making Back View...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-BACK"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,maxy,minz],[maxx,maxy,minz],[maxx,maxy,maxz],[minx,maxy,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="BACK-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="BACK-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].y.abs>0.9999 ### no horiz in Y
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.y=es.y-1
        ee.y=ee.y-1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, Y_AXIS]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, Y_AXIS)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, Y_AXIS)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="BACK-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    fgp.erase!
    ###
    ### flip
    tr=Geom::Transformation.rotation([0,maxy,0], Z_AXIS, 180.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### lay down
    tr=Geom::Transformation.rotation([max.x, max.y, 0], X_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### slide to axis
    tr=Geom::Transformation.translation([0, -max.y, @gap])
    tents.transform_entities(tr, tents.to_a)
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("BACK", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.translation([-bbx, minz, 0])
    txtgp.transform!(tr)
    ### place
    tr=Geom::Transformation.translation([minx-maxy+min.y+min.x, 0, 0])
    tr=Geom::Transformation.translation([minx-maxy+min.y+min.x, 0, 0])
    tents.transform_entities(tr, tents.to_a)
    begin
      view.refresh
    rescue
    end
    ### RIGHT [E] ---------------------------------------------------------
    Sketchup::set_status_text(gname+": Making Right View...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-RIGHT"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([maxx,miny,minz],[maxx,maxy,minz],[maxx,maxy,maxz],[maxx,miny,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="RIGHT-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="RIGHT-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].x.abs>0.9999 ### no horiz in X
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.x=es.x-1
        ee.x=ee.x-1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, X_AXIS]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, X_AXIS)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, X_AXIS)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="RIGHT-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    fgp.erase!
    ###
    ### rotate 90
    tr=Geom::Transformation.rotation([maxx,0,0], Z_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### lay down
    tr=Geom::Transformation.rotation([maxx,0,0], X_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### slide to origin
    tr=Geom::Transformation.translation([-maxx, 0, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("RIGHT", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    tr=Geom::Transformation.translation([0, minz, 0])
    txtgp.transform!(tr)
    ### place
    tr=Geom::Transformation.translation([maxx-min.y, 0, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    begin
      view.refresh
    rescue
    end
    ### LEFT [W] ---------------------------------------------------------
    Sketchup::set_status_text(gname+": Making Left View...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-LEFT"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,miny,minz],[minx,maxy,minz],[minx,maxy,maxz],[minx,miny,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="LEFT-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="LEFT-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].x.abs>0.9999 ### no horiz in X
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.x=es.x+1
        ee.x=ee.x+1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, X_AXIS.reverse]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, X_AXIS.reverse)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, X_AXIS.reverse)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="LEFT-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    fgp.erase!
    ###
    ### rotate 90
    tr=Geom::Transformation.rotation([minx,0,0], Z_AXIS, 90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### lay down
    tr=Geom::Transformation.rotation([minx,0,0], X_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### slide to origin
    tr=Geom::Transformation.translation([-minx, 0, 0])
    tgp.transform!(tr)
    tgp.definition.invalidate_bounds
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("LEFT", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    #tr=Geom::Transformation.translation([min.y+txtgp.bounds.width, minz, 0])
    tr=Geom::Transformation.translation([-bby-@gap, minz, 0])
    txtgp.transform!(tr)
    ### place
    tr=Geom::Transformation.translation([minx+min.y, 0, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    begin
      view.refresh
    rescue
    end
    ###
    ###--------------------------------------------------------------------
    ### SECTIONS
    ### TOP >>> BOTTOM ----------------------------------------------------------------
    Sketchup::set_status_text(gname+": Making Section-Bottom...",SB_PROMPT)
    ###
    yup=maxz
    yupq=maxy-miny+maxy-miny+maxy
    yup=yupq if yup < yupq
    ###
    tgp=gents.add_group()
    tgp.name=@skadname+"-SECT-BOTTOM"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,miny,cenz],[maxx,miny,cenz],[maxx,maxy,cenz],[minx,maxy,cenz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="SECT-BOTTOM-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="SECT-BOTTOM-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].z.abs>0.9999 ### no verticals
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.z=es.z-1
        ee.z=ee.z-1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, Z_AXIS]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, Z_AXIS)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, Z_AXIS)
        end#until
        if cont
          ptsC << [pps, ppe] if ps.z<=cenz or pe.z<=cenz
        else
          ptsH << [pps, ppe] if ps.z<=cenz or pe.z<=cenz
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="SECT-BOTTOM-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.z>cenz
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.z>cenz
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.z>cenz
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges) 
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    ### ADD SECT CUT ------------------------------------------------------
    cgp=tents.add_group()
    cgp.name="SECT-BOTTOM-SECT"
    cgp.layer=layerSECT
    cents=cgp.entities
    tr=cgp.transformation
    ients.intersect_with(true, tr, cents, tr, true, [face])
    ###
    fgp.erase!
    ###
    ### drop to z=0
    tr=Geom::Transformation.translation([0, 0, -cenz])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("SECT-BOTTOM", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new([0, miny, 0])
    txtgp.transform!(tr)
    ### move up
    tr=Geom::Transformation.translation([0, yup-miny, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    ###
    begin
      view.refresh
    rescue
    end
    ###
    ### SECT BOTTOM > TOP -------------------------------------------------
    Sketchup::set_status_text(gname+": Making Section-Top...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-SECT-TOP"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,miny,cenz],[maxx,miny,cenz],[maxx,maxy,cenz],[minx,maxy,cenz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="SECT-TOP-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="SECT-TOP-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].z.abs>0.9999 ### no verticals
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.z=es.z+1
        ee.z=ee.z+1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, Z_AXIS.reverse]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, Z_AXIS.reverse)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, Z_AXIS.reverse)
        end#until
        if cont
          ptsC << [pps, ppe] if ps.z>=cenz or pe.z>=cenz
        else
          ptsH << [pps, ppe] if ps.z>=cenz or pe.z>=cenz
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="SECT-TOP-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.z<cenz
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.z<cenz
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.z.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Z_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.z<cenz
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    ### ADD SECT CUT ------------------------------------------------------
    cgp=tents.add_group()
    cgp.name="SECT-TOP-SECT"
    cgp.layer=layerSECT
    cents=cgp.entities
    tr=cgp.transformation
    ients.intersect_with(true, tr, cents, tr, true, [face])
    ###
    fgp.erase!
    ###
    ### drop to z=0
    tr=Geom::Transformation.translation([0, 0, -cenz])
    tents.transform_entities(tr, tents.to_a)
    ### flip
    tr=Geom::Transformation.rotation(ORIGIN, X_AXIS, 180.degrees)
    tents.transform_entities(tr, tents.to_a)
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("SECT-TOP", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new([0, miny, 0])
    txtgp.transform!(tr)
    ### place
    tr=Geom::Transformation.translation([0, yup-miny+maxy-miny, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    ###
    begin
      view.refresh
    rescue
    end
    ###
    ### SECTION FRONT [S] >> BACK ---------------------------------------------------------
    Sketchup::set_status_text(gname+": Making Section-Back...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"SECT-BACK"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,ceny,minz],[maxx,ceny,minz],[maxx,ceny,maxz],[minx,ceny,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="SECT-BACK-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="SECT-BACK-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].y.abs>0.9999 ### no horiz in Y
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.y=es.y+1
        ee.y=ee.y+1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, Y_AXIS.reverse]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, Y_AXIS.reverse)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, Y_AXIS.reverse)
        end#until
        if cont
          ptsC << [pps, ppe] if ps.y>=ceny or pe.y>=ceny
        else
          ptsH << [pps, ppe] if ps.y>=ceny or pe.y>=ceny
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="SECT-BACK-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.y<ceny
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.y<ceny
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.y<ceny
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    ### ADD SECT CUT ------------------------------------------------------
    cgp=tents.add_group()
    cgp.name="SECT-BACK-SECT"
    cgp.layer=layerSECT
    cents=cgp.entities
    tr=cgp.transformation
    ients.intersect_with(true, tr, cents, tr, true, [face])
    ###
    fgp.erase!
    ###
    ### shift to y=0
    tr=Geom::Transformation.translation([0, -ceny, -minz])
    tents.transform_entities(tr, tents.to_a)
    ### lay down
    tr=Geom::Transformation.rotation(ORIGIN, X_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("SECT-BACK", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.translation([0, minz, 0])
    tgp.transform!(tr)
    ### place
    tr=Geom::Transformation.translation([maxx-min.y+max.y-minx, yup-minz, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    begin
      view.refresh
    rescue
    end
    ###
    ### SECTION BACK [N] >> FRONT -----------------------------------------
    Sketchup::set_status_text(gname+": Making Section-Front...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"SECT-FRONT"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([minx,ceny,minz],[maxx,ceny,minz],[maxx,ceny,maxz],[minx,ceny,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="SECT-FRONT-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="SECT-FRONT-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].y.abs>0.9999 ### no horiz in Y
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.y=es.y-1
        ee.y=ee.y-1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, Y_AXIS]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, Y_AXIS)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, Y_AXIS)
        end#until
        if cont
          ptsC << [pps, ppe] if ps.y<=ceny or pe.y<=ceny
        else
          ptsH << [pps, ppe] if ps.y<=ceny or pe.y<=ceny
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="SECT-FRONT-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.y>ceny
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.y>ceny
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.y.abs>0.9999
      center=a.center
      rayt=model.raytest(center, Y_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.y>ceny
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(X_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(X_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
     ### ADD SECT CUT ------------------------------------------------------
    cgp=tents.add_group()
    cgp.name="SECT-LEFT-SECT"
    cgp.layer=layerSECT
    cents=cgp.entities
    tr=cgp.transformation
    ients.intersect_with(true, tr, cents, tr, true, [face])
    ###
    fgp.erase!
    ###
    ### move to origin
    tr=Geom::Transformation.translation([0, -ceny, 0])
    tents.transform_entities(tr, tents.to_a)
    ### lay down
    tr=Geom::Transformation.rotation(ORIGIN, X_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### flip
    tr=Geom::Transformation.rotation(ORIGIN, Y_AXIS, 180.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("SECT-FRONT", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    tr=Geom::Transformation.translation([-bbx, minz, 0])
    txtgp.transform!(tr)
    ### place
    tr=Geom::Transformation.translation([minx+min.y-maxy+min.x, yup-minz, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    begin
      view.refresh
    rescue
    end
    ###
    ### SECTION RIGHT [E] >> LEFT---------------------------------
    Sketchup::set_status_text(gname+": Making Section-Left...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"SECT-LEFT"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([cenx,miny,minz],[cenx,maxy,minz],[cenx,maxy,maxz],[cenx,miny,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="SECT-LEFT-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="SECT-LEFT-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].x.abs>0.9999 ### no horiz in X
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.x=es.x-1
        ee.x=ee.x-1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, X_AXIS]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, X_AXIS)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, X_AXIS)
        end#until
        if cont
          ptsC << [pps, ppe] if ps.x<=cenx or pe.x<=cenx
        else
          ptsH << [pps, ppe] if ps.x<=cenx or pe.x<=cenx
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="SECT-LEFT-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.x>cenx
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.x>cenx
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.x>cenx
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    ### ADD SECT CUT ------------------------------------------------------
    cgp=tents.add_group()
    cgp.name="SECT-LEFT-SECT"
    cgp.layer=layerSECT
    cents=cgp.entities
    tr=cgp.transformation
    ients.intersect_with(true, tr, cents, tr, true, [face])
    ###
    fgp.erase!
    ###
    ### move to x=0
    tr=Geom::Transformation.translation([-cenx, 0, 0])
    tents.transform_entities(tr, tents.to_a)
    ### rotate 90
    tr=Geom::Transformation.rotation(ORIGIN, Z_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### lay down
    tr=Geom::Transformation.rotation(ORIGIN, X_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("SECT-LEFT", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    tr=Geom::Transformation.new([0, minz, 0])
    txtgp.transform!(tr)
    ### to x=0 move to yup
    tgp.definition.invalidate_bounds
    tr=Geom::Transformation.translation([0, yup-minz, 0])
    tents.transform_entities(tr, tents.to_a)
    ### move over to right
    tr=Geom::Transformation.translation([maxx-min.y, 0, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    begin
      view.refresh
    rescue
    end
    ###
    ### SECTION LEFT [W] >> RIGHT------------------------------------------
    Sketchup::set_status_text(gname+": Making Right-Section...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"SECT-RIGHT"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    face=fents.add_face([cenx,miny,minz],[cenx,maxy,minz],[cenx,maxy,maxz],[cenx,miny,maxz])
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="SECT-RIGHT-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    gpHIDN=tents.add_group()
    gpHIDN.name="SECT-RIGHT-HIDN"
    gpHents=gpHIDN.entities
    gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].x.abs>0.9999 ### no horiz in X
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      es=e.start.position
      ee=e.end.position
      ### trap for smoothed etc
      if e.hidden? or e.smooth? or e.soft?
        es.x=es.x+1
        ee.x=ee.x+1
      end#if
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, X_AXIS.reverse]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, X_AXIS.reverse)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, X_AXIS.reverse)
        end#until
        if cont
          ptsC << [pps, ppe] if ps.x>=cenx or pe.x>=cenx
        else
          ptsH << [pps, ppe] if ps.x>=cenx or pe.x>=cenx
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ### sort out circles/arcs
    circs=[]
    arcs=[]
    ngons=[]
    edges.each{|e|
      next if not e.curve and not e.curve==Sketchup::ArcCurve
      if self.is_loop?(e.curve) ### circle or polygon
        begin
          if e.curve.is_polygon?
            ngons << e.curve if not ngons.include?(e.curve)
          else ### a circle
            circs << e.curve if not circs.include?(e.curve)
          end#if
        rescue #<v7.1
          circs << e.curve if not circs.include?(e.curve)
        end
      else ### it's an arc
        arcs << e.curve if not arcs.include?(e.curve)
      end#if
    }
    gpCIRC=tents.add_group()
    gpCIRC.name="SECT-RIGHT-CIRC"
    gpCIRC.layer=layerCIRC
    gpAents=gpCIRC.entities
    
    cpts=[]
    circs.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.x<cenx
      gpAents.add_circle(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    arcs.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.x<cenx
      gpAents.add_arc(center, a.xaxis, a.normal, a.radius, a.start_angle, a.end_angle, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    ngons.each{|a|
      next if not a.normal.x.abs>0.9999
      center=a.center
      rayt=model.raytest(center, X_AXIS.reverse)
      next if not rayt
      next if not rayt[1][-1]==face
      center=rayt[0]
      next if center.x<cenx
      gpAents.add_ngon(center, a.normal, a.radius, a.count_edges)
      cpts << gpAents.add_line(center,center.offset(Y_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Y_AXIS.reverse, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS, @cmk))
      cpts << gpAents.add_line(center,center.offset(Z_AXIS.reverse, @cmk))
    }
    cpts.compact.each{|e|e.layer=layerCPTS}
    ###
    ### ADD SECT CUT ------------------------------------------------------
    cgp=tents.add_group()
    cgp.name="SECT-RIGHT-SECT"
    cgp.layer=layerSECT
    cents=cgp.entities
    tr=cgp.transformation
    ients.intersect_with(true, tr, cents, tr, true, [face])
    ###
    fgp.erase!
    ###
    ### move to x=0
    tr=Geom::Transformation.translation([-cenx, 0, 0])
    tents.transform_entities(tr, tents.to_a)
    ### rotate 90
    tr=Geom::Transformation.rotation(ORIGIN, Z_AXIS, 90.degrees)
    tents.transform_entities(tr, tents.to_a)
    ### lay down
    tr=Geom::Transformation.rotation(ORIGIN, X_AXIS, -90.degrees)
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    ### text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("SECT-RIGHT", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    tr=Geom::Transformation.new([-bby, minz, 0])
    txtgp.transform!(tr)
    ### to left
    tr=Geom::Transformation.translation([minx+min.y, yup-minz, 0])
    tents.transform_entities(tr, tents.to_a)
    tgp.definition.invalidate_bounds
    begin
      view.refresh
    rescue
    end
    ###
    ### AXONOMETRICS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    ### AXO-SW
    Sketchup::set_status_text(gname+": Making Axo-SW...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-AXO-SW"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    diag=bb.diagonal*10
    face=fents.add_face([-diag,-diag,maxz],[diag,-diag,maxz],[diag,diag,maxz],[-diag,diag,maxz])
    verts=face.vertices
    corn=Geom::Point3d.new(minx-@gap,miny-@gap,maxz+@gap)
    ### rotate face so nearly 'axo'
    tr=Geom::Transformation.rotation(corn, X_AXIS, 45.0.degrees)
    fents.transform_entities(tr, verts)
    tr=Geom::Transformation.rotation(corn, Z_AXIS, -45.0.degrees)
    fents.transform_entities(tr, verts)
    ###
    face=nil
    fents.each{|e|face=e if e.class==Sketchup::Face}
    face.reverse! if face.normal.z<0
    vect=face.normal
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="AXO-SW-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    #gpHIDN=tents.add_group()
    #gpHIDN.name="AXO-SW-HIDN"
    #gpHents=gpHIDN.entities
    #gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].parallel?(vect) ### no 'perp' edges
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      ### trap for smoothed etc ?
      #next if e.hidden? or e.smooth? or e.soft?
      ###
      es=e.start.position
      ee=e.end.position
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, vect]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, vect)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, vect)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ###ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ###ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ###
    fgp.erase!
    ###
    ### rearrange so it's flat
    tr=Geom::Transformation.rotation(corn, Z_AXIS, 45.0.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    tr=Geom::Transformation.rotation(corn, X_AXIS, -45.0.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    ### scale in Y by sqrt2 so correct...
    tr=Geom::Transformation.scaling(corn, 1, Math.sqrt(2), 1)
    gpCents.transform_entities(tr, gpCents.to_a)
    ###
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ### move/place
    axoY=yup-minz+maxz+@gap-minz+maxz+@gap+@gap
    tr=Geom::Transformation.new([-gpCONT.bounds.max.x-(@tht), axoY, @gap-corn.z])
    tgp.transform!(tr) ### over to left of Yaxis
    gpCONT.definition.invalidate_bounds
    ### add text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("AXO-SW", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new(gpCONT.bounds.min.offset([0,-@gap,0]))
    txtgp.transform!(tr)
    tr=Geom::Transformation.translation([0, @gap, 0])
    tgp.transform!(tr)
    tgp.definition.invalidate_bounds
    ###
    axomin=tgp.bounds.min ### to use later
    ###
    begin
      view.refresh
    rescue
    end
    ###
    ### AXO-SE
    Sketchup::set_status_text(gname+": Making Axo-SE...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-AXO-SE"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    diag=bb.diagonal*10
    face=fents.add_face([-diag,-diag,maxz],[diag,-diag,maxz],[diag,diag,maxz],[-diag,diag,maxz])
    verts=face.vertices
    corn=Geom::Point3d.new(maxx+@gap,miny-@gap,maxz+@gap)
    ### rotate face so nearly 'axo'
    tr=Geom::Transformation.rotation(corn, X_AXIS, 45.0.degrees)
    fents.transform_entities(tr, verts)
    tr=Geom::Transformation.rotation(corn, Z_AXIS, 45.0.degrees)
    fents.transform_entities(tr, verts)
    ###
    face=nil
    fents.each{|e|face=e if e.class==Sketchup::Face}
    face.reverse! if face.normal.z<0
    vect=face.normal
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="AXO-SE-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    #gpHIDN=tents.add_group()
    #gpHIDN.name="AXO-SW-HIDN"
    #gpHents=gpHIDN.entities
    #gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].parallel?(vect) ### no 'perp' edges
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      ### trap for smoothed etc ?
      #next if e.hidden? or e.smooth? or e.soft?
      ###
      es=e.start.position
      ee=e.end.position
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, vect]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, vect)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, vect)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ###ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ###ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ###
    fgp.erase!
    ###
    ### rearrange so it's flat
    tr=Geom::Transformation.rotation(corn, Z_AXIS, -45.0.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    tr=Geom::Transformation.rotation(corn, X_AXIS, -45.0.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    ### scale in Y by sqrt2 so correct...
    tr=Geom::Transformation.scaling(corn, 1, Math.sqrt(2), 1)
    gpCents.transform_entities(tr, gpCents.to_a)
    ###
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ### move/place
    tr=Geom::Transformation.new([-gpCONT.bounds.min.x+(@tht), axoY, @gap-corn.z])
    tgp.transform!(tr) ### over to left of Yaxis
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ### add text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("AXO-SE", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new(gpCONT.bounds.min.offset([0,-@gap,0]))
    txtgp.transform!(tr)
    tr=Geom::Transformation.translation([0, axomin.y-tgp.bounds.min.y, 0])
    tgp.transform!(tr)
    tgp.definition.invalidate_bounds
    wid2=tgp.bounds.width
    begin
      view.refresh
    rescue
    end
    ###
    ### AXO-NW
    Sketchup::set_status_text(gname+": Making Axo-NW...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-AXO-NW"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    diag=bb.diagonal*10
    face=fents.add_face([-diag,-diag,maxz],[diag,-diag,maxz],[diag,diag,maxz],[-diag,diag,maxz])
    verts=face.vertices
    corn=Geom::Point3d.new(minx-@gap,maxy+@gap,maxz+@gap)
    ### rotate face so nearly 'axo'
    tr=Geom::Transformation.rotation(corn, X_AXIS, -45.0.degrees)
    fents.transform_entities(tr, verts)
    tr=Geom::Transformation.rotation(corn, Z_AXIS, 45.0.degrees)
    fents.transform_entities(tr, verts)
    ###
    face=nil
    fents.each{|e|face=e if e.class==Sketchup::Face}
    face.reverse! if face.normal.z<0
    vect=face.normal
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="AXO-NW-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    #gpHIDN=tents.add_group()
    #gpHIDN.name="AXO-SW-HIDN"
    #gpHents=gpHIDN.entities
    #gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].parallel?(vect) ### no 'perp' edges
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      ### trap for smoothed etc ?
      #next if e.hidden? or e.smooth? or e.soft?
      ###
      es=e.start.position
      ee=e.end.position
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, vect]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, vect)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, vect)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ###ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ###ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ###
    fgp.erase!
    ###
    ### rearrange so it's flat
    tr=Geom::Transformation.rotation(corn, Z_AXIS, -45.0.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    tr=Geom::Transformation.rotation(corn, X_AXIS, 45.0.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    ### scale in Y by sqrt2 so correct...
    tr=Geom::Transformation.scaling(corn, 1, Math.sqrt(2), 1)
    gpCents.transform_entities(tr, gpCents.to_a)
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ### flip
    tr=Geom::Transformation.rotation(gpCONT.bounds.center, Z_AXIS, 180.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ### move/place
    tr=Geom::Transformation.translation(gpCONT.bounds.min.vector_to(axomin))
    tgp.transform!(tr) ###
    tr=Geom::Transformation.translation([-gpCONT.bounds.width-@gap, @gap, 0])
    tgp.transform!(tr) ###
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ### add text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("AXO-NW", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new(gpCONT.bounds.min.offset([0,-@gap,0]))
    txtgp.transform!(tr)
    tgp.definition.invalidate_bounds
    begin
      view.refresh
    rescue
    ###
    end
    ###
    ### AXO-NE
    Sketchup::set_status_text(gname+": Making Axo-NE...",SB_PROMPT)
    tgp=gents.add_group()
    tgp.name=@skadname+"-AXO-NE"
    tents=tgp.entities
    fgp=tents.add_group()
    fents=fgp.entities
    diag=bb.diagonal*10
    face=fents.add_face([-diag,-diag,maxz],[diag,-diag,maxz],[diag,diag,maxz],[-diag,diag,maxz])
    verts=face.vertices
    corn=Geom::Point3d.new(maxx+@gap,maxy+@gap,maxz+@gap)
    ### rotate face so nearly 'axo'
    tr=Geom::Transformation.rotation(corn, X_AXIS, -45.0.degrees)
    fents.transform_entities(tr, verts)
    tr=Geom::Transformation.rotation(corn, Z_AXIS, -45.0.degrees)
    fents.transform_entities(tr, verts)
    ###
    face=nil
    fents.each{|e|face=e if e.class==Sketchup::Face}
    face.reverse! if face.normal.z<0
    vect=face.normal
    plane=face.plane
    gpCONT=tents.add_group()
    gpCONT.name="AXO-NE-CONT"
    gpCONT.layer=layerCONT
    gpCents=gpCONT.entities
    #gpHIDN=tents.add_group()
    #gpHIDN.name="AXO-SW-HIDN"
    #gpHents=gpHIDN.entities
    #gpHIDN.layer=layerHIDN
    edges=[]
    ients.each{|e|
      next if not e.class==Sketchup::Edge
      next if e.line[1].parallel?(vect) ### no 'perp' edges
      edges << e
    }
    all_edges=[]
    edges.each{|e|
      next if not e.valid?
      ### trap for smoothed etc ?
      #next if e.hidden? or e.smooth? or e.soft?
      ###
      es=e.start.position
      ee=e.end.position
      ###
      eline=[es, es.vector_to(ee)]
      ###
      pes=es.project_to_plane(plane)
      pee=ee.project_to_plane(plane)
      peline=[pes, pes.vector_to(pee)]
      epts=[[0.0, es.to_a]]
      (edges-[e]).each{|r|
        rs=r.start.position
        re=r.end.position
        rline=r.line
        prs=rs.project_to_plane(plane)
        pre=re.project_to_plane(plane)
        prline=[prs, prs.vector_to(pre)]
        begin
          pt=Geom.intersect_line_line(peline, prline)
        rescue
          next
        end
        next if not pt
        next if not self.between?(pt, pes,pee) or not self.between?(pt, prs,pre)
        pline=[pt, vect]
        begin
          pte=Geom.intersect_line_line(pline, eline)
        rescue
          next
        end
        next if not pte
        begin
          ptr=Geom.intersect_line_line(pline, rline)
        rescue
          next
        end
        next if not ptr
        epts << [es.distance(pte), pte.to_a] if pt.distance(pte) >= pt.distance(ptr)
      }
      epts << [e.length, ee.to_a]
      epts.uniq!
      epts.sort!
      all_edges << epts
    }
    ### process
    ptsC=[]
    ptsH=[]
    all_edges.each{|pts|
      0.upto(pts.length-2){|i|
        ps=pts[i][1]
        pe=pts[i+1][1]
        ps=Geom::Point3d.new(ps.x, ps.y, ps.z)
        pe=Geom::Point3d.new(pe.x, pe.y, pe.z)
        pps=ps.project_to_plane(plane)
        ppe=pe.project_to_plane(plane)
        pps=Geom::Point3d.new(pps.x, pps.y, pps.z)
        ppe=Geom::Point3d.new(ppe.x, ppe.y, ppe.z)
        next if ps==pe or pps==ppe
        prt=ps.offset(ps.vector_to(pe), ps.distance(pe)/2)
        rayt=model.raytest(prt, vect)
        next if not rayt ### should not happen
        if rayt[1][-1]==face
          cont=true
          rayt=nil
        else
          cont=false
        end#if
        until not rayt or rayt[1].include?(gp)
          cont=true if rayt[1][-1]==face
          prt=rayt[0] if rayt
          rayt=model.raytest(prt, vect)
        end#until
        if cont
          ptsC << [pps, ppe]
        else
          ###ptsH << [pps, ppe]
        end#if
      }
    }
    ptsC.each{|pts|gpCents.add_line(pts[0], pts[1])}
    ###ptsH.each{|pts|gpHents.add_line(pts[0], pts[1])}
    ###
    fgp.erase!
    ###
    ### rearrange so it's flat
    tr=Geom::Transformation.rotation(corn, Z_AXIS, 45.0.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    tr=Geom::Transformation.rotation(corn, X_AXIS, 45.0.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    ### scale in Y by sqrt2 so correct...
    tr=Geom::Transformation.scaling(corn, 1, Math.sqrt(2), 1)
    gpCents.transform_entities(tr, gpCents.to_a)
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ### flip
    tr=Geom::Transformation.rotation(gpCONT.bounds.center, Z_AXIS, 180.degrees)
    gpCents.transform_entities(tr, gpCents.to_a)
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ### move/place
    tr=Geom::Transformation.translation(tgp.bounds.min.vector_to(axomin))
    gpCents.transform_entities(tr, gpCents.to_a)
    wid=tgp.bounds.width
    tr=Geom::Transformation.translation([wid+@gap+wid2+@gap, @gap, 0])
    gpCents.transform_entities(tr, gpCents.to_a)
    gpCONT.definition.invalidate_bounds
    tgp.definition.invalidate_bounds
    ###
    ### add text
    txtgp=tents.add_group()
    txtgp.name="TEXT"
    txtents=txtgp.entities
    txtents.add_3d_text("AXO-NE", TextAlignLeft, "Arial", false, false, @tht, 0.0, 0, false, 0.0)
    txtents.each{|e|e.layer=layerTEXT}
    txtgp.layer=layerTEXT
    tr=Geom::Transformation.new(gpCONT.bounds.min.offset([0,-@gap,0]))
    txtgp.transform!(tr)
    tgp.definition.invalidate_bounds
    begin
      view.refresh
    rescue
    end
    ###
    ### add in exact copy of the instance at end --------------------------
    inst.erase!
    Sketchup::set_status_text(gname+": Adding Original...",SB_PROMPT)
    ins=gents.add_instance(defn, str)
    ovec=ins.transformation.origin.vector_to(ORIGIN)
    tr=Geom::Transformation.translation(ovec)
    ins.transform!(tr)
    ins.material=smat
    attrdicts.each{|attrdict|
      name=attrdict.name
      attrdict.each_pair{|key,value| ins.set_attribute(name, key, value) }
    } if attrdicts
    ### replace original
    nins=oents.add_instance(defn, str)
    nins.material=smat
    nins.layer=slay
    attrdicts.each{|attrdict|
      name=attrdict.name
      attrdict.each_pair{|key,value| nins.set_attribute(name, key, value) }
    } if attrdicts
    ###
    ### componentize container
    ninst=gp.to_component
    ninst.definition.name=gname
    dname=ninst.definition.name
    Sketchup::set_status_text(dname+": Done.",SB_PROMPT)
    ###
    model.commit_operation ################################################
    ###
    sleep(0.5)
    #Sketchup.send_action("selectSelectionTool:")
    ###
  end#def initialize
  
  def dialog()
    ### TO DO
    #return nil if not results
    return true
  end#def dialog
  
  def between?(pt, es, ee)
    len=es.distance(ee)
    return false if es.distance(pt) > len
    return false if ee.distance(pt) > len
    return true
  end#def on_edge?
  
  def is_loop?(arccurve)### circle OR polygon
    arccurve.vertices.each{|v|
      edgecount=0
      v.edges.each{|ee|edgecount+=1 if ee.curve==self}
      return false if edgecount<2
      ### vert can have >1 edge BUT it might belong to other curve etc
    }
    return true
  end#def

end#class SKAD
###

###
class Sketchup::Group
    # Sometimes 'group.entities.parent' refers to the wrong definition. 
    # This method checks for this error & finds the correct definition.
    if not Sketchup::Group.method_defined?(:definition)
       def definition()
          if self.entities.parent.instances.include?(self)
             return self.entities.parent
          else
             Sketchup.active_model.definitions.each { |definition|
                return definition if definition.instances.include?(self)
             }
          end
          return nil # Should not happen.
       end
    end#if
end#class Group
###

###
def cadup()
  SKAD.new()
end#if
def skad()
  SKAD.new()
end#if
###

### Menu ###------------------------------------------------------------
unless file_loaded?(File.basename(__FILE__))
  UI.menu("Tools").add_item("CADup"){SKAD.new()}
end#if
file_loaded(File.basename(__FILE__))
###
