#------------------------------------------------------------------------------------------------
# Permission to use, copy, modify, and distribute this software for 
# any purpose and without fee is hereby granted.
#------------------------------------------------------------------------------------------------
# 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.
#------------------------------------------------------------------------------------------------
# IT WAS CREATED AND TESTED IN A WINDOWS ENVIRONMENT ONLY AND MAY NOT FUNCTION ON A MAC.
#------------------------------------------------------------------------------------------------
# THIS PLUGIN IS ANOTHER FIGMENT OF MY IMAGENATION AND IS NOT BASED ON OR COMPLY WITH ANYTHING! 
#------------------------------------------------------------------------------------------------
#  Name:	Clip or Trim Terrian Mesh
#    By:	sdmitch
# Usage:	Plugins>SDM Tools>CorG Tool>Clip/Trim GE Mesh
#  Note:	Select the mesh you wish to keep then the mesh you wish to clip.  In steep areas where
#					a higher resolution patch is placed upon a larger low resolution, there will be vertical
#					gaps.  No attempt is made to close them by this plugin.
#  Date:	Oct 2016
# ------------------  MENU SETUP ---------------------- #
unless $sdm_tools_menu
	$sdm_tools_menu = UI.menu("Plugins").add_submenu("SDM Tools")
	$sdm_Edge_tools = $sdm_tools_menu.add_submenu("Edge Tool")
	$sdm_Face_tools = $sdm_tools_menu.add_submenu("Face Tool")
	$sdm_CorG_tools = $sdm_tools_menu.add_submenu("CorG Tool")
	$sdm_Misc_tools = $sdm_tools_menu.add_submenu("Misc Tool")
end
unless file_loaded?(__FILE__)
	$sdm_CorG_tools.add_item("Clip/Trim GE Mesh") { Sketchup.active_model.select_tool SDM::Clip_or_Trim_Terrain.new }
	file_loaded(__FILE__)
