=begin
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
# Designed December 2014 by Fredo6

# Permission to use this software for any purpose and without fee is hereby granted
# Distribution of this software for commercial purpose is subject to:
#  - the expressed, written consent of the author
#  - the inclusion of the present copyright notice 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			:   TopoShaperCloudTool.rb
# Original Date	:   9 Dec 2014
# Description	:   Interactive Tool for generation of terrain from a cloud of points
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
=end

module F6_TopoShaper

T6[:TIT_CloudOperation] = "TopoShaper: Terrain from Points Cloud"

T6[:BOX_Roundness] = "Roundness"
T6[:TIP_Roundness] = "Factor for Roundness of the terrain (advised between 2.5 and 4)"
T6[:BOX_DeviationMax] = "Smoothing"
T6[:TIP_DeviationMax] = "Maximum roof angle at edges of the mesh"
T6[:PROMPT_DeviationMax] = "Smoothness factor (in degrees)"
T6[:BOX_TriangleMax] = "Max. Tri"
T6[:TIP_TriangleMax] = "Maximum number of triangles (generation will stop beyond this number)"
T6[:PROMPT_TriangleMax] = "Maximum number of triangles"
T6[:BOX_IsoContour] = "IsoContours"
T6[:TIP_IsoContourTitle] = "Hide / Show Iso-Contours"
T6[:TIP_IsoContourVal] = "Interval between Iso-Contours"
T6[:BOX_Points] = "Points"
T6[:TIP_PointsTitle] = "Hide / Show Cloud Points"
T6[:TIP_PointsOnly] = "Only Guide points"
T6[:TIP_PointsLine] = "Guide points with trailer guide lines"
T6[:BOX_Skirt] = "Skirt"
T6[:TIP_SkirtDelta] = "Delta in % versus minimum altitude"
T6[:TIP_SharpBorders] = "Nb of sharp edges"
T6[:TIP_SharpBorders2] = "Nb of very sharp edges"
T6[:TIP_NbCloudPoints] = "Number of Cloud Points"
T6[:TIP_NbTriangles] = "Number of Triangles"
T6[:TIP_ShowDetails] = "Show / Hide triangles and sharp borders"

T6[:LABEL_IsoContour] = "Iso-Contour:"
T6[:LABEL_CloudPoint] = "Cloud Point:"
T6[:LABEL_SharpEdge] = "Sharp Edge:"
T6[:LABEL_VerySharpEdge] = "Very Sharp Edge:"
T6[:LABEL_TinyVerySharpEdge] = "Tiny Very Sharp Edge:"

T6[:TIP_NavigationStartOver] = "Start Over"			
T6[:TIP_NavigationForceCompute] = "Compute"			
T6[:TIP_NavigationHistory] = "History"	
T6[:TIP_NavigationReset] = "Reset calculation"
T6[:TIP_NavigationForceStartOver] = "Double-Click to force start-over"
T6[:TIP_NavigationPrevious] = "Back One Iteration"
T6[:TIP_NavigationCurrent] = "Current Iteration"
T6[:TIP_NavigationNext] = "Next Iteration"
T6[:TIP_NavigationAuto] = "Auto Calculation"
	
T6[:MSG_NotValidGroup] = "Selection is not a Valid group or component"
T6[:MSG_NoPointInGroup] = "Selection does not contain Guide Points"
T6[:MSG_CalcultingFittingBox] = "Calculating Best-Fitting box for the Cloud Points"

T6[:BOX_Contours] = "Contours"
T6[:TIP_ContoursTitle] = "Method for computing the contours"
T6[:TIP_Contours_face] = "Based on Faces in the Group"
T6[:TIP_Contours_convex] = "Convex Hull"
T6[:TIP_Contours_concave] = "Concave Hull"
T6[:TIP_Contours_best_box] = "Best-Fitting rectangle"

#=============================================================================================
#=============================================================================================
# Class TopoShaperCloudTool: main class for the Interactive tool
#=============================================================================================
#=============================================================================================

class TopoShaperCloudTool < Traductor::PaletteSuperTool

def initialize(action_code, *args)
	#Basic initialization
	@model = Sketchup.active_model
	@tr_id = Geom::Transformation.new
	@rendering_options = @model.rendering_options
	@action_code = action_code
	@old_drawhidden = @rendering_options["DrawHidden"]
	@rendering_options["DrawHidden"] = true
	
	#Parsing the arguments
	args.each { |arg| arg.each { |key, value|  parse_args(key, value) } if arg.class == Hash }

	#Static initialization
	init_cursors
	init_colors
	init_messages

	#Initializing the Key manager
	@keyman = Traductor::KeyManager.new() { |event, key, view| key_manage(event, key, view) }

	#Initializing the Zoom Manager
	@zoom_void = G6::ZoomVoid.new
	
	#Creating the palette manager and texts
	@hsh_bounds = F6_TopoShaper.bounds_param
	#init_palette
	
	#VCB: Initialize VCB
	vcb_init
	
	#Callback when changing default parameters
	MYDEFPARAM.add_notify_proc(self.method("notify_from_defparam"), true)	
end

#INIT: Notification from default parameters
def notify_from_defparam(key, val)
	lst_buttons = [:pal_sharp_borders_title, :pal_sharp_borders2_title, :pal_triangles_title, :pal_details]
	lst_buttons.each do |button|
		@palette.button_refresh_draw button
	end
	@trgul.geometry_change_colors if @trgul
	@view.invalidate
end

#INIT: Parse the arguments of the initialize method
def parse_args(key, value)
	skey = key.to_s
	case skey
	when /from/i
		@invoked_from = value
	end	
end	

#---------------------------------------------------------------------------------------------
# OPTIONS: Option Management and storage
#---------------------------------------------------------------------------------------------
			
#INIT: Initialize texts and messages
def init_messages
	@mnu_exit = T6[:T_BUTTON_Exit]	
	@mnu_abort = T6[:T_STR_AbortTool]
	
	@box_by_step = T6[:BOX_ByStep].sub "|", "\n"
	@tip_sharp_borders = T6[:TIP_SharpBorders]
	@tip_sharp_borders2 = T6[:TIP_SharpBorders2]	
	
	@hsh_tip_navigation = Hash.new " [#{T6[:TIP_NavigationHistory]}]"
	@hsh_tip_navigation[:start_over] = " [#{T6[:TIP_NavigationStartOver]}]"
	@hsh_tip_navigation[:force_compute] = " [#{T6[:TIP_NavigationForceCompute]}]"
	
	@tip_nav_next = T6[:TIP_NavigationNext]
	@tip_nav_auto = T6[:TIP_NavigationAuto]
end

