###############################################################################
#       SCRIPT NAME : Chamfer_Along_Path.rb
#
#       AUTHOR : Ashley Joyce (c) 2006  Version: 1.0
#
#       LICENSING: Smustard.com™ Ruby Script End User License Agreement
#
#       Based on ExtrudeAlongPath.rb written by Tig which itself was based on
#		original wall making idea by Didier Bur and using some vertex array
#		ideas from Rick Wilson's Weld.rb
#
#       USAGE :
#		Select joined lines, arcs, circles, curves, etc.
#		Select "Chamfer Along Path" from the Tool menu.
#
#       This tool differs from ExtrudeAlong Path in that the extrude face is
#       a triangular shape with a specified width and height. The Triangular
#       face is referenced from the edge. Branching paths will not
#       extrude.
#
#       The only tricky bit about this tool is knowing that (+) positive and
#       (-) negative values for both width and height parameters change the
#       orientation of the triangular face.
#
#       This means you can create (4) different orientations by changing
#       the Height and Width Settings using (+) positive & (-) negative values
#
#       TUTORIAL & UPGRADES:
#
#       FOR GRAPHICAL TUTORIALS ON USING THE CHAMFER ALONG PATH TOOL AND FUTURE
#       UPGRADES PLEASE VISIT  WWW.SMUSTARD.COM
#
#       Email: ashley@bowin.com.au
#
#
###############################################################################
###############################################################################
require 'sketchup.rb'
###############################################################################

def chamfer_along_path

@error=0

model = Sketchup.active_model
entities = model.active_entities
ss = model.selection

### show VCB and status info
Sketchup::set_status_text("Chamfer Along Path...ENTER PARAMETERS...", SB_PROMPT)
Sketchup::set_status_text(" ", SB_VCB_LABEL)
Sketchup::set_status_text(" ", SB_VCB_VALUE)
###
if ss.empty?
  Sketchup::set_status_text("Chamfer Along Path... NO SELECTION ! ", SB_PROMPT)
  UI.messagebox("No Selection to Chamfer.")
  return nil
end
###############################################################

def get_vertices

###############################################################
### this next bit is mainly thanks to Rick Wilson's weld.rb
### & Tig's ExtrudeAlongPath.rb
###############################################################

	model=Sketchup.active_model
	ents=model.active_entities
	@sel=model.selection
	sl=@sel.length
	verts=[]
	edges=[]
	@newVerts=[]
	startEdge=startVert=nil

#DELETE NON-EDGES, GET THE VERTICES

	@sel.each {|item| edges.push(item) if item.typename=="Edge"}
	edges.each {|edge| verts.push(edge.vertices)}
	verts.flatten!

#FIND AN END VERTEX

	vertsShort=[]
	vertsLong=[]
	vertsEnds=[] ### 17/8/5 ### to ensure array is only ends ###
	verts.each do |v|
		if vertsLong.include?(v)
			vertsShort.push(v)
		else
			vertsLong.push(v)
		end
	end
	vertsLong.each do |v| ### 17/8/5 ### to ensure array is only ends ###
		if not vertsShort.include?(v)
			vertsEnds.push(v)
		end
	end ### 17/8/5 ### to ensure array is only ends ###
	if vertsEnds.length==0 ### i.e. it's looped ###
 		### path start or end ? ###
		if @theEnd==0
		  startVert=vertsLong.first
		  startEdge=startVert.edges.first
		else
		  startVert=vertsLong.last
		  startEdge=startVert.edges.first
		end
		###
		closed=true
	else
		if vertsEnds.length != 2
			Sketchup::set_status_text("Chamfer Along Path... PATH ERROR ! ", SB_PROMPT)
			UI.messagebox("The selected Path either branches or is not continuous ! \nCannot make a Chamfer ! \nRe-select a single continuous path... ") ### 17/8/5 ###
			@error=1
			return nil
		else
			### path start or end ?
			if @theEnd==0
			  startVert=vertsEnds.first
			else
			  startVert=vertsEnds.last
			end
			###
			closed=false
			startEdge=startVert.edges.first
		end
	end
	@sel.clear


