=begin
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
# Copyright 2012 - Designed April 2012 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			:   CurvizardAlgo.rb
# Original Date	:   21 Apr 2012 - version 1.0
# Description	:   Manage the Algorithms for Curvizard
#-------------------------------------------------------------------------------------------------------------------------------------------------
#*************************************************************************************************
=end

module F6_Curvizard

T6[:TIP_AngleSimplify] = "Maximum angle for contour Simplification (in degree)"	
T6[:TIP_AngleSmooth] = "Average angle for contour Smoothing (in degree)"	
T6[:TIP_CreateGuidePoints] = "Create guide Points at each vertex"	
T6[:BOX_NumSeg] = "Nb Segments"	
T6[:TIP_NumSeg] = "Number of segments for the generated contour"	
T6[:PROMPT_NumSeg] = "Number of segments"	
T6[:TIP_OptimizeVertices] = "Optimize placement of vertices: smoother rounding and less vertices on flat sections"
T6[:TIP_SmoothBySection] = "Smooth by section - Preserve contour shape where adjacent collinear vertices surround an angle"
T6[:TIP_RemoveCollinear] = "Ignore collinear edges"
T6[:TIP_RemoveSpikes] = "Ignore small spikes"
T6[:TIP_SmoothMethod_BSpline] = "Approximation by B-Spline - curve inside original contour"
T6[:TIP_SmoothMethod_FSpline] = "Fitting by Fit-Spline - curve outside original contour"
T6[:TIP_SmoothMethod] = "Smooth method"

T6[:VBAR_Step_explode_curves] = "Preparation - Analyze curves"
T6[:VBAR_Step_cleanup] = "Postprocessing - Cleanup"
T6[:VBAR_Step_make_curve] = "Postprocessing - making curves"
T6[:VBAR_Step_dessin] = "Preparing Display"

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class Algo_Generic: Generic parent class for Algo
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class Algo_Generic

def initialize(plugin_symb, hsh_options_from_registry, notify_proc)
	@plugin_symb = plugin_symb
	@plugin_info = F6_Curvizard.plugin_info[plugin_symb]
	@plugin_title = T6[@plugin_info[:symb_mnu]]
	@hsh_options = {}
	@notify_proc = notify_proc
	@hsh_params = {}
	@hspecs_options = {}
	@vbar_notify_proc = self.method "vbar_notify"
	@vbar_reshaping_steps = [:explode_curves, :transform_before, :cleanup, :make_curve]
	@color_but_title = 'lightblue'
	@color_but_on = 'lightgreen'
	@color_but_value = 'lightgreen'
	@draw_common = self.method "common_opengl"	
	@rendering_options = Sketchup.active_model.rendering_options
	
	#Configuring the options and VCB
	@lst_options = []
	configure
	for i in 0..@lst_options.length-1
		hsh = @lst_options[i]
		symb = hsh[:symb]
		@lst_options[i] = hsh = check_builtin_options(hsh)
		@hspecs_options[symb] = hsh
		@hsh_options[symb] = (hsh_options_from_registry.has_key?(symb)) ? hsh_options_from_registry[symb] : hsh[:default]
		@hsh_options[symb] = 4 if hsh[:type] == :powermeter && @hsh_options[symb].class != Fixnum
	end
	init_VCB
	
end

#Default placeholder methods
def activating ; end
def deactivating ; end
def draw_button_opengl(symb, dx, dy, main_color, frame_color, selected) ; end

#----------------------------------------------------------------------------------------
# GENERIC: VCB and Param management
#----------------------------------------------------------------------------------------

def get_hparams ; @hsh_params ; end
def get_hoptions ; @hsh_options ; end

#GENERIC: VCB Management placeholders
def get_VCB ; @vcb ; end

def show_VCB
	Sketchup.set_status_text @label_vcb, SB_VCB_LABEL
	if @vcb
		ls = []
		@hspecs_options.each do |symb, hspecs|
			input = hspecs[:input]
			ls.push input.compute_show_vcb if input
		end
		Sketchup.set_status_text ls.join("  "), SB_VCB_VALUE
	else
		Sketchup.set_status_text "", SB_VCB_VALUE
	end	
