mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 13:04:10 +00:00
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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user