1
0
forked from mirrors/0ad

Add Math.square to compute the square of a number without the need to repeat the term, without using the slower Math.pow.

Start unifying the euclidian distance functions instead of adding yet
another helper function to the random map script library after this
diff.

Differential Revision: https://code.wildfiregames.com/D969
Math.square accepted by mimo
Includes changes proposed by bb, fatherbushido

This was SVN commit r20328.
This commit is contained in:
elexis
2017-10-22 20:46:41 +00:00
parent 67e27ed7ea
commit 6590f301c2
8 changed files with 65 additions and 22 deletions
@@ -174,6 +174,14 @@ Math.pow = function(x, y)
return Math.exp(y*Math.log(x));
};
/**
* Get the square of a number without repeating the value and without calling the slower Math.pow.
*/
Math.square = function(x)
{
return x * x;
};
/**
* Approximation of the exponential function, e raised to the power x
*/
@@ -315,3 +323,25 @@ Math.intPow = function(x, y)
};
Math.euclidDistance2DSquared = function(x1, y1, x2, y2)
{
return Math.square(x2 - x1) + Math.square(y2 - y1);
};
/**
* Can be faster than Math.hypot.
*/
Math.euclidDistance2D = function(x1, y1, x2, y2)
{
return Math.sqrt(Math.euclidDistance2DSquared(x1, y1, x2, y2));
};
Math.euclidDistance3DSquared = function(x1, y1, z1, x2, y2, z2)
{
return Math.square(x2 - x1) + Math.square(y2 - y1) + Math.square(z2 - z1);
};
Math.euclidDistance3D = function(x1, y1, z1, x2, y2, z2)
{
return Math.sqrt(Math.euclidDistance3DSquared(x1, y1, z1, x2, y2, z2));
};
@@ -126,12 +126,12 @@ Vector2D.prototype.compareLength = function(v)
Vector2D.prototype.distanceToSquared = function(v)
{
return Math.pow(this.x - v.x, 2) + Math.pow(this.y - v.y, 2);
return Math.euclidDistance2DSquared(this.x, this.y, v.x, v.y);
};
Vector2D.prototype.distanceTo = function(v)
{
return Math.sqrt(this.distanceToSquared(v));
return Math.euclidDistance2D(this.x, this.y, v.x, v.y);
};
// Static 2D functions
@@ -283,17 +283,17 @@ Vector3D.prototype.compareLength = function(v)
Vector3D.prototype.distanceToSquared = function(v)
{
return Math.pow(this.x - v.x, 2) + Math.pow(this.y - v.y, 2) + Math.pow(this.z - v.z, 2);
return Math.euclidDistance3DSquared(this.x, this.y, this.z, v.x, v.y, v.z);
};
Vector3D.prototype.distanceTo = function(v)
{
return Math.sqrt(this.distanceToSquared(v));
return Math.euclidDistance3D(this.x, this.y, this.z, v.x, v.y, v.z);
};
Vector3D.prototype.horizDistanceToSquared = function(v)
{
return Math.pow(this.x - v.x, 2) + Math.pow(this.z - v.z, 2);
return Math.euclidDistance2DSquared(this.x, this.z, v.x, v.z);
};
Vector3D.prototype.horizDistanceTo = function(v)
@@ -45,7 +45,7 @@ function sameColor(color1, color2)
*/
function colorDistance(color1, color2)
{
return Math.sqrt(Math.pow(color2.r - color1.r, 2) + Math.pow(color2.g - color1.g, 2) + Math.pow(color2.b - color1.b, 2));
return Math.euclidDistance3D(color1.r, color1.g, color1.b, color2.r, color2.g, color2.b);
}
/**
@@ -147,10 +147,10 @@ m.Map.prototype.multiplyInfluence = function(cx, cy, maxDist, strength, type = "
let str = strength / maxDist;
for (let y = y0; y < y1; ++y)
{
let dy = y - cy;
for (let x = x0; x < x1; ++x)
{
let dx = x - cx;
let dy = y - cy;
let r2 = dx*dx + dy*dy;
if (r2 >= maxDist2)
continue;
@@ -169,10 +169,10 @@ m.Map.prototype.multiplyInfluence = function(cx, cy, maxDist, strength, type = "
let str = strength / maxDist2;
for (let y = y0; y < y1; ++y)
{
let dy = y - cy;
for (let x = x0; x < x1; ++x)
{
let dx = x - cx;
let dy = y - cy;
let r2 = dx*dx + dy*dy;
if (r2 >= maxDist2)
continue;
@@ -190,10 +190,10 @@ m.Map.prototype.multiplyInfluence = function(cx, cy, maxDist, strength, type = "
{
for (let y = y0; y < y1; ++y)
{
let dy = y - cy;
for (let x = x0; x < x1; ++x)
{
let dx = x - cx;
let dy = y - cy;
let r2 = dx*dx + dy*dy;
if (r2 >= maxDist2)
continue;
@@ -19,16 +19,12 @@ m.exit = function()
m.VectorDistance = function(a, b)
{
let dx = a[0] - b[0];
let dz = a[1] - b[1];
return Math.sqrt(dx*dx + dz*dz);
return Math.euclidDistance2D(...a, ...b);
};
m.SquareVectorDistance = function(a, b)
{
let dx = a[0] - b[0];
let dz = a[1] - b[1];
return dx*dx + dz*dz;
return Math.euclidDistance2DSquared(...a, ...b);
};
/** Utility functions for conversions of maps of different sizes */
@@ -4437,7 +4437,7 @@ UnitAI.prototype.MoveToTargetAttackRange = function(target, type)
// No negative roots please
if (h>-range.max/2)
var parabolicMaxRange = Math.sqrt(range.max*range.max+2*range.max*h);
var parabolicMaxRange = Math.sqrt(Math.square(range.max) + 2 * range.max * h);
else
// return false? Or hope you come close enough?
var parabolicMaxRange = 0;
@@ -4628,11 +4628,8 @@ UnitAI.prototype.CheckTargetDistanceFromHeldPosition = function(target, iid, typ
var heldPosition = this.heldPosition;
if (heldPosition === undefined)
heldPosition = {"x": pos.x, "z": pos.z};
var dx = heldPosition.x - pos.x;
var dz = heldPosition.z - pos.z;
var dist = Math.sqrt(dx*dx + dz*dz);
return dist < halfvision + range.max;
return Math.euclidDistance2D(pos.x, pos.z, heldPosition.x, heldPosition.z) < halfvision + range.max;
};
UnitAI.prototype.CheckTargetIsInVisionRange = function(target)
@@ -199,7 +199,7 @@ UnitMotionFlying.prototype.OnUpdate = function(msg)
// If we're in range of the target then tell people that we've reached it
// (TODO: quantisation breaks this)
var distFromTarget = Math.sqrt(Math.pow(this.targetX - pos.x, 2) + Math.pow(this.targetZ - pos.z, 2));
var distFromTarget = Math.euclidDistance2D(pos.x, pos.z, this.targetX, this.targetZ);
if (!this.reachedTarget && this.targetMinRange <= distFromTarget && distFromTarget <= this.targetMaxRange)
{
this.reachedTarget = true;
@@ -281,7 +281,7 @@ UnitMotionFlying.prototype.IsInPointRange = function(x, y, minRange, maxRange)
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
var pos = cmpPosition.GetPosition2D();
var distFromTarget = Math.sqrt(Math.pow(x - pos.x, 2) + Math.pow(y - pos.y, 2));
var distFromTarget = Math.euclidDistance2D(x, y, pos.x, pos.y);
if (minRange <= distFromTarget && distFromTarget <= maxRange)
return true;
@@ -121,4 +121,24 @@ TS_ASSERT(isNegativeZero(Math.sqrt(-0)));
TS_ASSERT_EQUALS(Math.sqrt(Infinity), Infinity);
TS_ASSERT_EQUALS(Math.sqrt(1e-323), 3.1434555694052576e-162);
// square
TS_ASSERT_UNEVAL_EQUALS(Math.square(NaN), NaN);
TS_ASSERT(isPositiveZero(Math.square(0)));
TS_ASSERT(isPositiveZero(Math.square(-0)));
TS_ASSERT_EQUALS(Math.square(Infinity), Infinity);
TS_ASSERT_EQUALS(Math.square(1.772979291871526e-81),3.143455569405258e-162);
TS_ASSERT_EQUALS(Math.square(1e+155), Infinity)
TS_ASSERT_UNEVAL_EQUALS(Math.square(1), 1);
TS_ASSERT_UNEVAL_EQUALS(Math.square(20), 400);
TS_ASSERT_UNEVAL_EQUALS(Math.square(300), 90000);
TS_ASSERT_UNEVAL_EQUALS(Math.square(4000), 16000000);
TS_ASSERT_UNEVAL_EQUALS(Math.square(50000), 2500000000);
TS_ASSERT_UNEVAL_EQUALS(Math.square(-3), 9);
TS_ASSERT_UNEVAL_EQUALS(Math.square(-8), 64);
TS_ASSERT_UNEVAL_EQUALS(Math.square(0.123), 0.015129);
// euclid distance
TS_ASSERT_UNEVAL_EQUALS(Math.euclidDistance2D(0, 0, 3, 4), 5);
TS_ASSERT_UNEVAL_EQUALS(Math.euclidDistance2D(-4, -4, -5, -4), 1);
TS_ASSERT_UNEVAL_EQUALS(Math.euclidDistance2D(1e+140, 1e+140, 0, 0), 1.414213562373095e+140);
TS_ASSERT_UNEVAL_EQUALS(Math.euclidDistance3D(0, 0, 0, 20, 48, 165), 173);