# GVB - a GTK+/GNOME vibrations simulator
#
# Copyright (C) 2008 Pietro Battiston
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#Give startup dispositions of the points

from scipy import array, zeros, sin, cos, pi, concatenate, ones, prod, sqrt
from scipy.linalg import norm

from gvbi18n import _

def disposition(shape, type_descriptor):
#	print "shape", shape
	if len(shape) in dispositions and type_descriptor in dispositions[len(shape)]:
		return dispositions_dict[len(shape)][type_descriptor](shape)
	else:
		print "type not found:", type_descriptor
		return zeros(shape)

waveforms_dict = {	#hl=half wave lenght, cen=centering (from 0 to 1), x is between 1 (not 0) and wl-1
	'square': (lambda hl, ce, t: 1)
	,
	'triangular': (lambda hl, ce, t: min(float(t)/ce, float(hl-t)/(1-ce))/hl )
	,
	'sinusoidal': (lambda hl, ce, t: sin(min(float(t)/(2*ce), float(hl-t)/(2*(1-ce))) * pi/hl) )
	,
	'peak': (lambda hl, ce, t: max((abs(hl*ce-t),0),(.5,1))[1] )
				}

waveforms = ['sinusoidal', 'triangular', 'square', 'peak']


def waveformer_1d((n,), waveform, lenght, shift, wavelenght, fase_angle, height, centering, rule = None):

	singlewave = array([waveforms_dict[waveform](wavelenght/2+1, centering, t)	for t in range (1,wavelenght/2+1)])
	doublewave = concatenate([singlewave, zeros(1), -1*singlewave])*height

	fase = wavelenght * fase_angle/360
	calculated = doublewave
	while len(calculated) < lenght+fase:
		calculated = concatenate([calculated, array([0]), doublewave])

#	print "stopped extending:", len(calculated)

	calculated = calculated[fase:lenght+fase]

#	print "calculated clipped:", len(calculated)

	wave_clip = lenght - max(0, shift + lenght - n)

	zeros_before = shift-(lenght-wave_clip)
	zeros_after = n - (shift + wave_clip)

	wave_final = concatenate([ calculated[wave_clip:], zeros(zeros_before), calculated[:wave_clip], zeros(zeros_after) ])
#	print "first trunk:", calculated[wave_clip:]
#	print "fase:", fase, "wave_clipped:", wave_clip

	return wave_final

def waveformer_2d((n1,n2), *args):

	wave1 = waveformer_1d((n1,), *args[:7])
	wave2 = waveformer_1d((n2,), *args[7:14])

	rules = {'sum' : sum, 'prod' : prod, 'max' : max, 'min': min}

	rule = rules[args[14]]

#	print "rule:", rule

	#FIXME: really not efficient... should someway use scipy.
	wave_final = array( [[rule([wave1[i], wave2[j]]) for i in range(n1)] for j in range(n2)] )
#	print "max final:", max ([max(i) for i in wave_final])

	return wave_final

waveformer = {1: waveformer_1d, 2: waveformer_2d}