end

#GENERIC: Parsing the VCB inputs
def parse_VCB(vcb)
	vcb.each_result do |symb, val, suffix|
		next unless @specs_vcb.include?(symb)
		set_option symb, val
	end	
end

#SIMPLIFY: Declare vcb formats
def init_VCB
	@label_vcb = ""
	@specs_vcb = []
	return unless @lst_options
	@hspecs_options.each do |symb, hspecs|
		vcb_format = hspecs[:vcb_format]
		next unless vcb_format
		vcb_format = [vcb_format] unless vcb_format.class == Array
		vcb_format.each do |a|
			@vcb = Traductor::VCB.new unless @vcb
			@vcb.declare_input_format symb, a
		end
		@specs_vcb.push symb
	end
	
	n = @specs_vcb.length
	if n == 1
		tit = @hspecs_options[@specs_vcb[0]][:title]
		@label_vcb = tit if tit
	elsif n > 1
		@label_vcb = "Options"
	end		
end

#----------------------------------------------------------------------------------------
# GENERIC: Visual bar management
#----------------------------------------------------------------------------------------

#VBAR: Manage progression and mini progression
def vbar_progression(state, ik, nk)
	if ik == 0
		vbar_ratio = @hsh_steps[state] / @nbsteps
		text = (state == :transform_before) ? @plugin_title : T6["VBAR_Step_#{state}".intern]
		@vbar.progression vbar_ratio, text
	end	
	@vbar.mini_progression(ik * 1.0 / nk, 1.0 / @nbsteps) if nk
end

#VBAR: Notification method
def vbar_notify(state, ik=nil, nk=nil)
	case state
	when :init
		#Starting the Visual Bar
		delay = (ik && ik > 30) ? 0 : 0.5
		hsh = { :delay => delay, :mini_delay => 0.5 }
		@vbar = Traductor::VisualProgressBar.new @plugin_title, hsh
		@vbar.start
		lst_steps = @lst_steps + [:dessin]
		@nbsteps = lst_steps.length
		@hsh_steps = {}
		lst_steps.each_with_index { |step, ik| @hsh_steps[step] = ik * 1.0 }
	when :transform_after
		#do nothing
	when :end
		@vbar.stop
	else
		vbar_progression state, ik, nk
	end	
end

#----------------------------------------------------------------------------------------
# GENERIC: Palette Management
#----------------------------------------------------------------------------------------

#PALETTE: contribution for value fields
def contribute_palette(palette)
	return unless @lst_options
	
	#Creating the palette helper
	draw_local = self.method("draw_button_opengl")
	hsh = { :get_option_proc => self.method("get_option"), :set_option_proc => self.method("set_option"),
	        :toggle_option_proc => self.method("toggle_option"), :draw_local_proc => draw_local }
	pal_helper = Traductor::PaletteHelper.new palette, "pal_#{@plugin_symb}", hsh
	
	#Processing the instructions for creating contributing buttons
	pal_helper.process_contribution @lst_options	
end

#PALETTE: Custom drawing of buttons
def common_opengl(symb, dx, dy, main_color, frame_color, selected)
	code = symb.to_s
	lst_gl = []
	dx2 = dx / 2
	dy2 = dy / 2
	
	case code			
	when /keep/
	end
	lst_gl
end
		
#----------------------------------------------------------------------------------------
# GENERIC: Option Management
#----------------------------------------------------------------------------------------

#OPTION: get the value of an option
def get_option(symb)
	@hsh_options[symb]
end

#OPTION: set the value of an option
def set_option(symb, val)
	val = verify_option symb, val
	return if @hsh_options[symb] == val
	@hsh_options[symb] = val
	@notify_proc.call :set_option
end

#OPTION: toggle the value of an option
def toggle_option(symb)
	@hsh_options[symb] = !@hsh_options[symb]
	@notify_proc.call :set_option
