require 'sketchup.rb'
def gcd3(one,other)
	min = one.abs
	max = other.abs
	while min > 0
		min, max = max % min, min
	end
	max
end
def options
	dc = "Distance Crawling"
	sc = "Split and Connect"
	all = "Distance Crawling|Split and Connect"
	#selections = UI.inputbox(["For Two Lines", "For Just Faces", "For Line to Face", "With Intersections"], [sc, dc, dc, sc], [all, all, all, all], "Skinning Methods to Use")
	selections = UI.inputbox(["For Two Lines", "For Just Faces"], [sc, dc], [all, all], "Skinning Methods to Use")
	selections.collect! do
		|looptemp|
		if (looptemp == dc)
			"Crawl"
		elsif (looptemp == sc)
			"Split"
		end
	end
	Sketchup.write_default("skinrb", "lines", selections[0])
	Sketchup.write_default("skinrb", "faces", selections[1])
	#Sketchup.write_defults("skinrb", "lineface", selections[2])
	#Sketchup.write_defults("skinrb", "intersect", selections[1])
end
def clean_selection(entities)
	trash = []
	Sketchup.active_model.start_operation "Clean Selection"
	selection = Sketchup.active_model.selection
	if (entities)
		selection.clear
		selection.add entities
	end
	selection.each {|looptemp|trash.push(looptemp) if (looptemp.typename == "Edge" && looptemp.faces.length == 0)}
	selection.each {|looptemp|trash.push(looptemp) if (looptemp.typename == "Edge" && looptemp.faces.length == 2 && looptemp.faces[0].material == looptemp.faces[1].material && (looptemp.faces[0].plane == looptemp.faces[1].plane))}
	Sketchup.active_model.entities.erase_entities(trash)
	Sketchup.active_model.commit_operation
end
def multiplyPoints(points, amount)
	addpoints = []
	(points.length - 1).times do
		|index|
		addpoints.push []
		(amount - 1).times do
			|number|
			addpoints.last.push(Geom::Point3d.linear_combination((amount - number - 1)/amount.to_f, points[index], (number + 1)/amount.to_f, points[index + 1]))
		end
	end
	points = points.zip addpoints
	points.flatten!
	points.compact!
	return points
end
def connect_rails(leftpoints, rightpoints, reverse, connectType)
	Sketchup.active_model.start_operation "Skin Part"
	leftpoints.collect!{|looptemp| looptemp.position}
	rightpoints.collect!{|looptemp| looptemp.position}
	rightnext = nil
	leftnext = nil
	forepoint = nil
	backpoints = []
	thesefaces = []
	rightpoints.reverse! if ((rightpoints.first.distance(leftpoints.first) > rightpoints.last.distance(leftpoints.first) && reverse == nil) || reverse == true)
	if (connectType == "Split")
		forepoint = (rightpoints.length-1)*(leftpoints.length-1)/gcd3((rightpoints.length-1), (leftpoints.length-1))
		rightnext = forepoint/(rightpoints.length-1)
		leftnext = forepoint/(leftpoints.length-1)
		rightpoints = multiplyPoints(rightpoints, rightnext)
		leftpoints = multiplyPoints(leftpoints, leftnext)
	end
	leftpoint = leftpoints.shift
	leftnext = leftpoints.shift
	rightpoint = rightpoints.shift
	rightnext = rightpoints.shift
	if (connectType == "Crawl")
		while (true)
			backpoints = [leftpoint, rightpoint]
			leftnext = leftpoints.shift if (leftnext == nil)
			rightnext = rightpoints.shift if (rightnext == nil)
			if ([leftnext, rightnext] == [nil, nil])
				thesefaces.collect!{|looptemp|Sketchup.active_model.entities.add_face(looptemp)}	
				Sketchup.active_model.commit_operation
				return thesefaces
			elsif (leftnext == nil || (rightnext != nil && rightnext.distance(leftpoint) < leftnext.distance(rightpoint)))
				forepoint = rightnext
				rightpoint = rightnext
				rightnext = nil
			elsif (leftnext != nil)
				forepoint = leftnext
				leftpoint = leftnext
				leftnext = nil
			end
			thesefaces.push [backpoints, forepoint].flatten
		end
	elsif (connectType == "Split")
		while (true)
			if ([leftnext, rightnext] == [nil, nil])
				thesefaces.collect!{|looptemp|Sketchup.active_model.entities.add_face(looptemp)}
				return thesefaces
			elsif (rightnext.distance(leftpoint) < leftnext.distance(rightpoint))
				thesefaces.push([rightpoint, leftpoint, rightnext], [rightnext, leftnext, leftpoint])
			else
				thesefaces.push([rightpoint, leftpoint, leftnext], [rightnext, leftnext, rightpoint])
			end
			leftpoint = leftnext
			rightpoint = rightnext
			leftnext = leftpoints.shift
			rightnext = rightpoints.shift
		end
	end