#SORT VERTICES, LIMITING TO THOSE IN THE SELECTION SET

	if startVert==startEdge.start
		@newVerts=[startVert]
		counter=0
		while @newVerts.length < verts.length
			edges.each do |edge|
				if edge.end==@newVerts.last
					@newVerts.push(edge.start)
				elsif edge.start==@newVerts.last
					@newVerts.push(edge.end)
				end
			end
			counter+=1
			if counter > verts.length
				Sketchup::set_status_text("Chamfer Along Path... ERROR ! ", SB_PROMPT)
				return nil if UI.messagebox("There seems to be a problem. Try again?", MB_YESNO)!=6
				@newVerts.reverse!
				reversed=true
			end
		end
	else
		@newVerts=[startVert]
		counter=0
		while @newVerts.length < verts.length
			edges.each do |edge|
				if edge.end==@newVerts.last
					@newVerts.push(edge.start)
				elsif edge.start==@newVerts.last
					@newVerts.push(edge.end)
				end
			end
			counter+=1
			if counter > verts.length
				Sketchup::set_status_text("Chamfer Along Path... ERROR ! ", SB_PROMPT)
				return nil if UI.messagebox("There seems to be a problem. Try again?", MB_YESNO)!=6
				@newVerts.reverse!
				reversed=true
			end
		end
	end
	@newVerts.reverse! if reversed

#CONVERT VERTICES TO POINT3Ds

	@newVerts.collect!{|x| x.position}

### now have an array of vertices in order with NO forced closed loop ...

end ### get_vertices

@theEnd=0
get_vertices
if @error==1
  return nil
end

### Input Parameters ################################################
#####################################################################

prompts = ["Width: ","Height: "]

if not $widthIn
   values = [-10.mm,-10.mm]
else
   values = [$widthIn,$heightIn]
end

results = inputbox prompts, values,"Chamfer Parameters (mm)"

return nil if not results ### i.e. the user cancelled the operation

$widthIn,$heightIn = results

###################################################################
### this next bit is mainly thanks to Tig's ExtrudeAlongPath.rb ###
###################################################################

pt1 = @newVerts[0]
pt2 = @newVerts[1]

width = $widthIn
if $widthIn == 0.mm ### can't be 0 ###
   $widthIn = -10.mm
   UI.messagebox("Zero Width NOT allowed ! ")
   return nil
end
###
if $heightIn == 0.mm ### can't be 0 ###
   $heightIn = -10.mm
   UI.messagebox("Zero Height NOT allowed ! ")
   return nil
end
###
if (pt1.x == pt2.x) and (pt1.y == pt2.y) ### vertical 1st path ###
   vflag = 1
   height = $heightIn
else
   vflag = 0
   height = (($heightIn * (pt1.distance pt2)) / (pt1.distance [pt2.x,pt2.y,pt1.z]))
end

   offL = width
   offR = 0
   heightUp = height
   heightDn = 0

if vflag == 1 ###
  vec = pt1.vector_to [(pt1.x + 1), pt1.y, pt1.z]
else
  vec = pt1.vector_to [pt2.x, pt2.y, pt1.z]
end


piBy2 = 1.5707963267948965 ### a radian right-angle for calculating vector offset to edges

rotated_vecL = vec.transform(Geom::Transformation.rotation(pt1, [0,0,1], (0 + piBy2)))
pt1_leftC = pt1.offset(rotated_vecL, offL)
rotated_vecR = vec.transform(Geom::Transformation.rotation(pt1, [0,0,1], (0 - piBy2)))
pt1_rightC = pt1.offset(rotated_vecR, offR)

if vflag == 1 ### 1st path is vertical
  pt1_left  = pt1_leftC.offset([-1,0,0], heightDn)
  pt1_right = pt1_rightC.offset([-1,0,0], heightDn)
  pt2_left  = pt1_leftC.offset([1,0,0], heightUp)
  pt2_right = pt1_rightC.offset([1,0,0], heightUp)
else
  pt1_left  = pt1_leftC.offset([0,0,-1], heightDn)
  pt1_right = pt1_rightC.offset([0,0,-1], heightDn)
  pt2_left  = pt1_leftC.offset([0,0,1], heightUp)
  pt2_right = pt1_rightC.offset([0,0,1], heightUp)
end

ents=entities
##############################################
model.start_operation "MakeChamberface"
##############################################
  theChamberFace = ents.add_face(pt1_left,pt1_right,pt2_right)
  theChamberFace.reverse!

  theChamberEdges= []
  0.upto((@newVerts.length/2 -1)) do |i|
   theChamberEdges[i] = ents.add_line(@newVerts[i],@newVerts[i+1]) ### make vertices into Chamber edges
 end

#############################################
model.commit_operation
#############################################

  begin
  theExtrusion=theChamberFace.followme theChamberEdges
  rescue
  UI.messagebox $!.message
  end

end ### end def chamfer_along_path

if( not file_loaded?("Chamfer_Along_Path.rb") )

   UI.menu("Tools").add_separator
   UI.menu("Tools").add_item("Chamfer Along Path") { chamfer_along_path }
   ###$submenu2.add_item("Chamfer Along Path") { chamfer_along_path }

end

###
file_loaded("Chamfer_Along_Path.rb")###
### #################################################################