end

#OPTION: Verify option
def verify_option(symb, val)
	hsh = @hspecs_options[symb]
	return val unless hsh
	
	newval = val
	case hsh[:type]
	when :integer, :float
		vmin = hsh[:vmin]
		vmax = hsh[:vmax]
		if vmin && val < vmin
			newval = vmin
		elsif vmax && val > vmax
			newval = vmax
		end	
		
	end	
	newval
end

#OPTION: Fill built-in specifications for commonly-used options
def check_builtin_options(hoptions)
	symb = hoptions[:symb]
	return {} unless symb
	
	case symb
	when :make_curve
		hsh = { :type => :bool, :default => true, :draw_proc => :std_MakeCurve, :tooltip => T6[:T_STR_MakeSUCurve] }
	when :remove_spikes
	    hsh = { :type => :powermeter, :default => 3, :tooltip => T6[:TIP_RemoveSpikes], :draw_proc => :contour_remove_spikes }
	when :contour_gen_mode
	    hsh = { :type => :contour_gen_mode, :default => :erase }	
	when :remove_collinear	
		hsh = { :type => :bool, :default => false, :tooltip => T6[:TIP_RemoveCollinear], :draw_proc => :contour_remove_collinear }
	else
		hsh = {}
	end

	hsh.clone.update hoptions
end

#OPTION: Map options for Hash array specifications
def map_option(*args)
	hsh = {}
	args.each do |a|
		if a.class == Array
			hsh[a[0]] = get_option a[1]
		else
			hsh[a] = get_option a
		end	
	end
	hsh
end

end	#class Algo_Generic

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class Algo_make_curve: MAKE CURVE Algorithm
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
class Algo_make_curve < Algo_Generic

#MAKE_CURVE: Class instance initialization
def configure
	@hsh_params = { :hi_display => :arrow, :hi_stipple => '', :hi_width => 2, :hi_color_scheme =>  ['red', 'darkred'],
                    :draw_proc => :std_MakeCurve }
	@lst_steps = [:transform_before]
end

#MAKE_CURVE: Top level call for geometry generation
def execute_geometry(lst_info_contours)
	results_info = []
	n = lst_info_contours.length
	lst_info_contours.each_with_index do |info, ik|
		vbar_notify :transform_before, ik, n
		lvx, ledges, tr, parent = info
		entities = G6.grouponent_entities(parent)
		curves = G6.contour_make_curve lvx, entities
		results_info.push [curves.collect { |curve| curve.vertices }, parent, tr] if curves
		vbar_notify :transform_after, ik
	end
	results_info
end

end	#class Algo_make_curve

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class Algo_explode_curve: EXPLODE CURVE Algorithm
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
class Algo_explode_curve < Algo_Generic

#EXPLODE: Class instance initialization
def configure
	@hsh_params = { :hi_display => :dot, :hi_stipple => '-.-', :hi_color_scheme =>  ['magenta', 'purple', 'pink'], :hi_width => 2 }
	@lst_steps = [:prepare, :transform_before]
end

#EXPLODE: Custom drawing of buttons
def draw_button_opengl(symb, dx, dy, main_color, frame_color, selected)
	code = symb.to_s
	lst_gl = []
	dx2 = dx / 2
	dy2 = dy / 2
	
	case code
	when /explode_curve/
		pts = G6.pts_circle dx2, dy2, dx * 0.35
		lst_gl.push [GL_POLYGON, pts, 'slategray']
		lst_gl.push [GL_LINE_LOOP, pts, 'seashell', 1, '']
		pts = G6.pts_circle dx2-2, dy2-2, 3
		lst_gl.push [GL_POLYGON, pts, 'lightgrey']
		pts = []
		pts.push Geom::Point3d.new(dx2, dy * 2 / 3)
		pts.push Geom::Point3d.new(dx2+3, dy-1)
		lst_gl.push [GL_LINE_STRIP, pts, 'seashell', 4, '']
		lst_gl.push [GL_LINE_STRIP, pts, 'slategray', 2, '']
	end
	lst_gl
