/***********************************************************************/
/*                                                                     */
/*      ComplexClass ::   Complex Number Class                         */
/*                        including various operators                  */
/*                                                                     */
/*      [Ver: 1.0]   [Author: Marc Autret]         [Modif: 05/25/10]   */
/*      [Lang: EN]   [Req: InDesign CS2/CS3/CS4]   [Creat: 05/23/10]   */
/*                                                                     */
/*      Installation:                                                  */
/*                                                                     */
/*      1) Place the current file into Scripts/Scripts Panel/          */
/*                                                                     */
/*      2) Run InDesign, open a document containing texts              */
/*                                                                     */
/*      3) Exec script from Window > Automatisation > Scripts          */
/*         (double-click on the script name)                           */
/*                                                                     */
/*      Bugs & Feedback : marc{at}indiscripts{dot}com                  */
/*                        www.indiscripts.com                          */
/*                                                                     */
/***********************************************************************/

var Complex = (function()
{
// UTILITIES
// ---------------------------
var mSqr = Math.sqrt,
	mCos = Math.cos,
	mSin = Math.sin,
	mAtan2 = Math.atan2,
	kDeg = 180/Math.PI,
	kRad = Math.PI/180,
	m2 = function(){return this.x*this.x+this.y*this.y;},
	eq = function(z){return this.x==z.x && this.y==z.y;},
	cx = function(z){return z instanceof cstr;},
	df = function(z){return cx(z)?z:{x:+(z||0),y:0};};

// CONSTRUCTOR
// ---------------------------
var cstr = function Complex(re,im)
	{
	this.x = +re;
	this.y = +im;
	};

// INTERFACE (INCLUDING OPERATORS)
// ---------------------------
cstr.prototype = {
	toString: function()
		{
		return [this.x,this.y].toString();
		},
	valueOf: function()
		{
		return (this.y)?NaN:this.x;
		},
	// MAGNITUDE : |Z|
	mag: function()
		{
		return mSqr(m2.call(this));
		},
	// INVERSION : 1/Z
	inv: function()
		{
		if( this==0 ) return NaN;
		return (~this)*(1/(m2.call(this)));
		},
	// ARGUMENT (PHASE) in radians
	arg: function()
		{
		if( this==0 ) return NaN;
		return mAtan2(this.y,this.x);
		},
	// ARGUMENT (PHASE) in degrees
	deg: function()
		{
		return kDeg*this.arg();
		},
	// ADDITION
	"+": function(z)
		{ // Supports: +Z | Z+X | X+Z | Z+Z'
		var xy = df(z);
		return new cstr(
			this.x + xy.x,
			this.y + xy.y
			);
		},
	// MULTIPLICATION
	"*": function(z)
		{ // Supports: Z*X | X*Z | Z*Z'
		var xy = df(z);
		return new cstr(
			this.x*xy.x - this.y*xy.y,
			this.x*xy.y + this.y*xy.x
			);
		},
	// SUBTRACTION
	"-": function(z,rev)
		{ // Supports: -Z | Z-X | X-Z | Z-Z'
		if( !z ) return new cstr(-this.x,-this.y);
		return (rev)?(z+(-this)):(this+(-z));
		},
	// DIVISION	
	"/": function(z, rev)
		{ // Supports: Z/X | X/Z | Z/Z'
		if( cx(z) ) return this*(z.inv());
		return (rev)?(z*this.inv()):this*(1/z);
		},
	// EQUALITY
	"==": function(z)
		{ // Supports: Z==X | X==Z | Z==Z'
		return eq.call(this,df(z));
		},
	// CONJUGATE FORM
	"~": function()
		{ // Supports: ~Z
		return new cstr(this.x,-this.y);
		},
	// INTEGER POWER
	"^": function(n,rev)
		{ // Supports: Z^N
		if( rev || n!==~~n ) return NaN;
		if( n==0 ) return cstr.unity;
		if( n<0 ) return 1/(this^(-n));
		var r = +this; // clone
		while( --n ) r*=this;
		return r;
		},
	// ROTATION
	"<<": function(/*degrees*/aDeg,rev)
		{ // counterclockwise rotation about [0,0]
		if( rev ) return NaN;
		if( !aDeg ) return +this;
		var	a = aDeg*kRad,
			z = new cstr(mCos(a),mSin(a));
		return this*z;
		},
	">>": function(/*degrees*/aDeg,rev)
		{ // clockwise rotation about [0,0]
		if( rev ) return NaN;
		return this<<(-aDeg);
		},
	};

// CONSTANTS
// ---------------------------
cstr.zero = new cstr(0,0);
cstr.unity = new cstr(1,0);
cstr.i = new cstr(0,1);

return cstr;
})();



// Sample code
// ---------------------------
var z = new Complex(4,3),
	i = Complex.i;

// magnitude and phase
var m = z.mag();
alert( m ); // 5
alert( z.deg() ); // about 37°

// basic operations
alert( 2*z - 4*i ); // [8,2]
alert( -(z*~z)/(5*i) ); // [0,5]

// comparisons
alert( (i^2) == -1 ); // true
alert( 0 == Complex.zero ); // true
alert( (m*m)/z == ~z ); // true

// rotation
z <<= 30;
alert( z ); // about [2,4.6]