#INIT: Initialize colors
def init_colors
	@pal_bk_color = 'lightblue'
	@pal_hi_color = 'lightgreen'
	@pal_ct_color = 'gold'
	@color_message = 'khaki'
	
	@hsh_boxinfo = {}					 	
	@hsh_boxinfo[:iso] = { :bk_color => 'yellow', :fr_color => 'blue' }					 	
	@hsh_boxinfo[:cloud_point] = { :bk_color => 'lightgrey', :fr_color => 'black' }					 	
	@hsh_boxinfo[:sharp] = { :bk_color => 'moccasin', :fr_color => 'orange' }					 	
	@hsh_boxinfo[:very_sharp] = { :bk_color => 'pink', :fr_color => 'red' }					 	
	@hsh_boxinfo[:tiny_very_sharp] = { :bk_color => 'lightpink', :fr_color => 'tomato' }					 	
	
	@color_iter = 'skyblue'
	@color_info_bk = 'lightblue'
	@color_nav_bk = 'skyblue'
	@color_nav = 'navy'
	@color_nav_disabled = 'white'
	
	@hsh_colors_navigation = Hash.new @color_nav
	@hsh_colors_navigation[:start_over] = 'red'
	@hsh_colors_navigation[:force_compute] = 'green'
	
	@hsh_instructions_navigation = Hash.new []
	@hsh_instructions_navigation[:start_over] = instructions_start_over
	@hsh_instructions_navigation[:force_compute] = instructions_force_compute
	
	@mode_button_next = @mode_button_auto = :start_over
end

#INIT: Initialize cursors
def init_cursors
	@id_cursor_default = Traductor.create_cursor "Cursor_Arrow_Default", 2, 2
	@id_cursor_arrow_exit = Traductor.create_cursor "Cursor_Arrow_Exit", 0, 0	
	@id_cursor_validate = Traductor.create_cursor "Cursor_Validate", 0, 0	
	@id_cursor_hourglass_green = Traductor.create_cursor "Cursor_hourGlass_Green", 16, 16		
	@id_cursor_hourglass_red = Traductor.create_cursor "Cursor_hourGlass_Red", 16, 16		
	@id_cursor = @id_cursor_default
end

#--------------------------------------------------
# Activation / Deactivation
#--------------------------------------------------

#ACTIVATION: Tool activation
def activate
	LibFredo6.register_ruby "TopoShaper::PointCloud"
	Traductor::Hilitor.stop_all_active
	@model = Sketchup.active_model
	@model_current = @model if @model != @model_current
	@selection = @model.selection
	@entities = @model.active_entities
	@view = @model.active_view
		
	#Resetting the environment
	reset_context
	
	#Initializing the palette	
	init_palette

	#Initializing the Executor of Operation
	hsh = { :title => T6[:TIT_CloudOperation], :palette => @palette, :end_proc => self.method('geometry_terminate'),
            :no_commit => true, :info_proc => self.method('geometry_info') }
	@suops = Traductor::SUOperation.new hsh
	@suops.start_operation

	#Handling the initial selection
	handle_initial_selection
	return unless @trgul
		
	@palette.set_tooltip @trgul.stats_info, 'powderblue'	
	@view.invalidate
	show_message
end

#ACTIVATION: Reset context variables and environment
def reset_context
	@button_down = false
	@ph = @view.pick_helper
end

#ACTIVATION: Tool Deactivation
def deactivate(view)
	if @trgul && @trgul.geometry_generated?
		@grp_cloud.visible = true unless !@grp_cloud || @grp_cloud.visible?
		@suops.finish_operation
	else
		@suops.abort_operation
	end	
	selection_at_exit
	@rendering_options["DrawHidden"] = @old_drawhidden
	view.invalidate if @trgul
end

#ACTIVATION: Manage the initial selection or the previous results
def handle_initial_selection
	@old_selection = @selection.to_a.clone
	
	all_ents = (@selection.empty?) ? @entities : @selection
	grp_cloud = nil
	
	#Checking for groups with Guide points
	unless @selection.length > 1 
		grp = @selection[0]
		msg = T6[:MSG_NotValidGroup]
		if G6.is_grouponent?(grp)
			ent = G6.grouponent_entities(grp)
			msg = T6[:MSG_NoPointInGroup]
			if ent.grep(Sketchup::ConstructionPoint).length > 0
				grp_cloud = grp
			end
		end	
	end	
	
	#No group or not valid group
	unless grp_cloud
		abort_tool
		UI.messagebox msg
		return
	end
	
	#Clearing the selection
	@selection.clear
	
	#Analyze the group
	analyze_group grp_cloud
end

#ACTIVATION: Analyze the candidate group
def analyze_group(grp_cloud)
	@grp_cloud = grp_cloud
	
	#Analysing the group
	@grp_entities = G6.grouponent_entities(@grp_cloud)
	@tr = @grp_cloud.transformation
	
	lfaces = @grp_entities.grep(Sketchup::Face)
	
	#Getting the cloud points
	lcpoints = @grp_entities.grep(Sketchup::ConstructionPoint).collect { |cpoint| @tr * cpoint.position }
	
	#Analyzing the effective contours and holes if any
	contours, holes = contour_from_faces(lfaces)
	
	#Creating the Triangulator algo
	hsh = { :suops => @suops }
	@trgul = PointCloudTriangulation.new lcpoints, @tr_id, contours, holes, grp_cloud

	@fac_sharp_borders2 = @trgul.algo_sharp_borders_info_fac2
	@nb_cloud_points = lcpoints.length
end
	
#CONTOUR: Analyze the group for contours and holes	
def contour_from_faces(lfaces)
	return nil if lfaces.empty?
	
	#Finding the normal
	area_max = 0
	facemax = nil
	lfaces.each do |face|
		area = G6.face_area(face, @tr)
		if area > area_max
			facemax = face
			area_max = area
		end	
	end
	normal = G6.transform_vector(facemax.normal, @tr)
	tr_axe = Geom::Transformation.axes ORIGIN, *(normal.axes)
	tinv = @tr * tr_axe.inverse
	
	#Finding the point with lowest altitude
	ptmin = nil
	zmin = nil
	lfaces.each do |face|
		pt = tinv * face.vertices[0].position
		if !zmin || pt.z < zmin
			ptmin = pt
			zmin = pt.z
		end	
	end
	plane = [@tr * tinv.inverse * ptmin, normal]
	
	#Creating a temp group and projecting the faces
	group = @entities.add_group
	gent = group.entities
	lfaces.each do |face|
		face.loops.each_with_index do |loop, iloop|
			pts = loop.vertices.collect { |vx| (@tr * vx.position).project_to_plane(plane) }
			f = gent.add_face pts
			f.erase! if iloop > 0
			f.material = f.back_material = 'red' if iloop == 0
		end
	end	
	
	#Removing all collinear edges
	lerase = gent.grep(Sketchup::Edge).find_all { |e| G6.edge_coplanar?(e) }
	gent.erase_entities lerase unless lerase.empty?
	
	#Getting the contours and holes
	contours = []
	holes = []
	gent.grep(Sketchup::Face).each do |face|
		contours.push face.outer_loop.vertices.collect { |vx| vx.position }
		face.loops[1..-1].each do |loop|
			holes.push loop.vertices.collect { |vx| vx.position }
		end	
	end
	
	#Aborting the operation
	group.erase!	
	
	[contours, holes]
