#
# 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
#
# ** Modified by kyyu 05-29-2010 - rewrote "get_offset_points" method because of a bug          **
#   where the pocket lines were out of the pocket boundaries because of mix direction edges     **
#   -Looks like it works, but not rigorously check so USE AT YOUR OWN RISK!                     **
# [Modified by Kram242 08-30-2010 Set this one up for a smaller step over on the creation of the pocket lines to use as a sharpie mod by changing bit diameter from 3.15mm to 0.03125 in]

require 'sketchup.rb'

class PocketTool

	def initialize
		@bit_diameter = 0.03125
		@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)
        lines = []
        r = []
        notr = []
        for edge in loop.edges 
            if edge.reversed_in? @active_face then r.push edge
            else notr.push edge
            end
        end    
        
        for edge in loop.edges
            pt1 = edge.start.position
			pt2 = edge.end.position
            
			line_vector = edge.line[1]
			line_vector.normalize!
			move_vector = line_vector * normal_vector
			move_vector.length = offset

            if r.length != 0 and notr.length != 0
                if edge.reversed_in? @active_face
                    lines <<  [pt1.offset(move_vector.reverse), pt2.offset(move_vector.reverse)]
                else 
                    lines <<  [pt1.offset(move_vector), pt2.offset(move_vector)]
                end
            elsif r.length == 0
			lines <<  [pt1.offset(move_vector), pt2.offset(move_vector)]
            elsif notr.length == 0
            lines <<  [pt1.offset(move_vector.reverse), pt2.offset(move_vector.reverse)]
            end
		end

		points = get_intersect_points(lines)
        return points

		# 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")

#------------------------------------------------------------------------