end

#EXPLODE: Top level call for geometry generation
def execute_geometry(lst_info_contours)
	#Gathering the curves in the selected edges
	hcurves = {}
	n = lst_info_contours.length
	lst_info_contours.each_with_index do |info, ik|
		vbar_notify :prepare, ik, n
		lvx, ledges, tr, parent = info
		ledges.each do |e| 
			curve = e.curve
			next unless curve
			key = "#{curve.entityID}-#{parent.entityID}"
			hcurves[key] = [curve, parent, tr] unless hcurves[key]
		end	
	end
	
	#Registering the curves vertices
	results_info = []
	hcurves.each do |key, info|
		curve, parent, tr = info
		results_info.push [[curve.vertices], parent, tr] if curve
	end	
	
	#Exploding the curves
	n = hcurves.length
	ik = 0
	hcurves.each do |key, info|
		vbar_notify :transform_before, ik, n
		curve, = info
		curve.edges[0].explode_curve if curve.valid?
		ik += 1
	end	
	
	results_info
end

end	#class Algo_explode_curve

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class Algo_edge_prop: EDGE PROP Algorithm
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
class Algo_edge_prop < Algo_Generic

#EDGE_PROP: Class instance initialization
def configure
	@lst_options = [ 
		{ :symb => :edge_properties, :type => :edge_prop_extended, :default => {} }
	]
	@lst_steps = [:transform_before]
end

def activating
	@old_drawhidden = @rendering_options["DrawHidden"]
	@rendering_options["DrawHidden"] = true
end

def deactivating
	@rendering_options["DrawHidden"] = @old_drawhidden
end
	
#EDGE_PROP: Custom drawing of buttons
def draw_button_opengl(symb, dx, dy, main_color, frame_color, selected)
	code = symb.to_s
	lst_gl = []
	
	case code
	when /edge_prop/
		y4 = dy / 4
		lst_gl.push [GL_LINE_STRIP, [Geom::Point3d.new(1, 1), Geom::Point3d.new(dx-1, 1)], 'blue', 2, '']
		y = y4 + 2
		lst_gl.push [GL_LINE_STRIP, [Geom::Point3d.new(1, y), Geom::Point3d.new(dx-1, y)], 'blue', 2, '-']
		y = 2 * y4 + 3
		lst_gl.push [GL_LINE_STRIP, [Geom::Point3d.new(1, y), Geom::Point3d.new(dx-1, y)], 'blue', 2, '-.-']
		y = dy - 1
		lst_gl.push [GL_LINE_STRIP, [Geom::Point3d.new(1, y), Geom::Point3d.new(dx-1, y)], 'blue', 2, '.']
	end
	lst_gl
end

#EDGE_PROP: Top level call for geometry generation
def execute_geometry(lst_info_contours)
	results_info = []
	hprop = get_option :edge_properties
	soft = hprop[:soft]
	smooth = hprop[:smooth]
	hidden = hprop[:hidden]
	cast = hprop[:cast_shadows]
	
	#Gathering the curves in the selected edges
	n = lst_info_contours.length
	lst_info_contours.each_with_index do |info, ik|
		vbar_notify :transform_before, ik, n
		lvx, ledges, tr, parent = info
		results_info.push [[lvx], parent, tr]
		ledges.each do |e| 
			if soft == 1 ; e.soft = true ; elsif soft == -1 ; e.soft = false ; end
			if smooth == 1 ; e.smooth = true ; elsif smooth == -1 ; e.smooth = false ; end
			if hidden == 1 ; e.hidden = true ; elsif hidden == -1 ; e.hidden = false ; end 
			if cast == 1 ; e.casts_shadows = true ; elsif cast == -1 ; e.casts_shadows = false ; end
		end	
	end
	
	results_info
end

end	#class Algo_edge_prop

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class Algo_cleanup_curve: CLEANUP CURVE Algorithm
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
class Algo_cleanup_curve < Algo_Generic

