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

View file

@ -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));
};

View file

@ -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)

View file

@ -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);
}
/**

View file

@ -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;

View file

@ -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 */

View file

@ -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)

View file

@ -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;

View file

@ -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);