=begin
btm_Sculpt4_smooth.rb

Copyright 2009, btmsketchup@hotmail.com

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.

Created by •BTM on 23/07/09.

Name:			Smooth (sculpt tools)
Version:		1.0
Description:	Smooths out a mesh.
Usage:			Set the settings of the tool with the Sculpt Tools Dialog, and use it by 'brushing' on the mesh, with the left mouse button held down.
=end
require 'sketchup.rb'
#===================================================================================
class SculptSmooth
#===================================================================================
	def activate
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
	@model = Sketchup.active_model
	
	if Sketchup.version_number < 7000000
		@model.start_operation "Sculpt Smooth"
	else
		@model.start_operation "Sculpt Smooth", true
	end
	@entities = @model.active_entities

	@points = []
	@apns = []
	@drawlocked = []
	@sculptlocks = []
	
	@max_thing = $btm_sculpt_radius
	@percent = $btm_sculpt_strength
	@area = $btm_sculpt_area
	@gravity = $btm_sculpt_gravity
	@kind = $btm_sculpt_trans
	@locked = $btm_sculpt_lock
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
	@ip1 = Sketchup::InputPoint.new
    @ip2 = Sketchup::InputPoint.new
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
	if @locked == "Use + Show" or @locked == "Use"
		@entities.each do |e|
			if e.is_a? Sketchup::Edge
			@apns << e.start
			@apns << e.end
			end
		att = e.get_attribute "sculpt", "lockgroup"
			if att != nil
			@sculptlocks << att
			end
		end
		@apns.uniq!
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
		@apns.each do |p|
			@sculptlocks.each do |l|
				if p.position.on_plane? l
				@drawlocked << p
				attrs = p.get_attribute  "sculpt", "lock"
				attrs = [] if not p.get_attribute  "sculpt", "lock"
				attrs << l
				p.set_attribute "sculpt", "lock", attrs
				end
			end
		end
	@drawlocked.uniq!
	end
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
	end
#===================================================================================
	def onLButtonDown(flags,x,y,view)
	@model.start_operation "Sculpt Smooth"
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
			@entities.each do |e|
				if e.is_a? Sketchup::Edge
				@points << e.start
				@points << e.end
				end
			end
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
		@points.uniq!
	end
#===================================================================================
	def onMouseMove(flags, x, y, view)
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
		@ip1.pick view, x, y
		if @ip1 != @ip2
		@old_point = @ip2.position
		view.invalidate
		@ip2.copy! @ip1
		end
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
		if flags == $btm_sculpt_platform + MK_LBUTTON or flags == $btm_sculpt_platform + MK_LBUTTON + MK_SHIFT
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
		ip1 = view.inputpoint x,y
		pt1 = ip1.position
		@mouse_point = Geom::Point3d.new pt1
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
			@points.each do |p|
			pos = p.position
			
				if $btm_sculpt_lag == "on"
			
				l_line = [@old_point, @mouse_point]
				l_start = @old_point
				l_end = @mouse_point
				linepos1 = pos.project_to_line l_line
				length_s = l_start.distance linepos1
				length_e = l_end.distance linepos1
				length_edge = l_start.distance l_end
			
						if length_s > length_edge and length_e
						@linepos = l_end
						elsif length_e > length_edge and length_s
						@linepos = l_start
						else @linepos = linepos1
						end
				dist = pos.distance @linepos
				else
				dist = pos.distance @mouse_point
				end
			
			radius = @max_thing + @area
			in_dist = dist - @area
			half_dist = @max_thing /2
			dist_from_half = half_dist - in_dist
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
			pedges = []
			mathpoints = []
			edgecount = 0
			pedges = p.edges
			
				pedges.each do |l|
				edgecount = edgecount + 1
					if p == l.start
					mathpoints << l.end.position
					elsif p == l.end
					mathpoints << l.start.position
					end
				end
			
			@mean = []
			@mean = [ 0, 0, 0]
				mathpoints.each do |m|
				@mean[0] = @mean[0] + m.to_a[0]
				@mean[1] = @mean[1] + m.to_a[1]
				@mean[2] = @mean[2] + m.to_a[2]
				end
			@mean[0] = @mean[0] /edgecount
			@mean[1] = @mean[1] /edgecount
			@mean[2] = @mean[2] /edgecount
			@vector = pos.vector_to @mean
			meandist = pos.distance @mean