end
	
#ACTIVATION: Set / reset the selection at exit
def selection_at_exit
	top_group = (@trgul) ? @trgul.geometry_top_group : nil
	sel = nil
	if top_group && top_group.valid?
		sel = [top_group]
	elsif @old_selection	
		sel = @old_selection.find_all { |a| a.valid? && a.parent == @model} 
	end	
	@selection.clear
	@selection.add sel if sel && !sel.empty?
end
		
#ACTIVATION: Exit the tool
def exit_tool
	@aborting = false
	@model.select_tool nil
end

#ACTIVATION: Abort the operation and exit
def abort_tool
	if @trgul && @trgul.geometry_generated?
		text = T6[:T_MSG_ConfirmAbortText] + "\n\n" + T6[:T_MSG_ConfirmAbortQuestion]
		if UI.messagebox(text, MB_YESNO) == 6
			return exit_tool
		end	
	end
	@aborting = true
	@suops.abort_operation
	@model.select_tool nil
end

#--------------------------------------------------
# PARAMETERS: Handle parameters and modifications
#--------------------------------------------------

#PARAMETER: Modify the roundness factor
def modify_roundness(roundness)
	@trgul.algo_set_roundness roundness
	generate_change_compute
end

#PARAMETER: Modify the maximum deviation factor
def modify_deviation_max(deviation_max)
	@trgul.algo_set_deviation_max deviation_max
	generate_change_compute
end

#PARAMETER: Modify the maximum deviation factor
def modify_triangles_max(triangles_max)
	@trgul.algo_set_triangles_max triangles_max
	generate_change_compute	
end

#PARAMETER: Modify the delta altitude for the iso-contours
def modify_iso_delta(iso_delta)
	@trgul.geometry_set_iso true, iso_delta
end

def toggle_iso_contour
	@trgul.geometry_toggle_iso
end

def toggle_skirt
	@trgul.geometry_toggle_skirt
end

def modify_skirt_delta(skirt_delta)
	@trgul.geometry_set_skirt true, skirt_delta
end

def toggle_points
	@trgul.geometry_toggle_points
end

def modify_points_style(style)
	@trgul.geometry_set_points true, style
end

def toggle_details
	@grp_cloud.visible = @rendering_options["DrawHidden"] = !@rendering_options["DrawHidden"]
	@view.invalidate
end

def modify_contour_method(hull_method)
	@trgul.contour_modify_method(hull_method, @suops)
end

#PARAMETER: Compute if a change should be enabled
def generate_change_compute	
	@trgul.algo_analyze_param_impact
	palette_refresh_navigation
end
			
#--------------------------------------------------
# Contextual menu
#--------------------------------------------------

#Contextual menu
def getMenu(menu)
	cxmenu = Traductor::ContextMenu.new
		
	#Abort
	if @trgul.geometry_generated?
		cxmenu.add_sepa
		cxmenu.add_item(@mnu_abort) { abort_tool }
	end
	
	#Exit
	cxmenu.add_sepa
	cxmenu.add_item(@mnu_exit) { exit_tool }
	
	#Showing the menu
	cxmenu.show menu
	true
end

#---------------------------------------------------------------------------------------------
# SU TOOL: Mouse Movement Methods
#---------------------------------------------------------------------------------------------

#SU TOOL: Mouse Movements
def onMouseMove_zero(flag=nil) ; onMouseMove(@flags, @xmove, @ymove, @view) if @xmove ; end
def onMouseMove(flags, x, y, view)
	#Event for the palette
	@xmove = x
	@ymove = y
	if super
		@mouse_in_palette = true
		refresh_viewport
		return
	end	
	@mouse_in_palette = false
	
	#Tracking element under mouse
	@trgul.element_under_mouse(flags, x, y, view)
	
	#Synchronize draw and move
	return if @moving
	@moving = true
	
	#Refreshing the view
	refresh_viewport
end	

def onMouseLeave(view)
	@mouseOut = true
	refresh_viewport
end

def onMouseEnter(view)
	@mouseOut = false
	refresh_viewport
end

#MOVE: Before Zooming or changing view
def suspend(view)
	@keyman.reset
	@zoom_void.suspend(view, @xmove, @ymove)
end

#MOVE: After changing view
def resume(view)
	@keyman.reset
	@zoom_void.resume(view)
	refresh_viewport
end

#--------------------------------------------------------------
# VIEWPORT: View Management
#--------------------------------------------------------------

#VIEWPORT: Computing Current cursor
def onSetCursor
	#Palette cursors
	ic = super
	return (ic != 0) if ic
	
	#Cursor for geometry processing
	if @geometry_processing
		@id_cursor = @id_cursor_hourglass_green
	else
		@id_cursor = @id_cursor_default
	end	
			
	#Other cursors depending on state
	UI.set_cursor @id_cursor
end

#VIEWPORT: Refresh the viewport
def refresh_viewport
	onSetCursor
	show_message
	@view.invalidate
end
	
#VIEWPORT: Show message in the palette
def show_message
	return unless @palette
	
	#Mouse if either in the palette or out of the viewport
	if @mouseOut
		@palette.set_message nil 
		return
	elsif @mouse_in_palette
		@palette.set_message @palette.get_main_tooltip, 'aliceblue'
		return
	else	
		@palette.set_message nil unless @trgul && @trgul.geometry_generated?
	end	
	
	text = label = value = ""
	
	#Showing the message in the status bar
	Sketchup.set_status_text label, SB_VCB_LABEL
	Sketchup.set_status_text value, SB_VCB_VALUE
	Sketchup.set_status_text text	
end

#---------------------------------------------------------------------------------------------
# SU TOOL: Click Management
#---------------------------------------------------------------------------------------------

#SU TOOL: Button click DOWN
def onLButtonDown(flags, x, y, view)
	#Interrupting geometry construction if running
	return if @suops.interrupt?

	#Palette management
	return if super
	
	onMouseMove_zero
end

#SU TOOL: Button click UP - Means that we end the selection
def onLButtonUp(flags, x, y, view)
	return if super
	case @mode
	when :selection	

	when :algo, :cleansing

	end	
	@button_down = false
	onMouseMove_zero
end

#SU TOOL: Double Click received
def onLButtonDoubleClick(flags, x, y, view)
	return if super
	view.invalidate
end

#---------------------------------------------------------------------------------------------
# SU TOOL: Keyboard handling
#---------------------------------------------------------------------------------------------

#Return key pressed
def onReturn(view)
	geometry_execute
end

