### Circle Tool
#
module Tools2D
class CircleTool2D

def db(string)
  dir=File.dirname(__FILE__) ### adjust folder to suit tool
  toolname="2Dtools"  ### adjust xxx to suit tool...
  locale=Sketchup.get_locale.upcase
  path=File.join(dir, toolname+locale+".lingvo")
  unless File.exist?(path)
     return string
  else
    deBabelizer(string,path)
  end 
end#def

def getExtents
    bbox=Sketchup.active_model.bounds
    bbox.add(@ip.position)if @ip and @ip.valid?
    bbox.add(@ip1.position)if @ip1 and @ip1.valid?
    bbox.add(@ip2.position)if @ip2 and @ip2.valid?
    bbox.add(@ip3.position)if @ip3 and @ip3.valid?
    return bbox
end

@@cursor=nil
def initialize()
    @ip1 = nil
    @ip2 = nil
    @ip3 = nil
    @ip = nil
    @points=[]
    @xdown = 0
    @ydown = 0
    @numsegs = 18 if !@numsegs
	@@cursor=nil
    curpath=File.join(File.dirname(__FILE__), "Icons", "2Dcircle_cursor.png")
    @@cursor=UI::create_cursor(curpath, 0, 31) if File.exist?(curpath)
end

def activate
    @ctrl=false
    @ctrlmsg=db(" [Center+Radius, Ctrl=3-point, Alt=2-point]")
    @alt=false
    @altmsg=""
    @ip1 = Sketchup::InputPoint.new
    @ip2 = Sketchup::InputPoint.new
    @ip3 = Sketchup::InputPoint.new
    @ip = Sketchup::InputPoint.new
    @points=[]
    @drawn = false
    Sketchup::set_status_text((db("NNs or Radius")), SB_VCB_LABEL)
    self.reset(nil)
end

def deactivate(view)
    view.invalidate if @drawn
    Sketchup::set_status_text("",SB_PROMPT)
    Sketchup::set_status_text("",SB_VCB_LABEL)
    Sketchup::set_status_text("",SB_VCB_VALUE)
end

def onSetCursor()
    #return nil if RUBY_PLATFORM =~ /darwin/
	UI::set_cursor(@@cursor)if @@cursor
end

def onMouseMove(flags, x, y, view)
    @ip.pick view, x, y
    if @state==0
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Center"))+@ctrlmsg+@altmsg, SB_PROMPT)if not @ctrl and not @alt
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick First Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)if @ctrl
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Start of Diameter"))+@ctrlmsg+@altmsg, SB_PROMPT)if @alt
        if @ip != @ip1
            view.invalidate if @ip.display? or @ip1.display?
            @ip1.copy! @ip            
            view.tooltip = @ip1.tooltip
        end
    elsif @state==1
        @ip.pick view, x, y, @ip1
        if @ip != @ip2
            view.invalidate if @ip.display? or @ip1.display?
            @ip2.copy! @ip            
            view.tooltip = @ip2.tooltip
        end
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Point on Circumference, or Enter Radius"))+@ctrlmsg+@altmsg, SB_PROMPT)if not @ctrl and not @alt
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Second Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)if @ctrl
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Third Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)if @ctrl and @points.length==2
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Other End of Diameter"))+@ctrlmsg+@altmsg, SB_PROMPT)if @alt
        view.tooltip = @ip2.tooltip if @ip2.valid?
        view.invalidate
        if @ip2.valid?
            p1=@ip1.position;p1.z=@z
            p2=@ip2.position;p2.z=@z
            length = p1.distance(p2)
            if @alt
              Sketchup::set_status_text((db("NNs or Diameter")),SB_VCB_LABEL)
              Sketchup::set_status_text(length.to_s, SB_VCB_VALUE)
            else
              Sketchup::set_status_text((db("NNs or Radius")),SB_VCB_LABEL)
              Sketchup::set_status_text(length.to_s, SB_VCB_VALUE)
            end#if
            if @ctrl
              Sketchup::set_status_text((db("NNs")),SB_VCB_LABEL)
              Sketchup::set_status_text("", SB_VCB_VALUE)
            end#if
        end        
        if (x-@xdown).abs > 10 || (y-@ydown).abs > 10
            @dragging = true
        end
    else ###state==2  ==@ctrl
        if @ip != @ip3
            view.invalidate if @ip.display? or @ip1.display?
            @ip3.copy! @ip            
            view.tooltip = @ip3.tooltip
        end
        view.tooltip = @ip3.tooltip if @ip3.valid?
        view.invalidate
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Third Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)
        if (x-@xdown).abs > 10 || (y-@ydown).abs > 10
            @dragging = true
        end
    end