end
def get_points(startpoint, lines)
	points = [startpoint]
	points.push (((lines.delete((points.last.edges & lines)[0])).vertices.reject{|looptemp|looptemp == points.last})[0]) while ((points.last.edges & lines).length != 0)
	return(points)
end
def skin
	strings = ["An error occurred. The next version will hopefully fix the one that you are experiencing. Version 3.0 is the next planned errorless one.",
		"You must have selected more than you wanted to, it is not all in two groups. Currently I'm taking two random ones but future versions will deal differently with this issue",
		"Is this connection done right?",
		"Do you want to try to guide me to the correct connection?",
		"Shall I try to fix my error?"]
	selection = Sketchup.active_model.selection
	reverse = nil
	connecttype = nil
	side = []
	sides = []
	connectionfaces = []
	sidesets = []
	allfaces = []
	alledges = []
	rightedges = []
	leftedges = []
	leftpoints = []
	rightpoints = []
	intersections = []
	ends = []
	selection.each {|looptemp| alledges.push(looptemp)}
	allfaces = alledges.reject{|looptemp| looptemp.typename != "Face"}
	alledges.reject!{|looptemp| looptemp.typename != "Edge"}
	while (alledges.length > 0)
		side.push(alledges.pop)
		side.each do
			|looptemp|
			looptemp.vertices.each do
				|loopt|
				(loopt.edges & alledges).each do
					|lpt|
					side.push lpt
					alledges.delete lpt
				end
			end
		end
		sides.push(side + [])
		side.clear
	end
	UI.messagebox strings[1] if (sides.length > 2)
	sidesets.push([sides[0], sides[1]])
	sidesets.each do
		|set|
		rightedges = set[0]
		leftedges = set[1]
		rightpoints = rightedges.collect{|looptemp| looptemp.vertices}.flatten.uniq
		leftpoints = leftedges.collect{|looptemp| looptemp.vertices}.flatten.uniq
		intersections = (rightpoints + leftpoints).reject{|looptemp|(looptemp.edges & (rightedges + leftedges)).length < 3}
		ends = (rightpoints + leftpoints).reject{|looptemp|(looptemp.edges & (rightedges + leftedges)).length != 1}
		if (intersections.length > 0)
			UI.messagebox strings[0]
			connecttype = 3
		elsif (ends.length == 0)
			leftpoints = get_points(leftpoints.sort{|a,b|a.position.distance(rightpoints.first) <=> b.position.distance(rightpoints.first)}[0], Array.new(leftedges))
			rightpoints = get_points(rightpoints.first, Array.new(rightedges))
			connectionfaces.push(connect_rails(leftpoints, rightpoints, reverse, Sketchup.read_default("skinrb", "faces", "Crawl")))
			connecttype = 4
		elsif ([(leftpoints & ends).length, (rightpoints & ends).length] == [2, 2])
			leftpoints = get_points((leftpoints & ends)[0], Array.new(leftedges))
			rightpoints = get_points((rightpoints & ends)[0], Array.new(rightedges))
			connectionfaces.push(connect_rails(leftpoints, rightpoints, reverse, Sketchup.read_default("skinrb", "lines", "Split")))
			connecttype = 4
		else
			UI.messagebox strings[0]
			connecttype = 4
		end
		if (reverse != false && UI.messagebox(strings[2], MB_YESNO, "Quality Check") == 7 && UI.messagebox(strings[connecttype], MB_YESNO, "Answer, Please") == 6)
			connectionfaces.clear
			Sketchup.undo
			reverse = false if reverse == true
			reverse = true if reverse == nil
			redo
		end
		allfaces.push connectionfaces
	end
	allfaces.flatten!
	allfaces.collect!{|looptemp| [looptemp.edges, looptemp]}
	allfaces.flatten!
	allfaces.uniq
	clean_selection allfaces
	return true
end
skin = SketchupExtension.new "Skin", "skin.rb"
skin.description = "A tool that takes two selected sets of entities and connects them, normally..."
skin.version = "2.2"
skin.creator = "Darrel, Toolbar Icons were done by Baz"
skin.copyright = "2007, Darrel"
skinc = UI::Command.new("Skin") {skin()}
skinc.small_icon = "skin/skinS.png"
skinc.large_icon = "skin/skin.png"
skinc.tooltip = "Connects the two selected sides."
cleanc = UI::Command.new("Clean") {clean_selection(nil)}
cleanc.small_icon = "skin/cleanS.png"
cleanc.large_icon = "skin/clean.png"
cleanc.tooltip = "Removes all coplanar or empty selected edges."
if not (file_loaded? "skin.rb")
	add_separator_to_menu("Tools")
	dbtoolsm = UI.menu("Tools").add_submenu("D.B.Tools")
		dbtoolsm.add_item("Clean Selection") {clean_selection(nil)}
		dbtoolsm.add_item("Skin") {skin()}
		dbtoolsm.add_item("Options") {options()}
	Sketchup.register_extension skin
	DBTools = UI::Toolbar.new("D.B. Tools")
	DBTools.add_item(skinc)
	DBTools.add_item(cleanc)
end
file_loaded("skin.rb")