#KEY: Manage key events
def key_manage(event, key, view)
	case event
	
	#SHIFT key
	when :shift_down
		onMouseMove_zero
		
	when :shift_toggle
		toggle_details
	
	when :shift_up
		
	#CTRL key	
	when :ctrl_down	
		onMouseMove_zero

	when :ctrl_up
		onMouseMove_zero

	when :ctrl_other_up
	
	when :ctrl_toggle
	
	#ALT key
	when :alt_down
		
	when :alt_up	
		
	
	#Arrows	
	when :arrow_down	
		case key
		when VK_UP
			geometry_execute if @trgul.generate_enabled?
		when VK_RIGHT
			geometry_execute(true) if @trgul.generate_enabled?
		when VK_LEFT
			geometry_navigate :previous
		when VK_DOWN
			geometry_navigate :reset			
		end
		
	#Backspace	
	when :backspace
		geometry_navigate :previous

	#TAB	
	when :tab
		
		
	when :shift_tab
		
	end
end

#KEY: Handle Key down
def onKeyDown(key, rpt, flags, view)
	ret_val = @keyman.onKeyDown(key, rpt, flags, view)
	onSetCursor
	@view.invalidate
	ret_val
end

#KEY: Handle Key up
def onKeyUp(key, rpt, flags, view)
	ret_val = @keyman.onKeyUp(key, rpt, flags, view)
	onSetCursor
	@view.invalidate
	ret_val
end

#---------------------------------------------------------------------------------------
# UNDO: Undo and Rollback Management
#---------------------------------------------------------------------------------------

#UNDO: Cancel and undo methods
def onCancel(flag, view)
	#Interrupting geometry construction if running
	return if @suops.interrupt?
	
	case flag
	when 1, 2	#Undo or reselect the tool
		handle_undo
	when 0		#user pressed Escape	
		handle_cancel
	end
end

#UNDO: Handle an undo
def handle_undo
	handle_cancel
end

#UNDO: Handle the escape key depending on current mode
def handle_cancel
	@suops.abort_restart_operation
	@trgul.algo_reset
	onMouseMove_zero
end

#---------------------------------------------------------------------------------------------
# SU TOOL: Drawing Methods
#---------------------------------------------------------------------------------------------

#SU TOOL: Draw top method
def draw(view)	
	#Drawing the mesh
	@trgul.draw view if @trgul

	if @trgul && @trgul.geometry_generated?
		@trgul.drawing_sharp_borders view if @rendering_options["DrawHidden"] && !@keyman.ctrl_down?
		drawing_info_picking view
	end
	
	@moving = false
	
	#Drawing the palette
	super
end

#DRAW: Draw the contours and holes
def drawing_info_picking(view)
	info_picking = @trgul.info_picking
	return unless info_picking
	
	type, txt_val = info_picking
	case type
	when :iso
		label = T6[:LABEL_IsoContour]
	when :cloud_point
		label = T6[:LABEL_CloudPoint]
	when :sharp
		label = T6[:LABEL_SharpEdge]
	when :very_sharp
		label = T6[:LABEL_VerySharpEdge]
	when :tiny_very_sharp
		label = T6[:LABEL_TinyVerySharpEdge]
	else
		return
	end	
	text = label + ' ' + txt_val
	G6.draw_rectangle_multi_text view, @xmove, @ymove, text, @hsh_boxinfo[type]
end

#SU TOOL: return the extents for drawing
def getExtents
	@model.bounds
end

#--------------------------------------------------------------
#--------------------------------------------------------------
# Palette Management
#--------------------------------------------------------------
#--------------------------------------------------------------

#---------------------------------------------------------------------
# Creation of the palette
#---------------------------------------------------------------------

#PALETTE: Separator for the Main and floating palette
def pal_separator ;	@palette.declare_separator ; end

#PALETTE: Initialize the main palette and top level method
def init_palette
	hshpal = { :width_message => 120, :width_message_min => 120, :key_registry => :toposhaper }
	@palette = Traductor::Palette.new hshpal
	@draw_local = self.method "draw_button_opengl"
	@blason_proc = self.method "draw_button_blason"
	@symb_blason = :blason
	@bk_color_tool = "lemonchiffon"
	@info_text1 = ""
	@info_text2 = ""
	@info_message = ""
	@color_proc_info = proc { (@trgul.algo_is_finished?) ? nil : @color_info_bk }
		
	#Blason Button
	tip = "TopoShaper" + ' ' + T6[:T_STR_DefaultParamDialog]
	hsh = { :blason => true, :draw_proc => @blason_proc, :tooltip => tip }
	@palette.declare_button(@symb_blason, hsh) { MYPLUGIN.invoke_default_parameter_dialog }
	
	#Parameters
	palette_contour_method
	palette_roundness
	palette_deviation_max
	palette_triangles_max
	palette_navigation
	palette_details
	palette_iso_delta
	palette_skirt
	palette_points
	
	#Abort tool
	pal_separator
	hsh = { :draw_proc => :std_abortexit, :main_color => 'red', :frame_color => 'green', 
	        :tooltip => T6[:T_STR_AbortTool] }
	@palette.declare_button(:pal_abort, hsh) { abort_tool }

	#Rollback
	ssb = :back
	tip = T6[:T_STR_UndoCtrlZ] + " [#{T6[:T_KEY_ESC]}]"
	grayed_proc = proc { !@trgul.geometry_generated? }
	hsh = { :tooltip => tip, :draw_proc => :rollback, :grayed_proc => grayed_proc }
	@palette.declare_button(:pal_back, hsh) { handle_cancel }
	
	#Exit tool
	hsh = { :draw_proc => :std_exit, :tooltip => T6[:T_STR_ExitTool] }
	@palette.declare_button(:pal_exit, hsh) { exit_tool }
		
	#Associating the palette
	set_palette @palette
end

#PALETTE: Button for roundness factor
def palette_roundness
	pal_separator

	#Title button
	title = T6[:BOX_Roundness]
	wid, = G6.simple_text_size(title)
	wid = [70, wid].max
	tip = T6[:TIP_Roundness]
	prompt = T6[:PROMPT_Roundness]

	hsh_dim = { :height => 16, :width => wid }
	hsht = { :passive => true, :text => title, :bk_color => @pal_bk_color, :tooltip => tip, :rank => 1 }
	@palette.declare_button :pal_roundness_title, hsh_dim, hsht
	
	#Input field
	vmin = @hsh_bounds[:roundness_min]
	vmax = @hsh_bounds[:roundness_max]
	hshi = { :vtype => :float, :vprompt => prompt, :vmin => vmin, :vmax => vmax, :vincr => 0.5, :vsprintf => "%2.1f" }
	get_proc = proc { @trgul.algo_roundness }
	set_proc = proc { |val| modify_roundness val }
	input = Traductor::InputField.new hshi, { :get_proc => get_proc, :set_proc => set_proc }
	
	hsh = { :bk_color => 'lightgreen', :input => input, :tooltip => tip }
	@palette.declare_button :pal_roundness_value, hsh_dim, hsh 
end