end

def onLButtonDown(flags, x, y, view)
    if @state==0
        @ip1.pick view, x, y
        if @ip1.valid?
            Sketchup.active_model.start_operation(db("2D Circle"))
            @state=1
            Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Point on Circumference, or Enter Radius"))+@ctrlmsg+@altmsg, SB_PROMPT)if not @ctrl and not @alt
            Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Second Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)if @ctrl
            Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Other End of Diameter, or Enter Diameter"))+@ctrlmsg+@altmsg, SB_PROMPT)if @alt
            @xdown = x
            @ydown = y
            p1=@ip1.position; p1.z=@z
            @points<<p1
        end
    elsif @state>=1
        if @ip2.valid?
          p2=@ip2.position; p2.z=@z
          @points<<p2
          if not @ctrl ### 2pt or ct+radius
            self.create_geometry(@points,view)
            self.reset(view)
          end#if
        end
        if @ctrl and @points.length==3 ### 3-point @ctrl
          self.create_geometry(@points,view)
          self.reset(view)
        end#if
        Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Third Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)if @ctrl and @points.length==2
    end
    view.lock_inference
end

def onLButtonUp(flags, x, y, view)
   ###
end

def onKeyDown(key, repeat, flags, view)
    if key == CONSTRAIN_MODIFIER_KEY && repeat == 1
        @shift_down_time = Time.now      
        if view.inference_locked?
            view.lock_inference
        elsif @state==0 && @ip1.valid?
            view.lock_inference @ip1
        elsif @state==1 && @ip2.valid?
            view.lock_inference @ip2, @ip1
        else ### ctrl ==3point
            view.lock_inference @ip3, @ip2
        end
    end
    if key==VK_CONTROL || key==VK_COMMAND  ### Ctrl toggles center+radius / 3-point
      if @ctrl
        @ctrl=false; @ctrlmsg=db(" [Center+Radius, Ctrl=3-point, Alt=2-point]")
        @alt=false; @altmsg=""
      else
        @ctrl=true; @ctrlmsg=db(" [3-point, Ctrl=Center+Radius, Alt=2-point]")
        @alt=false; @altmsg=""
      end#if
      self.reset(view)
    end#if
    if key==VK_ALT  ### Alt toggles center+radius / 2-point/diameter
      if @alt
        @alt=false; @altmsg=db(" [Center+Radius, Ctrl=3-point, Alt=2-point]")
        @ctrl=false; @ctrlmsg=""
      else
        @alt=true; @altmsg=db(" [2-point/diameter, Ctrl=Center+Radius, Alt=Center+Radius]")
        @ctrl=false; @ctrlmsg=""
      end#if
      self.reset(view)
    end#if
end

def onKeyUp(key, repeat, flags, view)
    if key == CONSTRAIN_MODIFIER_KEY && view.inference_locked? && (Time.now - @shift_down_time) > 0.5
        view.lock_inference
    end
end

def enableVCB?
   return true
end

def onUserText(text, view)
    if text.split('').last=="s"
      @numsegs=(text[0..-2]).to_i
      ###puts "Numsegs reset to #{@numsegs}"
      return nil
    end#if    
    return if not @state>=1
    return if not @ip2.valid?
    begin
        value = text.to_l
    rescue
        UI.beep
        puts (db("Cannot convert "))+text+(db(" to a Length"))
        value = nil
        Sketchup::set_status_text("", SB_VCB_VALUE)
    end
    return if !value
    pt1 = @ip1.position
    vec = @ip2.position - pt1
    if( vec.length == 0.0 )
        UI.beep
        return nil
    end
    vec.length = value
    pt2 = pt1 + vec
    @points=[pt1,pt2]
    if not @ctrl ###???
      self.create_geometry(@points, view)
      self.reset(view)
    end#if
end

def draw(view)
    view.guess_target
    if @ip1.valid?
        if @ip1.display?
            @ip1.draw(view)
            @drawn = true
        end
        if @ip2.valid?
            @ip2.draw(view) if @ip2.display?
            view.set_color_from_line(@ip1,@ip)
            p1=@ip1.position;p1.z=@z
            p2=@ip2.position;p2.z=@z
            if @ctrl and @points[1]
              self.draw_geometry(@points+[p2],view)
            else
              self.draw_geometry([p1,p2],view)
            end#if
            @drawn = true
        end
    end
end

def onCancel(flag, view)
    self.reset(view)
end

