I have an angle where I need to convert a 'normal' angle to an isometric angle (116 degrees), and I came up with this function. It works, but I was wondering if the math could be optimized/simplified, or if this is the way to go. It's for a mobile game.
public static inline var ISO:Float = 0.45378560551; // (116-90) / 180 * PI=;
function convert(angle:Float):Float
{
angle -= Math.PI; // corrected angle
var randomChoosenDistance = 2.0; // could be anything, I'm only interested in final angle.
// calculate new line, using isometic angle.
var x1 = Math.cos(angle - ISO);
var x2 = Math.cos(angle - ISO) * randomChoosenDistance;
var y1 = Math.sin(angle);
var y2 = Math.sin(angle) * randomChoosenDistance;
var dx = x1 - x2;
var dy = y1 - y2;
angle = Math.atan2(dy, dx);
return angle;
}
Can I get the new angle, without calculating the angle between the temporary points I'm creating at the moment?
2 Answers 2
@neo pointed out that dx
can be calculated as (1 - r) * Math.cos(a - b)
. Similarly, dy = (1 - r) * Math.sin(a)
. However, when you take dy / dx
, which is what Math.atan2(dy, dx)
implicitly does with its arguments, the (1 - r)
factor cancels out. You can also see, using a geometric argument, that (x2, y2) is pointless (pardon the pun).
Pointlessness of (x2, y2)
Therefore, Math.atan2(y1, x1)
would work just the same as Math.atan2(dy, dx)
.
So far, your function can be simplified to the following. Since you repurposed angle
twice, I need to disambiguate them as alpha
, beta
, and theta
for this discussion.
public static inline var ISO:Float = 0.45378560551; // (116-90) / 180 * PI=;
function convert(alpha:Float):Float
{
var beta = alpha - Math.PI; // corrected angle
// calculate new line, using isometic angle.
var x1 = Math.cos(beta - ISO);
var y1 = Math.sin(beta);
var theta = Math.atan2(y1, x1);
return theta;
}
But wait, there's more! There's a mysterious correction from alpha
to beta
, and the cosine expression is complicated.
Let's start with Math.sin(beta)
. That's Math.sin(-alpha)
, or -Math.sin(alpha)
.
It would be nice to say Math.atan2(Math.sin(alpha), something)
instead of Math.atan2(-Math.sin(alpha), something)
. Let's move the negation into the denominator then, for var theta = Math.atan2(Math.sin(alpha), -x1)
.
Can we simplify -x1
?
-x1 = -Math.cos(beta - ISO)
= Math.cos(beta - ISO + 180°)
= Math.cos(alpha - 180° - ISO + 180°)
= Math.cos(alpha - ISO)
So, your function simplifies to:
public static inline var ISO:Float = 0.45378560551; // = (116-90) / 180 * PI
function convert(angle:Float):Float
{
return Math.atan2(Math.sin(angle), Math.cos(angle - ISO));
}
Not only is the code more efficient, it's also less mysterious: the transformation is taking the x-coordinate of each point as if it were rotated 26° clockwise!
I have to question the motivation behind this function, though. This isn't an angle-preserving transformation, so why are you operating on an angle? Normally, you transform points' coordinates using matrix multiplication.
-
\$\begingroup\$ Thanks for taking time to this in-depth answer! It's very clear. About how I'm using this function: I have spritesheets from an old game that are drawn in isometric perspective, but my game itself runs in normal perspective (it only looks isometric). I'm using this function to get the right index on the spritesheet. So yes; I have to admit this function is very project specific. \$\endgroup\$Mark Knol– Mark Knol2014年01月20日 14:19:29 +00:00Commented Jan 20, 2014 at 14:19
It seems to me that this is a math related question rather than code review. Let's simplify the code first,
var dx = Math.cos(a - b) - Math.cos(a - b) * r;
The above can be simplified to
var dx = (1 - r) * Math.cos(a - b);
One less Math.cos()
and one less multiplication is being called, which could be CPU consuming.
Explore related questions
See similar questions with these tags.