=begin
TIG (c) 2012
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.
###
Arc-offset_true.rb
###
Usage:
Adds a new 'Tool' menu item 'Arc_Offset_True'.
Adds a new context-menu item 'Arc_Offset_True' if a single Arc is selected.
Enter the required +ve/-ve offset distance in the dialog.
Enter the required number of copies [if it's -ve and would zero/flip the 
copies its curtailed and a closing dialog tells you].
It works on Arcs or Circles.
Unlike the native Offset tool all offset-arcs are always made as 'Arcs' - 
whether they are faced/not-faced, or intersect with other geometry.
###
Donations:
By PayPal.com to info @ revitrev.org
###
Version:
1.0 20120403 First issue.
1.1 20120403 Now accommodates trimmed first/last segments properly, also 
traps for -ve offsets that would 'zero' or 'flip' the offset-arc, the 
selection now passes to the new offset-arc.
1.2 20120403 Now has optional 'Number' in dialog to make arrayed offsets.
Context-menu option added.
1.3 20120403 Multiple offsets will now intersect with other geometry only 
AFTER they have ALL been formed.
The native Offset tool's offset-arcs that are intersected become Curves, 
but this tool will make them as Arcs [albeit 'split'].
Offset-arcs made from an Arc that bounds a face will become Curves in the 
native Offset tool; this tool produces similar results.
1.4 20120403 With the native Offset tool offset-arcs made from an Arc that 
bounds a face will become Curves; however, this tool makes them as Arcs.
1.5 20120402 Minor code tweak [you'd probably not notice - I will].
###
=end
require 'sketchup.rb'
###
module Arc_Offset_True
  ###
  unless file_loaded?(File.basename(__FILE__))
    UI.menu("Tools").add_item("Arc_Offset_True"){self.new()}
    UI.add_context_menu_handler{|menu|
      menu.add_item("Arc_Offset_True"){self.new()} if self.ok()
    }
  end
  file_loaded(File.basename(__FILE__))
  ###
  def self.ok()
    ss = Sketchup.active_model.selection
    if ss[0].class==Sketchup::Edge and ss[0].curve and ss[0].curve.typename=="ArcCurve"
      return true
    else
      return false
    end
  end
  ###
  def self.new()
    model = Sketchup.active_model
    ss = model.selection
    if self.ok()
      arc = ss[0].curve
    else
      UI.messagebox("Arc_Offset_True:\n\nSelect ONE Arc before activating this tool.")
      return nil
    end
    @dist = 0.mm unless @dist
    @numr = 1 unless @numr
    results=inputbox(["Distance: ","Number: "],[@dist,@numr],"Arc_Offset_True")
    return nil unless results ### canceled
    if results[0]==0
      UI.messagebox("Arc_Offset_True:\n\nOffset distance cannot be ZERO !\n\nEnter a +ve, OR -ve, value.")
      self.new()
      return nil
    end
    if results[0]<0 and results[0].abs>=arc.radius
      UI.messagebox("Arc_Offset_True:\n\nA -ve offset cannot be >= the Arc's radius !\n\nEnter a new value.")
      self.new()
      return nil
    end
    if results[1]<=0
      UI.messagebox("Arc_Offset_True:\n\nNumber cannot be <= ZERO !\n\nEnter a +ve number.")
      self.new()
      return nil
    end
    @dist,@numr = results
    model.start_operation("Arc_Offset_True [#{@dist}]")
    cen=arc.center
    rad0=arc.radius
    rad=rad0
    fac=arc.edges[0].faces[0]
    pts=[]; arc.vertices.each{|v| pts << v.position } if fac
    ents=model.active_entities
    #tgp=ents.add_group(arc.edges)
    ags=arc.edges
    all=ags+ags[0].faces
    all.flatten.uniq!
    tcp=ents.add_group(all)
    tr=tcp.transformation
    tgp=ents.add_instance(tcp.entities.parent, tr)
    tgp.explode
    if fac and pts[2]
      eds=tcp.entities.to_a.each{|e|e.class==Sketchup::Edge}
      togos=[]
      eds.each{|e|togos << e unless ags.include?(e)}
      tcp.entities.erase_entities(togos)
    end
    gps=[]
    brk=nil
    (@numr-1).times{ents.add_instance(tcp.entities.parent, tcp.transformation)}
    is=tcp.entities.parent.instances
    is.each_with_index{|e,i|
      rad=rad+@dist
      trs=Geom::Transformation.scaling(cen, rad/rad0)
      e.transform!(trs)
      if rad+@dist<=0
        ents.erase_entities(is[i+1..-1])
        brk=@numr-(i+1)
        break
      end
    }
    es=tcp.entities.parent.instances
    eds=es[-1].entities.to_a if es[-1] and es[-1].valid?
    is.each{|i|i.explode if i.valid?}
    ss.clear
    ss.add(eds) if eds[0]
    if brk
      UI.messagebox("Arc_Offset_True:\n\n#{brk} of #{@numr} Negatively Offset Copies were NOT made,\nbecause they would have either been 0 radius or 'flipped' !")
    end
    model.commit_operation
  end
end
###