def reset(view)
    ### get/set reference plane 'z'
    @z=Sketchup.active_model.get_attribute("2Dtools","z",nil)
    Sketchup.active_model.set_attribute("2Dtools","z",0.0.mm)if not @z
    @z=Sketchup.active_model.get_attribute("2Dtools","z",nil)
    @zmsg=" [ Z="+@z.to_s+" ] "
    ###
    @state=0
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Center"))+@ctrlmsg+@altmsg, SB_PROMPT)if not @ctrl and not @alt
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick First Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)if @ctrl
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Start of Diameter"))+@ctrlmsg+@altmsg, SB_PROMPT)if @alt
    @ip.clear
    @ip1.clear
    @ip2.clear
    @ip3.clear
    @points=[]
    if view
        view.tooltip=nil
        view.invalidate # if @drawn
    end
    @drawn = false
    @dragging = false
end

def resume(view)
  view.invalidate
  if @state==0
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Center"))+@ctrlmsg+@altmsg, SB_PROMPT)if not @ctrl and not @alt
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick First Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)if @ctrl
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Start of Diameter"))+@ctrlmsg+@altmsg, SB_PROMPT)if @alt
  elsif @state==1
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Point on Circumference, or Enter Radius"))+@ctrlmsg+@altmsg, SB_PROMPT)if not @ctrl and not @alt
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Second Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)if @ctrl
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Other End of Diameter, or Enter Diameter"))+@ctrlmsg+@altmsg, SB_PROMPT)if @alt
  else
    Sketchup::set_status_text((db("2D Circle:"))+@zmsg+(db(" Pick Third Point on Circumference"))+@ctrlmsg+@altmsg, SB_PROMPT)
  end#if
end

def create_geometry(pts,view)
    p1=pts[0]###
    p2=pts[1]###
    p3=pts[2]###
  if not @ctrl and not @alt ### center+radius
    radius=p1.distance(p2)
    center=p1
    gp=view.model.active_entities.add_group()
    circ=gp.entities.add_circle(center,[0,0,1],radius,@numsegs)
    pt=circ[0].start.position
    ###
    angle=(p2-center).angle_between(pt-center) if p2
    angle=360.degrees-angle if p2.y>pt.y if p2
    tr=Geom::Transformation.rotation(center,[0,0,1],-angle) if p2
    gp.transform!(tr)### turn Polygon so vertex at p2 ?
    gp.explode
    view.model.active_entities.add_cpoint(center)
    ###############################
  elsif @ctrl ### 3point
    midpoint1 = p1.offset((p1.vector_to(p2)),(p1.distance(p2))/2)
    ### Get midpoints of lines 
    midpoint2 = p1.offset((p1.vector_to(p3)),(p1.distance(p3))/2) 
    perpendicular_vector = (p1.vector_to(p2)).normalize.cross((p1.vector_to(p3)).normalize)  
    perpendicular_vector1 = (p1.vector_to(p2)).cross((p1 + perpendicular_vector).vector_to(p2 - perpendicular_vector)) 
    perpendicular_vector2 = (p1.vector_to(p3)).cross((p1 + perpendicular_vector).vector_to(p3 - perpendicular_vector)) 
    center = Geom.intersect_line_line([midpoint1,perpendicular_vector1],[midpoint2,perpendicular_vector2])  
    ### Draw the circle
    gp=view.model.active_entities.add_group()
    circ=gp.entities.add_circle(center,perpendicular_vector,p1.distance(center),@numsegs)
    pt=circ[0].start.position
    ###
    angle=(p2-center).angle_between(pt-center)
    angle=360.degrees-angle if p2.y>pt.y
    tr=Geom::Transformation.rotation(center,[0,0,1],-angle)
    gp.transform!(tr)### turn Polygon so vertex at p2 ?
    gp.explode
    view.model.active_entities.add_cpoint(center)
    #################################
  elsif @alt ### diameter
    radius=(p1.distance(p2))/2
    center=p1.offset(p2-p1,radius)
    gp=view.model.active_entities.add_group()
    circ=gp.entities.add_circle(center,[0,0,1],radius,@numsegs)
    pt=circ[0].start.position
    angle=(p2-center).angle_between(pt-center) if p2
    angle=360.degrees-angle if p2.y>pt.y if p2
    tr=Geom::Transformation.rotation(center,[0,0,1],-angle) if p2
    gp.transform!(tr)### turn Polygon so vertex at p2 ?
    gp.explode
    view.model.active_entities.add_cpoint(center)
  end#if
  ###
  view.model.commit_operation
  ###
end#creategeom