#CLEANUP: Class instance initialization
def configure
	@hsh_params = { :hi_display => :dot, :hi_stipple => '', :hi_color_scheme =>  ['cyan', 'darkturquoise'], :hi_label => :nb_seg }
	@lst_options = [ 
	    { :symb => :remove_collinear, :default => true },  
	    { :symb => :remove_spikes, :default => 4 },  
	    { :symb => :contour_gen_mode},
		{ :symb => :make_curve }
	]
	@lst_steps = @vbar_reshaping_steps
end

#CLEANUP: Custom drawing of buttons
def draw_button_opengl(symb, dx, dy, main_color, frame_color, selected)
	code = symb.to_s
	lst_gl = []
	dx2 = dx / 2
	dy2 = dy / 2
	
	case code
	when /cleanup_curve/
		ll1 = [[dx2-1,dy2], [dx2-1,dy], [dx2+2,dy], [dx2+2,dy2], [dx2-1,dy2]]
		ll2 = [[dx2-1,dy2], [dx2-3,1], [dx2,dy2], [dx2,1], [dx2+1,dy2], [dx2+3,1], [dx2+2,dy2], [dx2+5,1]]
		t = Geom::Transformation.rotation Geom::Point3d.new(dx2, dy2), Z_AXIS, -30.degrees
		pts1 = ll1.collect { |a| t * Geom::Point3d.new(*a) }
		pts2 = ll2.collect { |a| t * Geom::Point3d.new(*a)  }
		lst_gl.push [GL_POLYGON, pts1, 'yellow']
		lst_gl.push [GL_LINE_STRIP, pts1, 'red', 1, '']
		lst_gl.push [GL_LINES, pts2, 'orange', 2, '']
	end
	lst_gl
end

#CLEANUP: top method to generate geometry
def execute_geometry(lst_info_contours)
	calculation_proc = self.method "calculate_contour"

	#Options for calculation
	hcalc_options = map_option :remove_spikes, :remove_collinear
	
	#Options for contour generation
	hgen_options = map_option :make_curve, :contour_gen_mode
	
	local_options = []
	
	#Generating the new calculated contour
	G6.contour_reshaping lst_info_contours, calculation_proc, hgen_options, hcalc_options, local_options, @vbar_notify_proc
end

#CLEANUP: Contour transformation (just clone)
def calculate_contour(pts, hcalc_options, local_options)
	pts.clone
end

end	#class Algo_cleanup_curve

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class Algo_simplify_curve: SIMPLIFY CURVE Algorithm
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
class Algo_simplify_curve < Algo_Generic

#SIMPLIFY: Class instance initialization
def configure
	@hsh_params = { :hi_display => :dot, :hi_stipple => '', :hi_color_scheme =>  ['yellow', 'khaki'], :hi_color_mark => 'sienna',
				    :hi_label => :nb_seg }
	@lst_options = [ 
		{ :symb => :angle, :type => :float, :vmin => 0, :vmax => 45, :vincr => 2, :default => 10, 
          :prompt => T6[:T_TXT_AngleMax], :title => T6[:T_TXT_Angle], :vsprintf => "%0.1f\°", :vvcb => "%0.1fd", :tooltip => T6[:TIP_AngleSimplify],
		  :vcb_format => ["a", "f"] },
	    { :symb => :remove_spikes },  
	    { :symb => :contour_gen_mode },
		{ :symb => :make_curve }
	]
	@lst_steps = @vbar_reshaping_steps
end

#SIMPLIFY: Custom drawing of buttons
def draw_button_opengl(symb, dx, dy, main_color, frame_color, selected)
	code = symb.to_s
	lst_gl = []
	dx2 = dx / 2
	dy2 = dy / 2
	
	case code
	when /simplify_curve/
		pts = []
		pts.push Geom::Point3d.new(dx-3, 4)
		pts.push Geom::Point3d.new(3, dy2)
		pts.push Geom::Point3d.new(dx-3, dy-4)
		lst_gl.push [GL_LINE_STRIP, pts, 'green', 3, '']
	end
	lst_gl