#PALETTE: Button for Smoothing factor
def palette_deviation_max
	pal_separator

	#Title button
	title = T6[:BOX_DeviationMax]
	wid, = G6.simple_text_size(title)
	wid = wid + 20
	tip = T6[:TIP_DeviationMax]
	prompt = T6[:PROMPT_DeviationMax]

	hsh_dim = { :height => 16, :width => wid }
	hsht = { :passive => true, :text => title, :bk_color => @pal_bk_color, :tooltip => tip, :rank => 1 }
	@palette.declare_button :pal_deviation_max_title, hsh_dim, hsht
	
	#Input field
	vmin = @hsh_bounds[:deviation_max_min]
	vmax = @hsh_bounds[:deviation_max_max]
	hshi = { :vtype => :float, :vprompt => prompt, :vmin => vmin, :vmax => vmax, :vincr => 5, :vsprintf => "%2.0f°" }
	get_proc = proc { @trgul.algo_deviation_max }
	set_proc = proc { |val| modify_deviation_max val }
	input = Traductor::InputField.new hshi, { :get_proc => get_proc, :set_proc => set_proc }
	
	hsh = { :bk_color => 'lightgreen', :input => input, :tooltip => tip }
	@palette.declare_button :pal_deviation_max_value, hsh_dim, hsh 
end

#PALETTE: Button for Max number of triangles
def palette_triangles_max
	pal_separator

	#Title button
	title = T6[:BOX_TriangleMax]
	wid, = G6.simple_text_size(title)
	wid = wid + 20
	tip = T6[:TIP_TriangleMax]
	prompt = T6[:PROMPT_TriangleMax]

	hsh_dim = { :height => 16, :width => wid }
	hsht = { :passive => true, :text => title, :bk_color => @pal_bk_color, :tooltip => tip, :rank => 1 }
	@palette.declare_button :pal_triangles_max_title, hsh_dim, hsht
	
	#Input field
	vmin = @hsh_bounds[:triangles_max_min]
	vmax = @hsh_bounds[:triangles_max_max]
	hshi = { :vtype => :integer, :vprompt => prompt, :vmin => vmin, :vmax => vmax, :vincr => 500, :vsprintf => "%2d" }
	get_proc = proc { @trgul.algo_triangles_max }
	set_proc = proc { |val| modify_triangles_max val }
	input = Traductor::InputField.new hshi, { :get_proc => get_proc, :set_proc => set_proc }
	
	hsh = { :bk_color => 'lightgreen', :input => input, :tooltip => tip }
	@palette.declare_button :pal_triangles_max_value, hsh_dim, hsh 
end

#PALETTE: Information on sharp borders
def palette_navigation
	pal_separator

	hsh_dim = { :width => 32, :height => 32, :draw_proc => @draw_local, :bk_color => @color_nav_bk, :hi_color => @pal_hi_color }
	
	double_click_proc = proc { geometry_navigate :force_start_over }
	grayed_proc = proc { !@trgul.geometry_generated? }
	tip = T6[:TIP_NavigationReset] + " [#{T6[:T_KEY_ArrowDown]}] [#{T6[:TIP_NavigationForceStartOver]}]"
	hsh = { :grayed_proc => grayed_proc, :double_click_proc => double_click_proc, :tooltip => tip }
	@palette.declare_button(:pal_nav_reset, hsh_dim, hsh) { geometry_navigate :reset }

	grayed_proc = proc { !@trgul.history_back_possible? }
	tip = T6[:TIP_NavigationPrevious] + @hsh_tip_navigation[nil] + " [#{T6[:T_KEY_ArrowLeft]}]"
	hsh = { :grayed_proc => grayed_proc, :tooltip => tip }
	@palette.declare_button(:pal_nav_previous, hsh_dim, hsh) { geometry_navigate :previous }

	grayed_proc = proc { !@trgul.algo_generate_enabled? }
	text_proc_iter = proc { "##{@trgul.algo_iteration}" }	
	tip_iter = T6[:TIP_NavigationCurrent]
	hsh = { :grayed_proc => grayed_proc, :text_proc => text_proc_iter, :width => 40, :height => 32, :justif => "MH", 
	        :tooltip => tip_iter, :bk_color => @color_nav_bk }
	@palette.declare_button(:pal_iteration, hsh)

	tip_proc = proc { @tip_nav_next + @hsh_tip_navigation[@mode_button_next] + " [#{T6[:T_KEY_ArrowRight]}]" }
	hsh = { :grayed_proc => grayed_proc, :tip_proc => tip_proc }
	@palette.declare_button(:pal_nav_next, hsh_dim, hsh) { geometry_execute true }
	
	tip_proc = proc { @tip_nav_auto + @hsh_tip_navigation[@mode_button_auto] + " [#{T6[:T_KEY_ArrowUp]}, #{T6[:T_KEY_Enter]}]" }
	hsh = { :grayed_proc => grayed_proc, :tip_proc => tip_proc }
	@palette.declare_button(:pal_nav_auto, hsh_dim, hsh) { geometry_execute }
	
	pal_separator
	palette_triangulation_info
	palette_sharp_borders_info
end

#PALETTE: Refresh the buttons for navigation
def palette_refresh_navigation
	palette_compute_button_navigation(:pal_nav_next)
	palette_compute_button_navigation(:pal_nav_auto)
end

#PALETTE: Calculate the mode for the button
def palette_compute_button_navigation(button)
	start_over, force_compute = @trgul.algo_param_impact
	if start_over
		mode = :start_over
	elsif force_compute || (button == :pal_nav_auto && !@trgul.history_was_finished?)
		mode = :force_compute
	else
		mode = :default
	end
	(button == :pal_nav_auto) ? @mode_button_auto = mode : @mode_button_next = mode
	@palette.button_refresh_draw button
end

#PALETTE: Information on sharp borders
def palette_sharp_borders_info
	tip_proc = proc { dv = @trgul.algo_deviation_max ; @tip_sharp_borders + " [#{dv}° - #{dv * @fac_sharp_borders2}°]" }
	tip_proc2 = proc { @tip_sharp_borders2 + " > #{@trgul.algo_deviation_max * @fac_sharp_borders2}°" }
	
	hsh_dim = { :passive => true, :draw_proc => @draw_local, :width => 24, :height => 16, :bk_color => @color_proc_info }
	hsh = { :tip_proc => tip_proc, :rank => 1 }
	@palette.declare_button(:pal_sharp_borders_title, hsh_dim, hsh) 
	hsh = { :tip_proc => tip_proc2 }
	@palette.declare_button(:pal_sharp_borders2_title, hsh_dim, hsh) 
	
	hsh_dim = { :passive => true, :width => 48, :height => 16, :bk_color => @color_proc_info, :justif => "LH" }
	text_proc = proc { @trgul.algo_sharp_borders_info }
	hsh = { :text_proc => text_proc, :tip_proc => tip_proc, :rank => 1 }
	@palette.declare_button(:pal_sharp_borders_val, hsh_dim, hsh)
	
	text_proc2 = proc { @trgul.algo_sharp_borders2_info }
	hsh = { :text_proc => text_proc2, :tip_proc => tip_proc2 }
	@palette.declare_button(:pal_sharp_borders2_val, hsh_dim, hsh)