#     -     -     -     -     -     -     -     -     -     -     -     -     -    -
			distpermean = (dist/ radius)*meandist
					
				if @area < dist  and dist <= radius
					if @kind == "s curve"
						if @vector != [ 0, 0, 0]
						@vector.length = ((meandist / ( 1 + E**-(5/ half_dist*dist_from_half)**1))/ 100)*@percent
						end
					elsif @kind == "pinch"
						if @vector != [ 0, 0, 0]
						@vector.length = ((((meandist - distpermean)**2)/ meandist) /100)*@percent
						end
					elsif @kind == "bump"
						if @vector != [ 0, 0, 0]
						@vector.length = ((((meandist**2) - (distpermean**2))/ meandist) /100)*@percent
						end
					else
						if @vector != [ 0, 0, 0]
						@vector.length = ((meandist - distpermean) / 100)*@percent
						end
					end
					if @vector != [ 0, 0, 0]
					@entities.transform_entities(@vector,p)
					end
					
					if @gravity != 0
					pos2 = p.position
					change = pos.distance pos2
					drop = -(change / 100)*@gravity
					vector2 = Geom::Vector3d.new [ 0, 0, drop]
					@entities.transform_entities(vector2,p)
					end
					if @locked == "Use + Show" or @locked == "Use"
					ats = p.get_attribute "sculpt", "lock"
						if ats != nil
							ats.each do |a|
							pos3 = p.position
							lockpoint = pos3.project_to_plane a
							vector3 = pos3.vector_to lockpoint
							@entities.transform_entities(vector3,p)
							end
						end
					end
				
				elsif dist <= @area
					if @vector != [ 0, 0, 0]
					@vector.length = (meandist / 100)*@percent
					@entities.transform_entities(@vector,p)
					end
					
					if @gravity != 0
					pos2 = p.position
					change = pos.distance pos2
					drop = -(change / 100)*@gravity
					vector2 = Geom::Vector3d.new [ 0, 0, drop]
					@entities.transform_entities(vector2,p)
					end
					if @locked == "Use + Show" or @locked == "Use"
					ats = p.get_attribute "sculpt", "lock"
						if ats != nil
							ats.each do |a|
							pos3 = p.position
							lockpoint = pos3.project_to_plane a
							vector3 = pos3.vector_to lockpoint
							@entities.transform_entities(vector3,p)
							end
						end
					end
				end
			end
		end
	end
#===================================================================================
#THIS SECTION OF CODE UNTILL end#def WAS WRITTEN BY TIG.
def circleArray(center,normal,radius,numseg)
    # Get the x and y axes
    axes = Geom::Vector3d.new(normal).axes
    center = Geom::Point3d.new(center)
    xaxis = axes[0]
    yaxis = axes[1]
    xaxis.length = radius
    yaxis.length = radius
    # compute the points
    da = (Math::PI * 2) / numseg
    pts = []
    for i in 0...numseg do
        angle = i * da
        cosa = Math.cos(angle)
        sina = Math.sin(angle)
        vec = Geom::Vector3d.linear_combination(cosa,xaxis,sina,yaxis)
        pts.push(center + vec)
    end
    # close the circle
    pts.push(pts[0].clone)
    pts
end#def
#===================================================================================
	def draw(view)
		if $btm_sculpt_visual == "Inference" or $btm_sculpt_visual == "Inference + Radius"
		@ip1.draw view
		end
		if @locked== "Use + Show" and @drawlocked != []
		dps = []
			@drawlocked.each do |d|
			dps << d.position
			end
		view.draw_points dps, 6, 1, "red"
		end
	rad = @area + @max_thing
	
points = []
	viewvec = [0,0,1]
		@entities.each do |f|
			if f.is_a? Sketchup::Face and @ip1.position.on_plane? f.plane
			viewvec = f.normal
			end
		end

		if $btm_sculpt_visual == "Radius" or $btm_sculpt_visual == "Inference + Radius"
			if @max_thing > 0.to_l
			view.drawing_color="blue"
			view.draw GL_LINE_LOOP, circleArray(@ip1.position, viewvec, rad, 30)
			end
			if @area > 0.to_l
			view.drawing_color="red"
			view.draw GL_LINE_LOOP, circleArray(@ip1.position, viewvec, @area, 30)
			end
		end
	end
#===================================================================================
	def deactivate(view)
		@drawlocked.each do |p|
		p.delete_attribute "sculpt", "lock"
		end
	end
#===================================================================================
end
		mgp = UI::Command.new("Smooth") { Sketchup.active_model.select_tool SculptSmooth.new }
		$btm_sculpt_menu.add_item mgp
		mgp.large_icon = "./smooth_24.png"
		mgp.small_icon = "./smooth_16.png"
		mgp.tooltip = "Smooth"
		toolbar = $btm_sculpt_toolbar.add_item mgp
		case toolbar.get_last_state
		when 1
			toolbar.restore
		when -1   
			toolbar.show
		end