end
# ------------------------------------------------------ #
require 'sketchup'
#
module SDM

	class Clip_or_Trim_Terrain

		def initialize
			@ip = Sketchup::InputPoint.new
			@ip1 = Sketchup::InputPoint.new
			@Mod = Sketchup.active_model
			@Ent = @Mod.active_entities
			@Sel = @Mod.selection
			begin
				if Sketchup.version.to_i>15
					@Mod.layers["Location Snapshot"].visible=false
					@Mod.layers["Location Terrain"].visible=true
				else
					@Mod.layers["Google Earth Snapshot"].visible=false
					@Mod.layers["Google Earth Terrain"].visible=true
				end
			rescue
				response = UI.messagebox "Model does not contain a Google Earth Terrain layer.  Continue?",MB_YESNO
				Sketchup.send_action "selectSelectionTool:" if response == IDNO
			end
			@Trim_It=true
			self.reset
		end

		def reset
			@grps=[]
			@state = 0
			@best = nil
			@ip1.clear
			@Sel.clear
			@drawn = false
			Sketchup::set_status_text("", SB_VCB_LABEL)
			Sketchup::set_status_text("", SB_VCB_VALUE)
		end

		def set_current_point(x, y, view)
			if( !@ip.pick(view, x, y, @ip1) )
				return false
			end
			@ip1.copy! @ip
			view.tooltip = @ip.tooltip
			Sketchup::set_status_text("Select the mesh to Trim.  Press Shift to Clip", SB_PROMPT) if @state == 0 && @Trim_It
			Sketchup::set_status_text("Select the mesh to keep.  Press Shift to Trim", SB_PROMPT) if @state == 0 && !@Trim_It
			Sketchup::set_status_text("Select the mesh to clip or Right Click in space to start over", SB_PROMPT) if @state == 1
		end

		def onMouseMove(flags, x, y, view)
			self.set_current_point(x, y, view)
			ph = view.pick_helper;ph.do_pick(x, y)
			@best = ph.best_picked if ph.best_picked != @best
			view.invalidate
		end

		def onLButtonDown(flags, x, y, view)
			case @state
				when 0
					if @best.is_a?(Sketchup::Group)
						@grps[0]=@best; @tran=@best.transformation
						bb=@grps[0].bounds;zmin=bb.min.z-100.feet;zmax=bb.max.z+100.feet
						verts=[];@cpts=[]
						@grps[0].entities.each{|e|
							if e.is_a?(Sketchup::Edge)
								verts<<e.vertices
							end
						}
						verts.flatten!.uniq!
						verts.collect!{|v| v.position.transform(@tran)}
						verts.each{|v| v.z=bb.min.z}
						for i in 0..3
							min_dist=1e9;
							for v in verts
								dist=v.distance bb.corner(i)
								if dist < min_dist
									min_dist=dist
									@cpts[i]=Geom::Point3d.new(v.x,v.y,zmin)
									@cpts[i+4]=Geom::Point3d.new(v.x,v.y,zmax)
								end
							end
						end
					end
					if @Trim_It && UI.messagebox("Trim this Mesh?",MB_YESNO)==6
						@Mod.start_operation "Trim Mesh",true
						plns=[];@Sel.clear; #p @cpts
						plns[0]=Geom.fit_plane_to_points(@cpts[0],@cpts[1],@cpts[5]);#@Ent.add_face(@cpts[0],@cpts[1],@cpts[5],@cpts[4])
						plns[1]=Geom.fit_plane_to_points(@cpts[2],@cpts[0],@cpts[4]);#@Ent.add_face(@cpts[2],@cpts[0],@cpts[4],@cpts[6])
						plns[2]=Geom.fit_plane_to_points(@cpts[3],@cpts[2],@cpts[6]);#@Ent.add_face(@cpts[3],@cpts[2],@cpts[6],@cpts[7])
						plns[3]=Geom.fit_plane_to_points(@cpts[1],@cpts[3],@cpts[7]);#@Ent.add_face(@cpts[1],@cpts[3],@cpts[7],@cpts[5])
						@grps[0].entities.each{|e|
							if e.is_a?(Sketchup::Edge)
								for i in 0..3
									pts = e.vertices.map{|v|	v.position.transform(@tran)}
									if pts[0].distance_to_plane(plns[i])<3.feet || pts[1].distance_to_plane(plns[i])<3.feet
										@Sel.add e
									end
								end
							end
						}
						@Ent.erase_entities(@Sel)
						@Mod.commit_operation
						self.reset
					else
						@state=1
					end
				when 1
					if @best.is_a?(Sketchup::Group) && @best!=@grps[0]
						@grps[1]=@best; @Sel.clear; edgs1=[]; vrts1=[];long1=0
						@Mod.start_operation "Clip Mesh",true
						poly=[@cpts[0],@cpts[2],@cpts[3],@cpts[1]]
						fgrp=@Ent.add_group ;fent=fgrp.entities;
						fent.add_face(@cpts[0],@cpts[4],@cpts[5],@cpts[1]);# FRONT
						fent.add_face(@cpts[0],@cpts[2],@cpts[6],@cpts[4]);# LEFT
						fent.add_face(@cpts[1],@cpts[5],@cpts[7],@cpts[3]);# RIGHT
						fent.add_face(@cpts[2],@cpts[3],@cpts[7],@cpts[6]);# BACK
						fent.intersect_with(true,fgrp.transformation,@grps[1],@grps[1].transformation,true,@grps[1])
						@grps[1].entities.each{|e|
							if e.is_a?(Sketchup::Edge) 
								if e.hidden?
									p0=e.start.position;p1=e.end.position
									if (Geom.point_in_polygon_2D(p0,poly,false) && Geom.point_in_polygon_2D(p1,poly,true)) || \
										(Geom.point_in_polygon_2D(p1,poly,false) && Geom.point_in_polygon_2D(p0,poly,true))
										@Sel.add e
									end
								else
									e.soft=true; e.smooth=true
									edgs1<<e; vrts1<<e.vertices
									long1=[long1,e.length].max
								end
							end
						}
						vrts1.flatten!; vrts1.uniq!; 
						vrts0=[]; vecs0=[]; vecs1=[]; vers0=[]
						edgs0=@grps[0].entities.grep(Sketchup::Edge)
						edgs0.reject!{|e| e.faces.length>1}
						edgs0.each{|e| vrts0<<e.vertices}
						vrts0.flatten!; vrts0.uniq!
						vrts1.each{|v1|
							cept=nil;cvpt=nil;ced=1e9;cvd=1e9
							p1=v1.position
							vrts0.each{|v0|
								p0=v0.position; d=p0.distance(p1)
								(cvpt=p0;cvd=d) if d < cvd
							}
							edgs0.each{|e|
								pp=p1.project_to_line(e.line)
								if e.bounds.contains?(pp)
									d=p1.distance(pp)
									(cept=pp;ced=d) if d<ced
								end
							}
							ced<cvd ? vecs1<<p1.vector_to(cept) : vecs1<<p1.vector_to(cvpt)
						}
						@grps[1].entities.transform_by_vectors(vrts1,vecs1)
						
						vrts0.each{|v0|
							cept=nil;ced=long1;p0=v0.position
							edgs1.each{|e|
								pp=p0.project_to_line(e.line)
								if e.bounds.contains?(pp)
									d=p0.distance(pp)
									(cept=pp;ced=d) if d<ced
								end
							}
							(vers0<<v0;vecs0<<p0.vector_to(cept)) if cept
						}
						@grps[0].entities.transform_by_vectors(vers0,vecs0)
						
						@Sel.add fent.to_a;@Ent.erase_entities(@Sel)
						@Mod.commit_operation
						self.reset
					else
						UI.beep; puts "same group selected"
					end
			end
			view.lock_inference
		end
		
		def onCancel(flag, view)
			view.invalidate if @drawn
			Sketchup.send_action "selectSelectionTool:"
		end
		
		def onRButtonDown(flags,x,y,view)
			Sketchup.send_action "selectSelectionTool:" if @state == 0
			self.reset
		end

		def draw(view)
			@drawn = false
			if( @ip.valid? && @ip.display? )
				@ip.draw(view)
				@drawn = true
			end
			if @best.class==Sketchup::Group
				bb=@best.bounds
				view.line_width=3; view.drawing_color="Yellow"
				view.draw_polyline bb.corner(0),bb.corner(2),bb.corner(3),bb.corner(1),bb.corner(0)
				view.draw_polyline bb.corner(4),bb.corner(6),bb.corner(7),bb.corner(5),bb.corner(4)
				0.upto(3){|i| view.draw_line(bb.corner(i), bb.corner(i+4))}
			end
		end

		def onKeyDown(key, repeat, flags, view)
			# puts "Key #{key} pressed"
			if key==CONSTRAIN_MODIFIER_KEY #16 || 131072 #shift PC || MAC
				@Trim_It=!@Trim_It
			end
		end

	end # of class Clip_or_Trim
	
end