end

#PALETTE: Information on sharp borders
def palette_triangulation_info
	hsh_dim = { :passive => true, :width => 24, :height => 16, :draw_proc => @draw_local, :bk_color => @color_proc_info }
	tip_clp = T6[:TIP_NbCloudPoints]
	hsh = { :tooltip => tip_clp, :rank => 1 }
	@palette.declare_button(:pal_cloud_point_title, hsh_dim, hsh) 
	
	tip_tri = T6[:TIP_NbTriangles]
	hsh = { :tooltip => tip_tri }
	@palette.declare_button(:pal_triangles_title, hsh_dim, hsh) 
	
	hsh_dim = { :passive => true, :width => 52, :height => 16, :justif => "LH", :bk_color => @color_proc_info }
	text_proc_iter = proc { "#{@nb_cloud_points}" }	
	hsh = { :text_proc => text_proc_iter, :tooltip => tip_clp, :rank => 1 }
	@palette.declare_button(:pal_cloud_point_val, hsh_dim, hsh)
	
	text_proc_tri = proc { "#{@trgul.geometry_number_faces}" }
	hsh = { :text_proc => text_proc_tri, :tooltip => tip_tri }
	@palette.declare_button(:pal_triangles_val, hsh_dim, hsh)
end

#PALETTE: Button for Isocontours
def palette_iso_delta
	pal_separator

	#Title button
	title = T6[:BOX_IsoContour]
	wid, = G6.simple_text_size(title)
	wid = wid + 20
	tip = T6[:TIP_IsoContourTitle]
	prompt = T6[:TIP_IsoContourVal]

	hsh_dim = { :height => 16, :width => wid }
	value_proc = proc { @trgul.geometry_iso_enabled? }
	hsht = { :value_proc => value_proc, :text => title, :hi_color => 'plum', :tooltip => tip, :rank => 1 }
	@palette.declare_button(:pal_iso_delta_title, hsh_dim, hsht) { toggle_iso_contour }
	
	#Input field
	hshi = { :vtype => :len, :vprompt => prompt }
	get_proc = proc { @trgul.geometry_iso_delta? }
	set_proc = proc { |val| modify_iso_delta val }
	show_proc = proc { |val| Sketchup.format_length val }
	input = Traductor::InputField.new hshi, { :get_proc => get_proc, :set_proc => set_proc, :show_proc => show_proc }
	
	hsh = { :bk_color => 'lightgreen', :input => input, :tooltip => T6[:TIP_IsoContourVal] }
	@palette.declare_button :pal_iso_delta_value, hsh_dim, hsh 
end

#PALETTE: Generation of the Skirt
def palette_skirt
	pal_separator
	
	#Title button
	title = T6[:BOX_Skirt]
	wid, = G6.simple_text_size(title)
	wid = wid + 20

	tip = T6[:TIP_OptionGeometryWall]
	hsh_dim = { :height => 16, :width => wid }
	value_proc = proc { @trgul.geometry_skirt_enabled? }
	hsht = { :value_proc => value_proc, :text => title, :hi_color => 'plum', :tooltip => tip, :rank => 1 }
	@palette.declare_button(:pal_skirt_title, hsh_dim, hsht) { toggle_skirt }

	#Input field
	prompt = T6[:TIP_SkirtDelta]
	hshi = { :vtype => :integer, :vprompt => prompt, :vsprintf => "%2d%" }
	get_proc = proc { @trgul.geometry_skirt_delta? }
	set_proc = proc { |val| modify_skirt_delta val }
	input = Traductor::InputField.new hshi, { :get_proc => get_proc, :set_proc => set_proc }
	
	hsh = { :bk_color => 'lightgreen', :input => input, :tooltip => T6[:TIP_SkirtDelta] }
	@palette.declare_button :pal_skirt_value, hsh_dim, hsh 

end

#PALETTE: Generation of the Skirt
def palette_points
	pal_separator
	
	#Title button
	symb_master = :pal_points
	title = T6[:BOX_Points]
	wid, = G6.simple_text_size(title)
	wid = [wid + 20, 32].max / 2

	tip = T6[:TIP_PointsTitle]
	hsh_dim = { :type => 'multi_free', :height => 16, :width => wid }
	value_proc = proc { @trgul.geometry_points_enabled? }
	hsht = { :value_proc => value_proc, :text => title, :hi_color => 'plum', :tooltip => tip }
	@palette.declare_button(symb_master, hsh_dim, hsht) { toggle_points }

	#Option buttons
	hshc = { :parent => symb_master, :draw_proc => @draw_local, :width => wid, :hi_color => @pal_hi_color }
	
	value_proc = proc { @trgul.geometry_points_style? == :only }
	hsh = { :value_proc => value_proc, :tooltip => T6[:TIP_PointsOnly] }
	@palette.declare_button(:pal_points_only, hshc, hsh) { modify_points_style :only }

	value_proc = proc { @trgul.geometry_points_style? == :line }
	hsh = { :value_proc => value_proc, :tooltip => T6[:TIP_PointsLine] }
	@palette.declare_button(:pal_points_line, hshc, hsh) { modify_points_style :line }

end

#PALETTE: Generation of the Skirt
def palette_contour_method
	pal_separator
	
	#Title button
	symb_master = :pal_contour
	title = T6[:BOX_Contours]
	wid, = G6.simple_text_size(title)
	wid = [(wid + 20)/4, 24].max
	
	tip = T6[:TIP_ContoursTitle]
	hsh_dim = { :type => 'multi_free', :height => 16, :width => wid }
	hsht = { :passive=> true, :text => title, :bk_color => @pal_ct_color, :tooltip => tip }
	@palette.declare_button(symb_master, hsh_dim, hsht)

	#Option buttons
	hshc = { :parent => symb_master, :draw_proc => @draw_local, :width => wid, :hi_color => @pal_ct_color }
	
	[:face, :convex, :concave, :best_box].each do |symb|
		palette_contour_method_button(symb_master, hshc, symb)
	end
end

#PALETTE: Buttons for contours option
def palette_contour_method_button(symb_master, hshc, symb)
	hidden_proc = (symb == :face) ? proc { @trgul.no_contour_face } : nil
	tip = T6["TIP_Contours_#{symb}".intern]
	value_proc = proc { @trgul.contour_hull_method == symb }
	hsh = { :hidden_proc => hidden_proc, :value_proc => value_proc, :tooltip => tip }
	@palette.declare_button("#{symb_master}_#{symb}".intern, hshc, hsh) { modify_contour_method symb }
end

#PALETTE: Button for details
def palette_details
	pal_separator
	
	tip = T6[:TIP_ShowDetails] + " [#{T6[:T_KEY_ShiftToggle]}]"
	value_proc = proc { @rendering_options["DrawHidden"] }
	hsh = { :value_proc => value_proc, :tooltip => tip, :hi_color => @pal_hi_color, :draw_proc => @draw_local }
	@palette.declare_button(:pal_details, hsh) { toggle_details }
