# Copyright 2004, Rick Wilson 
#
# Permission to use, copy, modify, and distribute this software for 
# any purpose and without fee is hereby granted, provided that the above
# copyright notice appear in all copies.
#
# 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.
#
# Name :          offset.rb 1.0
# Description :   Offset edges of a selected face (new method for class Sketchup::Face)
# Author :        Rick Wilson
# Usage :         1.	Intended for developers as a method to call from 
#				within a script.  Add a "require 'offset.rb' line
#				right after the "require 'sketchup.rb' line.  Distribute
#				with your script since not everyone will have this
#				already.  Returns the face created by the offset.
# Date :          7.Sept.2004
# Type :          Method
# History:
#			1.0 (7.Sept.2004) - first version
# 

class Sketchup::Face
	def offset(dist)
#		return nil if dist==0
		pi=Math::PI
		if (not ((dist.class==Fixnum || dist.class==Float || dist.class==Length) && dist!=0))
			return nil
		end
		verts=self.outer_loop.vertices
		pts=[]
		0.upto(verts.length-1) do |a|
			vec1=(verts[a].position-verts[a-(verts.length-1)].position).normalize
			vec2=(verts[a].position-verts[a-1].position).normalize
			vec3=(vec1+vec2).normalize
			if vec3.valid?
				ang=vec1.angle_between(vec2)/2
				ang=pi/2 if vec1.parallel?(vec2)
				vec3.length=dist/Math::sin(ang)
				t=Geom::Transformation.new(vec3)
				if pts.length > 0
					if not (vec2.parallel?(pts.last.vector_to(verts[a].position.transform(t))))
						t=Geom::Transformation.new(vec3.reverse)
					end
				end
				pts.push(verts[a].position.transform(t))
			end
		end
		Sketchup.active_model.active_entities.add_face(pts)
	end
end

class Array
	def offset(dist)
#		return nil if dist==0
		pi=Math::PI
		if (not ((dist.class==Fixnum || dist.class==Float || dist.class==Length) && dist!=0))
			return nil
		end
		verts = self
		pts=[]
		0.upto(verts.length-1) do |a|
			vec1=(verts[a]-verts[a-(verts.length-1)]).normalize
			vec2=(verts[a]-verts[a-1]).normalize
			vec3=(vec1+vec2).normalize
			if vec3.valid?
				ang=vec1.angle_between(vec2)/2
				ang=pi/2 if vec1.parallel?(vec2)
				vec3.length=dist/Math::sin(ang)
				t=Geom::Transformation.new(vec3)
				if pts.length > 0
					if not (vec2.parallel?(pts.last.vector_to(verts[a].transform(t))))
						t=Geom::Transformation.new(vec3.reverse)
					end
				end
				pts.push(verts[a].transform(t))
			end
		end
		return pts
	end
end

class Sketchup::ArcCurve
	def offset(dist)
		return nil if dist==0 || (not (dist.class==Float || dist.class==Fixnum || dist.class==Length))
		radius=self.radius+dist.to_f
		Sketchup.active_model.active_entities.add_arc self.center, self.xaxis, self.normal, radius, self.start_angle, self.end_angle, self.count_edges
	end
end

class Sketchup::Curve
	def offset(dist)
		return nil if self.count_edges<2
		pi=Math::PI
		if (not ((dist.class==Fixnum || dist.class==Float || dist.class==Length) && dist!=0))
			return nil
		end
		verts=self.vertices
		pts=[]
		0.upto(verts.length-1) do |a|
			if a==0 #special case for start vertex
				model=self.parent
				model.start_operation "offset"
				gp=model.active_entities.add_group
				gpents=gp.entities
				face=gpents.add_face(verts[0].position,verts[1].position,verts[2].position)
				zaxis=face.normal
				v=self.edges[0].line[1]
				f=dist/dist.abs
				t=Geom::Transformation.rotation(verts[0].position,zaxis,(pi/2)*f)
				vec3=v.transform(t)
				vec3.length=dist.abs
				pts.push(verts[0].position.transform(vec3))
				gp.erase!
				model.commit_operation
			elsif a==(verts.length-1) #special case for end vertex
				model=self.parent
				model.start_operation "offset"
				gp=model.active_entities.add_group
				gpents=gp.entities
				face=gpents.add_face(verts[a].position,verts[a-1].position,verts[a-2].position)
				zaxis=face.normal
				v=self.edges[a-1].line[1]
				f=dist/dist.abs
				t=Geom::Transformation.rotation(verts[a].position,zaxis,(pi/2)*f)
				vec3=v.transform(t)
				vec3.length=dist.abs
				pts.push(verts[a].position.transform(vec3))
				gp.erase!
				model.commit_operation
			else
				vec1=(verts[a].position-verts[a-(verts.length-1)].position).normalize
				vec2=(verts[a].position-verts[a-1].position).normalize
				vec3=(vec1+vec2).normalize
				if vec3.valid?
					ang=vec1.angle_between(vec2)/2
					ang=pi/2 if vec1.parallel?(vec2)
					vec3.length=dist/Math::sin(ang)
					t=Geom::Transformation.new(vec3)
					if pts.length > 0
						if not (vec2.parallel?(pts.last.vector_to(verts[a].position.transform(t))))
							t=Geom::Transformation.new(vec3.reverse)
						end
					end
					pts.push(verts[a].position.transform(t))
				end
			end
		end
		Sketchup.active_model.active_entities.add_curve(pts)
	end
end

