#
# Name:		PocketTool.rb
# Desctiption:	Create a pocket face and zigzag edges
# Author:	Katsuhiko Toba ( http://www.eprcp.com/ )
# Usage:	1. Install into the plugins directory.
#		2. Select "Pocket" from the Plugins menu.
#		3. Click the face to pocket
#		4. Select "CenterLine Tool" from menu or toolbar
#		5. Click the zigzag edge first, the face edge second.
#		NOTE: Do not use Centerline from context menu.
#                     It breaks the zigzag edge.
# Limitations:	Simple convex face only
#

require 'sketchup.rb'

class PocketTool

	def initialize
		@bit_diameter = 3.175.mm
		@ip = nil
		@active_face = nil
	end

	def activate
		@ip = Sketchup::InputPoint.new
		Sketchup::set_status_text "PocketTool Activated", SB_VCB_LABEL
		self.reset(nil)
	end

	def reset(view)
		if (view)
			view.tooltip = nil
			view.invalidate
		end
	end

	def draw(view)
		if (@active_face)
			self.draw_geometry(view)
		end
	end

	def onMouseMove(flags, x, y, view)
		@ip.pick view, x, y
		@active_face = activeFaceFromInputPoint(@ip)
		if (@active_face)
			view.tooltip = @ip.tooltip
		end
		view.invalidate if (@ip.display?)
	end

	def onLButtonDown(flags, x, y, view)
		@ip.pick view, x, y
		@active_face = activeFaceFromInputPoint(@ip)
		if (@active_face)
			self.create_geometry(@active_face, view)
		end
		self.reset(view)
		view.lock_inference
	end

	def activeFaceFromInputPoint(inputPoint)
		face = inputPoint.face

		# check simple face (outer_loop only)
		if (face)
			if (face.loops.length != 1)
				face = nil
			end
		end
		return face
	end

	def draw_geometry(view)
		view.drawing_color = "Green"
		#view.line_width = 3.0

		zigzag_points = get_zigzag_points(@active_face.outer_loop)
		contour_points = get_contour_points(@active_face.outer_loop)

		if (zigzag_points.length >= 2)
			view.draw GL_LINE_STRIP, zigzag_points
		end
		if (contour_points.length >= 3)
			view.draw GL_LINE_LOOP, contour_points
		end
	end

	def create_geometry(face, view)
		model = view.model
		model.start_operation "Creating Pocket"

		zigzag_points = get_zigzag_points(@active_face.outer_loop)
		contour_points = get_contour_points(@active_face.outer_loop)

		if (zigzag_points.length >= 2)
			model.entities.add_edges(zigzag_points)
		end
		if (contour_points.length >= 3)
			# reverse points for counter clockwize loop
			model.entities.add_face(contour_points.reverse!)
		end

		model.commit_operation
	end

	#----------------------------------------------------------------------
	# generic offset points routine
	#----------------------------------------------------------------------

	def get_intersect_points(lines)
		pts = []
		for i in 0..lines.length-1 do
			line1 = lines[i-1]	# array[-1] is equal to array[array.length-2]
			line2 = lines[i]
			pt = Geom::intersect_line_line(line1, line2)
			if (pt)
				pts << pt
			end
		end
		return pts
	end

	def get_offset_points(loop, offset)
		normal_vector = Geom::Vector3d.new(0,0,-1)

		loop_length = 0.0	# length of original loop
		normal_length = 0.0
		reverse_length = 0.0

		normal_lines = []
		reverse_lines = []

		for edge in loop.edges
			pt1 = edge.start.position
			pt2 = edge.end.position
			loop_length += pt1.distance pt2

			line_vector = edge.line[1]
			line_vector.normalize!
			move_vector = line_vector * normal_vector
			move_vector.length = offset

			normal_lines <<  [pt1.offset(move_vector), pt2.offset(move_vector)]
			reverse_lines <<  [pt1.offset(move_vector.reverse), pt2.offset(move_vector.reverse)]
		end

		normal_points = get_intersect_points(normal_lines)
		for i in 0..normal_points.length-1 do
			pt1 = normal_points[i-1]
			pt2 = normal_points[i]
			normal_length += pt1.distance pt2
		end

		reverse_points = get_intersect_points(reverse_lines)
		for i in 0..reverse_points.length-1 do
			pt1 = reverse_points[i-1]
			pt2 = reverse_points[i]
			reverse_length += pt1.distance pt2
		end

		#puts "loop_length="+loop_length.to_s
		#puts "normal_length="+normal_length.to_s
		#puts "reverse_length="+reverse_length.to_s

		if (normal_length > loop_length)
			if (offset > 0.0)
				return normal_points
			else
				return reverse_points
			end
		else
			if (offset > 0.0)
				return reverse_points
			else
				return normal_points
			end
		end
	end

	#----------------------------------------------------------------------
	# contour
	#----------------------------------------------------------------------

	def get_contour_points(loop)
		return get_offset_points(loop, -(@bit_diameter * 0.5))
	end

	#----------------------------------------------------------------------
	# zigzag
	#----------------------------------------------------------------------

	def get_hatch_points(points, y)
		plane = [Geom::Point3d.new(0, y, 0), Geom::Vector3d.new(0,1,0)]
		pts = []
		for i in 0..points.length-1 do
			y1 = points[i-1].y
			y2 = points[i].y
			next if (y1 == y2)
			next if ((y1 > y2) && ((y > y1) || (y < y2)))
			next if ((y1 < y2) && ((y < y1) || (y > y2)))

			line = [points[i-1], points[i]]
			pt = Geom::intersect_line_plane(line, plane)
			if (pt)
				pts << pt
			end
		end
		pts.uniq!
		return pts.sort{|a,b| a.x <=> b.x}
	end

	def get_zigzag_points(loop)
		dir = 1
		zigzag_points = []
		offset_points = get_offset_points(loop, -(@bit_diameter * 0.6))

		bb = loop.face.bounds
		y = bb.min.y + @bit_diameter
		while (y < bb.max.y) do
			pts = get_hatch_points(offset_points, y)
			if (pts.length >= 2)
				if (dir == 1)
					zigzag_points << pts[0]
					zigzag_points << pts[1]
					dir = -1
				else
					zigzag_points << pts[1]
					zigzag_points << pts[0]
					dir = 1
				end
			end
			y = y + @bit_diameter * 0.5
		end

		return zigzag_points
	end

end

#------------------------------------------------------------------------
def pockettool
	Sketchup.active_model.select_tool PocketTool.new
end

if( not file_loaded?("PocketTool.rb") )
	main_menu = UI.menu("Plugins")
	main_menu.add_item("Pocket") {(pockettool)}
end
file_loaded("PocketTool.rb")

#------------------------------------------------------------------------