def draw_geometry(pts,view)
    p1=pts[0]###
    p2=pts[1]###
    p3=pts[2]###
  if not @ctrl and not @alt ### center+radius
    gp=view.model.active_entities.add_group()
    radius=p1.distance(p2)if p2
    center=p1
    view.draw_points([p1,p2],5,5,"blue")if p2### show center & pt
    view.line_stipple="-"
    view.set_color_from_line(@ip1,@ip)
    view.draw_line(p1,p2)if p2
    view.line_stipple=""
    view.drawing_color = "black"
    circ=gp.entities.add_circle(center,[0,0,1],radius,@numsegs)if p2
    pt=circ[0].start.position if p2
    ### if pt
    angle=(p2-center).angle_between(pt-center) if p2
    angle=360.degrees-angle if p2.y>pt.y if p2
    tr=Geom::Transformation.rotation(center,[0,0,1],-angle) if p2
    gp.transform!(tr) if p2### turn Polygon so vertex at p2 ?
    curve=gp.entities[0].curve if p2
    points=[]; curve.vertices.each{|v|points<<v.position.transform!(gp.transformation)}if p2
    gp.erase! if gp.valid?
    view.draw_polyline(points)if points[1]
  elsif @ctrl ### 3-point #####################################
    ################
    view.draw_points(pts, 5, 5, "blue") if pts[0]
    view.line_stipple="-"
    view.drawing_color = "blue"    
    view.set_color_from_line(@ip1,@ip)
    view.draw_polyline(pts+[pts[0]])if pts[1]### triangle of lines
  ### Add ghost-circle
if @state>=1
 begin
    view.line_stipple=""
    view.drawing_color = "black"
    view.set_color_from_line(@ip1,@ip)    
    midpoint1 = p1.offset((p1.vector_to(p2)),(p1.distance(p2))/2)
    ### Get midpoints of lines. 
  midpoint2 = p1.offset((p1.vector_to(p3)),(p1.distance(p3))/2)
  perpendicular_vector = (p1.vector_to(p2)).normalize.cross((p1.vector_to(p3)).normalize)  
  perpendicular_vector1 = (p1.vector_to(p2)).cross((p1 + perpendicular_vector).vector_to(p2 - perpendicular_vector)) 
  perpendicular_vector2 = (p1.vector_to(p3)).cross((p1 + perpendicular_vector).vector_to(p3 - perpendicular_vector)) 
  center = Geom.intersect_line_line([midpoint1,perpendicular_vector1],[midpoint2,perpendicular_vector2])  
  # Draw the ghost-circle
  gp=Sketchup.active_model.active_entities.add_group()
  circ=gp.entities.add_circle(center,perpendicular_vector,p1.distance(center),@numsegs)
  pt=circ[0].start.position if p1!=p2
  ### if pt
    angle=(p2-center).angle_between(pt-center) if p2
    angle=360.degrees-angle if p2.y>pt.y if p2
    tr=Geom::Transformation.rotation(center,[0,0,1],-angle) if p2
    gp.transform!(tr) if p2### turn Polygon so vertex at p2 ?
  verts=gp.entities[0].curve.vertices
  points=[];verts.each{|v|points<<v.position.transform!(gp.transformation)}
  gp.erase! if gp.valid?
  view.draw_polyline(points)
  view.draw_points([center], 5, 5, "blue")
 rescue
  ###
 end#begin
end#if p2
    ###
    @drawn = true
    ##############
  elsif @alt ### diameter ###################################
    gp=view.model.active_entities.add_group()
    radius=(p1.distance(p2))/2 if p1!=p2
    center=p1.offset((p2-p1),radius)if p1!=p2
    view.draw_points([p1,p2,center],5,5,"blue")### show pts and center 
    view.line_stipple="-"
    view.set_color_from_line(@ip1,@ip)
    view.draw_line(p1,p2)if p1!=p2
    view.line_stipple=""
    view.drawing_color = "black"
    circ=gp.entities.add_circle(center,[0,0,1],radius,@numsegs)if p1!=p2
    pt=circ[0].start.position if p1!=p2
    ### if pt
    angle=(p2-center).angle_between(pt-center) if p2
    angle=360.degrees-angle if p2.y>pt.y if p2
    tr=Geom::Transformation.rotation(center,[0,0,1],-angle) if p2
    gp.transform!(tr) if p2### turn Polygon so vertex at p2 ?
    curve=gp.entities[0].curve if p1!=p2
    points=[]; curve.vertices.each{|v|points<<v.position.transform!(gp.transformation)}if p1!=p2
    gp.erase! if gp.valid? 
    view.draw_polyline(points)if points[1]
  end#if
    ###
end#drawgeom

end # class

end#mod
#-----------------------------------------------------------------------------
# shortcut
#def circletool2D
    #Sketchup.active_model.select_tool CircleTool2D.new
#end
######-----------------------------------------------