end

#SIMPLIFY: top method to generate geometry
def execute_geometry(lst_info_contours)
	calculation_proc = self.method "calculate_contour"

	#Options for calculation
	hcalc_options = map_option :remove_spikes, :angle
	
	#Options for contour generation
	hgen_options = map_option :make_curve, :contour_gen_mode
	
	local_options = []
	
	#Generating the new calculated contour
	G6.contour_reshaping lst_info_contours, calculation_proc, hgen_options, hcalc_options, local_options, @vbar_notify_proc
end
	
#SIMPLIFY: Method 1 - Simple algorithm based on angle comparisoon
def calculate_contour(pts, hcalc_options, local_options)
	angle = hcalc_options[:angle]
	angle = angle.degrees
	npt = pts.length
	
	#Only 2 points
	return pts if pts.length <= 2
   
	#Eliminating points if angle at vertex is lower than angle
	loose_min = 0.6
	loose_max = 3.0
	dmin, dmax, davg = G6.stats_segment_length pts
	
	pts_res = Array.new npt, 0
	last_pt = pts[0]
	for i in 1..npt-2
		cur_pt = pts[i]
		next_pt = pts[i+1]
		vec1 = cur_pt.vector_to last_pt
		vec2 = next_pt.vector_to cur_pt
		d = [cur_pt.distance(last_pt), cur_pt.distance(next_pt)].max
		fac = davg.to_f / d.to_f
		fac = loose_max if fac > loose_max
		fac = loose_min if fac < loose_min
		if vec1.angle_between(vec2) < angle * fac
			pts_res[i] = -1
		else
			last_pt = cur_pt
		end
	end
	
	#Creating the map
	map = []
	for i in 0..npt-1
		map.push [pts[i], pts[i], pts_res[i]]
	end	
	
	bz = []
	map.each { |a| bz.push a[0] if a[2] == 0 }
	
	bz
end

end	#class Algo_simplify_curve

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class Algo_smooth_curve: SMOOTH CURVE Algorithm
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
class Algo_smooth_curve < Algo_Generic

#SMOOTH: Class instance initialization
def configure
	@hsh_params = { :hi_display => :dot, :hi_stipple => '', :hi_color_scheme =>  ['magenta', 'deeppink', 'fuchsia'], :hi_label => :nb_seg }
	@lst_options = [ 
	    { :symb => :smooth_method, :type => :radio, :default => :bspline, :text => T6[:T_STR_Method], :tooltip => T6[:TIP_SmoothMethod], 
		  :buttons => [ { :val => :bspline, :tooltip => T6[:TIP_SmoothMethod_BSpline], :draw_proc => :contour_approximation }, 
                        { :val => :fspline, :tooltip => T6[:TIP_SmoothMethod_FSpline], :draw_proc => :contour_fitting }
					  ] },
		{ :symb => :angle, :type => :float, :vmin => 0, :vmax => 45, :vincr => 0.5, :default => 8, 
          :prompt => T6[:T_TXT_AngleAvg], :title => T6[:T_TXT_Angle], :vsprintf => "%0.1f\°", :vvcb => "%0.1fd", :tooltip => T6[:TIP_AngleSmooth],
		  :vcb_format => ["a", "f"] },
	    { :symb => :optimize_vertices, :type => :powermeter, :default => 3, :tooltip => T6[:TIP_OptimizeVertices], :draw_proc => :contour_optimize_vertices },  
	    { :symb => :smooth_by_section, :type => :bool, :default => true, :tooltip => T6[:TIP_SmoothBySection], :draw_proc => :contour_by_section},  
	    { :symb => :remove_collinear, :nosepa => true },  
	    { :symb => :remove_spikes },  
	    { :symb => :contour_gen_mode},
		{ :symb => :make_curve }
	]
	@lst_steps = @vbar_reshaping_steps
end