dispositions_1d={	#Dispositions are created combining waveformers and/or other dispositions
	'flat': zeros
	,
#	'sin': (lambda (n,): array([sin(t*pi*2/(n+1)) for t in range(1,n+1)]))
	'sin': (lambda shape: waveformer_1d(shape, 'sinusoidal', shape[0], 0, shape[0], 0, 1, .5 ) )
	,
#	'half sin': (lambda (n,): array([sin(t*pi/(n+1)) for t in range(1,n+1)]))
	'half sin': (lambda shape: waveformer_1d(shape, 'sinusoidal', shape[0], 0, 2*shape[0]+1, 0, 1, .5 ) )
	,
#	'picked': (lambda (n,): array([float(2*min(t, n-t+1))/n for t in range(1,n+1) ]))
	'picked': (lambda shape: waveformer_1d(shape, 'triangular', shape[0], 0, 2*shape[0]+1, 0, 1, .5 ) )
	,
	'triangular signal': (lambda (n,): concatenate([ disposition((n/4,), 'picked'), disposition((n-n/4,), 'flat') ]))
	,
	'sinusoidal signal': (lambda (n,): concatenate([ disposition((n/4,), 'sin'), disposition((n-n/4,), 'flat') ]))
	,
#	'picked lateral':  (lambda (n,): array([float(min(float(2*t)/n, float(n-t+1)/n)) for t in range(1,n+1) ]))
	'picked lateral': (lambda shape: waveformer_1d(shape, 'triangular', shape[0], 0, 2*shape[0]+1, 0, 1, .25 ) )
	,
	'opposite triangulars': (lambda (n,): concatenate([ disposition((n/4,), 'picked'), disposition((n-n/4-n/4,), 'flat'), disposition((n/4,), 'picked') ]))
	,
	'opposite sinusoidals': (lambda (n,): concatenate([ disposition((n/4,), 'sin'), disposition((n-n/4-n/4,), 'flat'), disposition((n/4,), 'sin') ]))
	,
	'square': ones
	,
	'square signal': (lambda (n,): concatenate([ disposition((n/4,), 'square'), disposition((n-n/4,), 'flat') ]))
	,
#	'discontinuous peak': (lambda (n,): concatenate([ disposition((n/2,), 'flat'), [1], disposition((n-n/2-1,), 'flat') ]))
	'discontinuous peak': (lambda shape: waveformer_1d(shape, 'peak', shape[0], 0, 2*shape[0]+1, 0, 1, .5 ) )
	,
	'cos (shifted)': (lambda shape: waveformer_1d(shape, 'sinusoidal', shape[0], 0, shape[0], 270, 1, .5) + ones(shape) )
				}


dispositions_2d={
	'flat': zeros
	,
#	'picked': (lambda (n,m): array([array([float(2*min(t, m-t+1))/n for t in range(1,m+1) ])*float(2*min(j, n-j+1))/n for j in range(1,n+1)]))
	'picked': (lambda shape: waveformer_2d(shape, 'triangular', shape[0], 0, 2*shape[0]+1, 0, .5, .5, 'triangular', shape[0], 0, 2*shape[0]+1, 0, .5, .5 , 'sum' ) )
	,
	'sin': (lambda shape: waveformer_2d(shape, 'sinusoidal', shape[0], 0, shape[0], 0, 1, .5, 'sinusoidal', shape[0], 0, shape[0], 0, 1, .5 , 'prod' ) )
	,
	'half sin': (lambda shape: waveformer_2d(shape, 'sinusoidal', shape[0], 0, 2*shape[0]+1, 0, .5, .5, 'sinusoidal', shape[0], 0, 2*shape[0]+1, 0, .5, .5 , 'sum' ) )
	,
	'pond': (lambda (n,m): array([[(lambda x,y,r : -.1*cos(10*pi*norm([x,y])/r) * max(1-norm([x,y])/r, 0) ) (i-float(m)/2, j-float(n)/2, float(min(m,n))/2) for i in range(1,m+1) ] for j in range(1,n+1)]))
	,
	'waterfall': (lambda (n,m): array([[(lambda x,y : 1 if norm([x,y]) < min(m,n)/10 else 0)(i-float(m)/2, j-float(n)/2) for i in range(1,m+1) ] for j in range(1,n+1)]))
	,
	'gut': (lambda (n,m): array([[(lambda x,y,r : -1-cos(8*pi*norm([x,y])/r) if norm([x,y]) < r/8 else 0) (i-float(m)/2, j-float(n)/2, float(min(m,n))) for i in range(1,m+1) ] for j in range(1,n+1)]))
				}

dispositions_dict={1:dispositions_1d, 2:dispositions_2d}

dispositions={}


for dim in [1,2]:
	keys=dispositions_dict[dim].keys()
	keys.sort()
	dispositions[dim]=keys






dummy_list_for_gettext=[_('flat'),	_('sin'), _('half sin'), _('picked'), _('triangular signal'), _('sinusoidal signal'), _('picked lateral'), _('opposite triangulars'), _('picked'), _('opposite sinusoidals'), _('square'), _('square signal'), _('discontinuous peak'), _('cos (shifted)'), _('pond'), _('waterfall'), _('gut'), _('peak'), _('sinusoidal') ]
