<!-- Begin

// Copyright (c) 2007-2008 Hydrix except otherwise noted. All rights reserved
// www.hydrix.com

// ---------------------------------------------------------------------------
// UTILITIES
// ---------------------------------------------------------------------------

function log10(x)
{
	return Math.log(x) / Math.LN10;
}

g_log10_1 = 0; // log10(1)  = 0
g_log10_2 = log10(2); //    ~ 0.301029996
g_log10_5 = log10(5); //    ~ 0.698970004
g_log10_10 = 1; // log10(1) = 1
g_log10_between_1_2  = (g_log10_1 + g_log10_2) / 2;
g_log10_between_2_5  = 0.5; // (log10(2)+log10(5)) / 2;
g_log10_between_5_10 = (g_log10_5 + g_log10_10) / 2;

// ---------------------------------------------------------------------------
// Scale125 OBJECT
// ---------------------------------------------------------------------------

// Constructor.
function Scale125()
{	// Base data.
	this.points = null;
	this.points_minus_1 = null;
	this.reversed = false; // true if min to the right/bottom, e.g. Y axis.
	this.center = null;
	this.center_rounded = null;
	this.scale_index = null;
	this.unit_per_point = null;
	this.point_per_unit = null;

	// Cache.
	this.resetCache();
}

Scale125.prototype.resetCache = function()
{
	this.min = null;
	this.max = null;
}

// Base setters.
Scale125.prototype.setSize = function(size_pt, reversed)
{
	this.points = size_pt;
	this.points_minus_1 = size_pt - 1;
	this.reversed = reversed;
	this.resetCache();
}
Scale125.prototype.setCenter = function(center_u)
{
	this.center = center_u;
	if (this.scale !== null)
	{
		this.center_rounded = this.roundUnitsToScale(center_u);
	}
	this.resetCache();
}
Scale125.prototype.setScaleIndex = function(scale_index)
{
	this.scale_index = scale_index;
	var exponent = Math.floor(scale_index / 3);
	var base_index = Math.round(scale_index - exponent * 3);
	this.unit_per_point = parseFloat((['1','2','5'][base_index]) + 'e' + exponent);

	exponent = Math.floor(-scale_index / 3);
	base_index = Math.round(-scale_index - exponent * 3);
	this.point_per_unit = parseFloat((['1','2','5'][base_index]) + 'e' + exponent);

	if (this.center !== null)
	{
		this.center_rounded = this.roundUnitsToScale(this.center);
	}

	this.resetCache();
}
Scale125.prototype.setScale = function(scale)
{
	var log10_scale = log10(scale);
	var scale_exponent = Math.floor(log10_scale);
	var l_frac = log10_scale - scale_exponent;
	var scale_base = 0;
	if (l_frac > g_log10_between_5_10) { scale_exponent++; }
	else if (l_frac > g_log10_between_2_5) { scale_base = 2; }
	else if (l_frac > g_log10_between_1_2) { scale_base = 1; }

	this.setScaleIndex(Math.round(scale_exponent * 3 + scale_base));
}
Scale125.prototype.setBorders = function(min, max)
{
	this.setCenter((min + max) / 2);
	this.setScale((max - min) / this.points_minus_1);
}
// Copy constructor.
function Scale125Copy(s)
{
	var s2 = new Scale125();
	s2.setSize(s.points);
	s2.setCenter(s.center);
	s2.setScaleIndex(s.scale_index);
	return s2;
}

// Round a coordinate in units to the closest middle of point.
Scale125.prototype.roundUnitsToScale = function (u)
{
	if (this.point_per_unit >= 1)
	{
		u = Math.round(u * this.point_per_unit) / this.point_per_unit;
	}
	else
	{
		u = Math.round(u * this.unit_per_point) / this.unit_per_point;
	}
	return u;
}

Scale125.prototype.getMin = function()
{
	if (this.min === null)
	{
		this.min = this.roundUnitsToScale(this.center_rounded - (this.points_minus_1 / 2) * this.unit_per_point);
	}
	return this.min;
}
Scale125.prototype.getMax = function()
{
	if (this.max === null)
	{
		this.max = this.roundUnitsToScale(this.getMin() + this.points_minus_1 * this.unit_per_point);
	}
	return this.max;
}
Scale125.prototype.getArray = function()
{
	var a = new Array(this.points);
	var v = this.center_rounded;
	var i = this.unit_per_point;
	for (var k = 0; k < this.points; k++)
	{
		a[k] = g_slice_scale.roundUnitsToScale(v + i * (k - (Math.round(this.points_minus_1 / 2))));
	}
	return a;
}

// Coordinate in units -> Point in viewer (not rounded!).
Scale125.prototype.unitsToPoints = function(u)
{
	var p = (u - this.getMin()) / this.unit_per_point;
	if (this.reversed)
	{
		p = this.points_minus_1 - p;
	}
	return p;
}
// Point in viewer -> Coordinate in units.
Scale125.prototype.pointsToUnits = function(p)
{
	if (this.reversed)
	{
		p = this.points_minus_1 - p;
	}
	return this.roundUnitsToScale(p * this.unit_per_point + this.getMin());
}

// Positive increment = zoom out.
Scale125.prototype.zoom = function(increment)
{
	this.setScaleIndex(this.scale_index + increment);
}
// t>0 -> Towards max.
Scale125.prototype.translatePoints = function(t_pt)
{
	this.setCenter(this.center_rounded + t_pt * this.unit_per_point);
}
Scale125.prototype.centerAtPoint = function(pt)
{
	this.setCenter(this.pointsToUnits(pt));
}
Scale125.prototype.centerAndZoom = function(pt, increment)
{
	this.centerAtPoint(pt);
	this.zoom(increment);
}
Scale125.prototype.reset = function()
{
	this.setCenter(0);
	this.setScaleIndex(-5);
}