#SMOOTH: Custom drawing of buttons
def draw_button_opengl(symb, dx, dy, main_color, frame_color, selected)
	code = symb.to_s
	lst_gl = []
	dx2 = dx / 2
	dy2 = dy / 2
	
	case code
	when /smooth_curve/
		ll = [[1,4], [4,9], [7,11], [9,9], [11, 7], [13, 8], [15,10], [17, 16]]
		pts = ll.collect { |a| Geom::Point3d.new *a }
		lst_gl.push [GL_LINE_STRIP, pts, 'green', 3, '']
	
	end
	lst_gl
end

#SMOOTH: top method to generate geometry
def execute_geometry(lst_info_contours)
	calculation_proc = self.method "calculate_contour"
	
	#Options for calculation
	hcalc_options = map_option [:method, :smooth_method], :optimize_vertices, :remove_spikes, :remove_collinear, :angle, [:by_section, :smooth_by_section]
	hcalc_options[:order] = 3
	
	#Options for contour generation
	hgen_options = map_option :make_curve, :contour_gen_mode 
	
	local_options = []
	
	#Generating the new calculated contour
	G6.contour_reshaping lst_info_contours, calculation_proc, hgen_options, hcalc_options, local_options, @vbar_notify_proc
end	
	
#SMOOTH: computation method for new contour
def calculate_contour(pts, hcalc_options, local_options=nil)
	G6.contour_maker pts, hcalc_options, local_options
end
	
end	#class Algo_smooth_curve

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Class Algo_convert_to_guide: CONVERT TO GUIDE Algorithm
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
class Algo_convert_to_guide < Algo_Generic

#CONVERT TO GUIDE: class instance initialization
def configure
	@hsh_params = { :hi_display => :arrow, :hi_stipple => '', :hi_width => 2, :hi_color_scheme =>  ['red', 'darkred', 'purple'] }
	@lst_options = [ 
		{ :symb => :guide_stipple, :type => :stipple, :default =>  "D", :title => T6[:T_TXT_Stipple], :tooltip => T6[:T_TIP_Stipple]  },
	    { :symb => :guide_cross, :type => :bool, :default => true, :tooltip => T6[:TIP_CreateGuidePoints], :draw_proc => :cross_small }
	]
	@lst_steps = [:transform_before]
end

#CONVERT TO GUIDE: Custom drawing of buttons
def draw_button_opengl(symb, dx, dy, main_color, frame_color, selected)
	code = symb.to_s
	lst_gl = []
	dx2 = dx / 2
	dy2 = dy / 2
	
	case code
				
	when /convert_to_guide/
		dd = 3
		n = ((dx / dd) / 2) * 2 + 1
		lines = []
		for i in 0..n
			lines.push Geom::Point3d.new(1 + dd * i, 1 + dd * i)
		end	
		lst_gl.push [GL_LINES, lines, 'black', 2, '']
	
	end	#case code
	
	lst_gl
end

#CONVERT TO GUIDE: top method to generate geometry
def execute_geometry(lst_info_contours)
	results_info = []
	flg_cross = get_option :guide_cross
	stipple = G6.stipple_from_code get_option(:guide_stipple)
	
	#Scanning the contours
	lpedges = []
	n = lst_info_contours.length
	lst_info_contours.each_with_index do |info, ik|
		vbar_notify :transform_before, ik, n
		lvx, ledges, tr, parent = info
		entities = G6.grouponent_entities(parent)
		grp = entities.add_group
		entities = grp.entities
		for i in 0..lvx.length-2
			pt1 = lvx[i].position
			pt2 = lvx[i+1].position
			entities.add_cline pt1, pt2, stipple
			entities.add_cpoint pt1 if flg_cross
		end
		entities.add_cpoint lvx.last.position if flg_cross && lvx.first != lvx.last
		lpedges.push [ledges, parent]
	end
	
	#Erasing the edges
	@notify_proc.call :delete_edges, lpedges
	
	results_info
end

end	#class Algo_convert_to_guide
	
end	#End Module F6_Curvizard