end

#PALETTE: Drawing the Blason
def draw_button_blason(symb, dx, dy)
	lst_gl = []
	dx2 = dx/2
	dy2 = dy/2
	dym = dy * 3 / 4
	dyb = dym-4
	
	lip = [[6, 8], [15, 15], [18, 25], [26, 20], [8, 22]]
	
	lines = []
	lip.each do |x, y|
		lines.concat G6.pts_cross(x, y, 3)
	end	
	lst_gl.push [GL_LINES, lines, 'blue', 1, '']
		
	pts = G6.pts_triangle 20, 9, 4
	lst_gl.push [GL_LINE_LOOP, pts, 'red', 2, '']
	
	lst_gl
end

#PALETTE: Compute instructions for compute
def instructions_force_compute
	lst_gl = []
	dx = dy = 32
	dx2 = dx /2
	dy2 = dy /2
	radius = 3
	radius2 = 2
	center = Geom::Point3d.new dx2-5, dy2-2
	
	bkcolor = 'lightgreen'
	frcolor = 'gray'
	pts = G6.pts_circle center.x, center.y, radius, 8
	lines = []
	pts.each do |pt|
		lines.push pt, pt.offset(center.vector_to(pt), radius2)
	end
	lst_gl.push [GL_POLYGON, pts, bkcolor]
	lst_gl.push [GL_LINE_LOOP, pts, frcolor, 1, '']
	lst_gl.push [GL_LINES, lines, bkcolor, 2, '']
	lst_gl
end

#PALETTE: Compute instructions for compute
def instructions_start_over
	lst_gl = []
	dx = dy = 32
	dx2 = dx /2
	dy2 = dy /2
	radius = 4
	center = Geom::Point3d.new dx2-5, dy2-2
	
	bkcolor = 'pink'
	frcolor = 'gray'
	pts = G6.pts_triangle center.x, center.y, radius, X_AXIS.reverse
	lst_gl.push [GL_POLYGON, pts, bkcolor]
	lst_gl.push [GL_LINE_LOOP, pts, frcolor, 1, '']
	pt1 = pts[2].offset Y_AXIS, 6
	pt2 = pts[2].offset Y_AXIS, -6
	lst_gl.push [GL_LINE_STRIP, [pt1, pt2], bkcolor, 3, '']
	lst_gl.push [GL_LINE_STRIP, [pt1, pt2], frcolor, 1, '']
	lst_gl
end

#--------------------------------------------------------------
# Custom drawing for palette buttons
#--------------------------------------------------------------

#PALETTE: Custom drawing of buttons
def draw_button_opengl(symb, dx, dy, main_color, frame_color, selected, grayed)
	code = symb.to_s
	lst_gl = []
	dx2 = dx / 2
	dy2 = dy / 2
	grayed = @palette.button_is_grayed?(symb)
	color = (grayed) ? 'gray' : frame_color
	
	case code

	when /skirt/i
		lpi = [[dx, dy-8], [dx-5, dy-3], [dx2, dy], [5, dy-1], [1, dy-5]]
		lpti = lpi.collect { |a| Geom::Point3d.new *a }
		pts = [[1, 1], [dx, 1]].collect { |a| Geom::Point3d.new *a } + lpti
		lst_gl.push [GL_POLYGON, pts, 'sandybrown']
		lst_gl.push [GL_LINE_LOOP, pts, 'gray', 1, '']
		pts = []
		lpti.each_with_index { |pt, i| pts.push pt, Geom::Point3d.new(lpti[i].x, 1) }
		lst_gl.push [GL_LINES, pts, 'gray', 1, '']
	
	when /pal_sharp_borders2/
		dec = dx / 5
		lpi = [[dec, 0], [dx2, dy], [dx-dec, 0]]
		pts = lpi.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_LINE_STRIP, pts, MYDEFPARAM[:TPS_ColorVerySharp], 3, '']
		
	when /pal_sharp_borders/
		dec = 1
		lpi = [[dec, 0], [dx2, dy], [dx-dec, 0]]
		pts = lpi.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_LINE_STRIP, pts, MYDEFPARAM[:TPS_ColorSharp], 2, '']

	when /pal_triangles_title/
		pts = G6.pts_triangle dx2, dy2, 5
		lst_gl.push [GL_POLYGON, pts, MYDEFPARAM[:TPS_ColorTerrain]]
		lst_gl.push [GL_LINE_LOOP, pts, 'gray', 2, '']
		
	when /pal_cloud_point_title/
		pts = G6.pts_cross dx2, dy2, 4
		lst_gl.push [GL_LINES, pts, 'blue', 2, '']

	when /pal_nav_previous/
		color = (grayed) ? @color_nav_disabled : @color_nav
		dec = 4
		lpi = [[dx-dec, 1], [dx-dec, dy-1], [dec, dy2]]
		pts = lpi.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_POLYGON, pts, color]
		lst_gl.push [GL_LINE_LOOP, pts, 'gray', 1, '']
		
	when /pal_nav_reset/
		color = (grayed) ? @color_nav_disabled : @color_nav
		dec = 4
		lpi = [[dx-dec, 1], [dx-dec, dy-1], [dec, dy2]]
		pts = lpi.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_POLYGON, pts, color]
		lst_gl.push [GL_LINE_LOOP, pts, 'gray', 1, '']
		lpi = [[0, 1], [dec, 1], [dec, dy-1], [0, dy-1]]
		pts = lpi.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_POLYGON, pts, color]
		lst_gl.push [GL_LINE_LOOP, pts, 'gray', 1, '']
		
	when /pal_nav_next/
		color = (grayed) ? @color_nav_disabled : @hsh_colors_navigation[@mode_button_next]
		dec = 4
		lpi = [[dec, 1], [dec, dy-1], [dx-dec, dy2]]
		pts = lpi.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_POLYGON, pts, color]
		lst_gl.push [GL_LINE_LOOP, pts, 'gray', 1, '']
		lst_gl.concat @hsh_instructions_navigation[@mode_button_next] unless grayed || @trgul.algo_iteration == 0
		
	when /pal_nav_auto/
		color = (grayed) ? @color_nav_disabled : @hsh_colors_navigation[@mode_button_auto]
		dec = 4
		lpi = [[dec, 1], [dec, dy-1], [dx-dec, dy2]]
		pts = lpi.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_POLYGON, pts, color]
		lst_gl.push [GL_LINE_LOOP, pts, 'gray', 1, '']
		lpi = [[dx-dec, 1], [dx, 1], [dx, dy-1], [dx-dec, dy-1]]
		pts = lpi.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_POLYGON, pts, color]
		lst_gl.push [GL_LINE_LOOP, pts, 'gray', 1, '']
		lst_gl.concat @hsh_instructions_navigation[@mode_button_auto] unless grayed || @trgul.algo_iteration == 0
	
	when /points_only/	
		pts = G6.pts_cross dx2, dy2, 3
		lst_gl.push [GL_LINES, pts, 'gray', 2, '']

	when /points_line/	
		pts = G6.pts_cross dx2, dy-3, 3
		lst_gl.push [GL_LINES, pts, 'gray', 2, '']
		pt1 = Geom::Point3d.new dx2, dy-3
		pt2 = Geom::Point3d.new dx2, 0
		lst_gl.push [GL_LINE_STRIP, [pt1, pt2], 'gray', 2, '-']

	when /pal_details/	
		color_very_sharp = MYDEFPARAM[:TPS_ColorVerySharp]
		color_sharp = MYDEFPARAM[:TPS_ColorSharp]
		lpi1 = [[1, 1], [dx2-2, dy2+2], [dx2+2, 2]]
		pts1 = lpi1.collect { |a| Geom::Point3d.new *a }
		pts_very_sharp = [pts1[0], pts1[1]]
		lst_gl.push [GL_LINE_LOOP, pts1, 'gray', 1, '-']
		lpi2 = [[dx2-2, dy2+2], [1, dy], [2, dy2]]
		pts2 = lpi2.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_LINE_LOOP, pts2, 'gray', 1, '-']
		lst_gl.push [GL_LINE_STRIP, [pts2.last, pts1.first], 'gray', 1, '-']
		pts3 = [pts2[0], pts2[1], Geom::Point3d.new(dx, dy-2)]
		pts_sharp = [pts2[0], pts2[1]]
		lst_gl.push [GL_LINE_LOOP, pts3, 'gray', 1, '-']
		lst_gl.push [GL_LINE_STRIP, [pts3.last, pts1.last], 'gray', 1, '-']
		lst_gl.push [GL_LINE_STRIP, pts_sharp, color_sharp, 2, '']
		lst_gl.push [GL_LINE_STRIP, pts_very_sharp, color_very_sharp, 2, '']
	
	when /pal_contour_(.+)/
		method = $1
		case method
		when /best_box/
			pts = G6.pts_rectangle 0, 0, dx-1, dy-1
			lst_gl.push [GL_LINE_LOOP, pts, 'red', 2, '']
		when /face/
			color = 'gray'
			lpi = [[1, 1], [dx2-1, 1], [dx2-1, dy-1], [5, dy-1], [1, dy-5]]
			pts = lpi.collect { |a| Geom::Point3d.new *a }
			lst_gl.push [GL_POLYGON, pts, color]
			lst_gl.push [GL_LINE_LOOP, pts, 'red', 2, '']
			lpi = [[dx2+1, 1], [dx-5, 1], [dx-1, 5], [dx-1, dy-1], [dx2+1, dy-1]]
			pts = lpi.collect { |a| Geom::Point3d.new *a }
			lst_gl.push [GL_POLYGON, pts, color]
			lst_gl.push [GL_LINE_LOOP, pts, 'red', 2, '']
		when /convex/
			lpi = [[1, 1], [dx-5, 1], [dx-1, 5], [dx-1, dy-1], [5, dy-1], [1, dy-5]]
			pts = lpi.collect { |a| Geom::Point3d.new *a }
			lst_gl.push [GL_LINE_LOOP, pts, 'red', 2, '']
		when /concave/
			lpi = [[1, 1], [dx-5, 1], [dx-1, 5], [dx-1, dy-1], [dx2, dy-5], [1, dy-1]]
			pts = lpi.collect { |a| Geom::Point3d.new *a }
			lst_gl.push [GL_LINE_LOOP, pts, 'red', 2, '']
			
		end	
		
		unless method =~ /face/
			pt1 = Geom::Point3d.new 3, 3
			pt2 = Geom::Point3d.new dx-3, dy2
			[pt1, pt2].each do |pt|
				pts = G6.pts_cross pt.x, pt.y, 2
				lst_gl.push [GL_LINES, pts, 'gray', 1, '']
			end	
		end
		
	end	#case code
	
	lst_gl
end

#---------------------------------------------------------------------------------------------
# VCB: VCB Management
#---------------------------------------------------------------------------------------------

#VCB: Enable or disable the VCB
def enableVCB?
	true
end

#VCB: Initialize VCB
def vcb_init
	@vcb = Traductor::VCB.new
	@vcb.declare_input_format :angle, "a"		#deviation max
	@vcb.declare_input_format :multiple, "f"	#all values
end

#VCB: Handle VCB input
def onUserText(text, view)
	action_from_VCB if @vcb.process(text, @palette)
end

#VCB: Execute actions from the VCB inputs	
def action_from_VCB
	devmax = multiple = nil
	@vcb.each_result do |symb, val, suffix|
		case symb
		when :angle
			devmax = val
		when :multiple
			multiple = val
		end
	end
	
	#Checking and updating the parameter
	devmax_min = @hsh_bounds[:deviation_max_min]
	devmax_max = @hsh_bounds[:deviation_max_max]
	
	deviation_max = roundness = triangles_max = nil
	if devmax && devmax >= devmax_min && devmax <= devmax_max
		deviation_max = devmax
		modify_deviation_max deviation_max
	elsif multiple
		if multiple >= @hsh_bounds[:roundness_min] && multiple <= @hsh_bounds[:roundness_max]
			roundness = multiple
			modify_roundness roundness
		elsif multiple >= devmax_min && multiple <= devmax_max
			deviation_max = multiple
			modify_deviation_max deviation_max
		elsif multiple >= @hsh_bounds[:triangles_max_min] && multiple <= @hsh_bounds[:triangles_max_max]
			triangles_max = multiple
			modify_triangles_max triangles_max
		else
			UI.beep
		end	
	end
end	

#---------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------
# GEOMETRY: Generation of Geometry
#---------------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------

#GEOMETRY: Execute the generation of Terrain geometry
def geometry_execute(by_step=false)
	@geometry_processing = true
	onSetCursor
	#@suops.abort_restart_operation
	
	#Launching the execution
	@trgul.algo_top_execute @suops, by_step
end

#GEOMETRY: Notification of the Termination of the geometry
def geometry_terminate(time)
	@geometry_processing = false
	if time
		@message_palette = "#{T6[:VGBAR_TIT_TimeCalculation]} #{sprintf("%0.2f", time)} s"
	end
	generate_change_compute
	onMouseMove_zero
	onSetCursor
end

#GEOMETRY: Navigate within history
def geometry_navigate(symb)	
	if symb == :force_start_over
		@trgul.force_start_over
		palette_refresh_navigation
		return
	end	
	return if (symb == :reset || symb == :previous) && @trgul.algo_iteration == 0
	@geometry_processing = true
	onSetCursor
	
	@trgul.history_execute(@suops, symb)
end

def geometry_info
	"#{@trgul.geometry_number_faces} Faces"
end

end	#class TopoShaperCloudTool

end	#End Module F6_TopoShaper
