How can I scale a 2D rotation vector without trig functions?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have a normalized 2D vector that I am using to rotate other 2D vectors. In one instance it indicates "spin" (or "angular momentum") and is used to rotate the "orientation" of a simple polygon. My vector class contains this method:
rotateByXY(x, y) {
let rotX = x * this.x - y * this.y;
let rotY = y * this.x + x * this.y;
this.x = rotX;
this.y = rotY;
}
So far, this is all efficient and uses no trig whatsoever.
However, I want the "spin" to decay over time. This means that the angle of the spin should tend towards zero. And here I'm at a loss as to how to do this without expensive trig calls like this:
let angle = Math.atan2(spin.y, spin.x);
angle *= SPIN_DECAY;
spin = new Vector2D(Math.cos(angle), Math.sin(angle));
Is there a better/faster way to accomplish this?
geometry 2d trigonometry
add a comment |
I have a normalized 2D vector that I am using to rotate other 2D vectors. In one instance it indicates "spin" (or "angular momentum") and is used to rotate the "orientation" of a simple polygon. My vector class contains this method:
rotateByXY(x, y) {
let rotX = x * this.x - y * this.y;
let rotY = y * this.x + x * this.y;
this.x = rotX;
this.y = rotY;
}
So far, this is all efficient and uses no trig whatsoever.
However, I want the "spin" to decay over time. This means that the angle of the spin should tend towards zero. And here I'm at a loss as to how to do this without expensive trig calls like this:
let angle = Math.atan2(spin.y, spin.x);
angle *= SPIN_DECAY;
spin = new Vector2D(Math.cos(angle), Math.sin(angle));
Is there a better/faster way to accomplish this?
geometry 2d trigonometry
1
Simple formulas exist only forSPIN_DECAY = 1/2
(and for arithmetic progressionan[i] = an0 - i*da
). Otherwise it would better to storeangle
to avoidatan2
. If you apply the same rotation to multiple points, single evaluation of sin/cos per step is not so bad.
– MBo
Jan 4 at 5:35
1
what about this: How to calculate rocket? see the rotation math at the end... beware it works only for rotations up to90deg
and the rotation is not linear but not too far from it either and works for any dimensionality...the dimming is done simply by decreasing thedang0
or bydang0*=0.95
each iteration etc ... you do not need theacos
for computinga
as you already know how much your original rotation rotates ...
– Spektre
Jan 4 at 11:00
Another idea: what about approximating your trigonometric functions with their Taylor expansions?
– Dominik Mokriš
Jan 17 at 20:03
@DominikMokriš, that sounds intriguing. Can you say more and/or provide details? Not quite sure how to implement that. BTW, I did consider something like this lookup: int iX = int((spin.x + 1) * 100); int iY = int((spin.y + 1) * 100); spin = DecayLookupX[iX][iY]; Where DecayLookup is a 200 x 200 array of pre-calculated vectors (could be tuned). A bit rough, but would work for a constant decay.
– Scott Schafer
Jan 19 at 0:28
add a comment |
I have a normalized 2D vector that I am using to rotate other 2D vectors. In one instance it indicates "spin" (or "angular momentum") and is used to rotate the "orientation" of a simple polygon. My vector class contains this method:
rotateByXY(x, y) {
let rotX = x * this.x - y * this.y;
let rotY = y * this.x + x * this.y;
this.x = rotX;
this.y = rotY;
}
So far, this is all efficient and uses no trig whatsoever.
However, I want the "spin" to decay over time. This means that the angle of the spin should tend towards zero. And here I'm at a loss as to how to do this without expensive trig calls like this:
let angle = Math.atan2(spin.y, spin.x);
angle *= SPIN_DECAY;
spin = new Vector2D(Math.cos(angle), Math.sin(angle));
Is there a better/faster way to accomplish this?
geometry 2d trigonometry
I have a normalized 2D vector that I am using to rotate other 2D vectors. In one instance it indicates "spin" (or "angular momentum") and is used to rotate the "orientation" of a simple polygon. My vector class contains this method:
rotateByXY(x, y) {
let rotX = x * this.x - y * this.y;
let rotY = y * this.x + x * this.y;
this.x = rotX;
this.y = rotY;
}
So far, this is all efficient and uses no trig whatsoever.
However, I want the "spin" to decay over time. This means that the angle of the spin should tend towards zero. And here I'm at a loss as to how to do this without expensive trig calls like this:
let angle = Math.atan2(spin.y, spin.x);
angle *= SPIN_DECAY;
spin = new Vector2D(Math.cos(angle), Math.sin(angle));
Is there a better/faster way to accomplish this?
geometry 2d trigonometry
geometry 2d trigonometry
asked Jan 4 at 0:22
Scott SchaferScott Schafer
1067
1067
1
Simple formulas exist only forSPIN_DECAY = 1/2
(and for arithmetic progressionan[i] = an0 - i*da
). Otherwise it would better to storeangle
to avoidatan2
. If you apply the same rotation to multiple points, single evaluation of sin/cos per step is not so bad.
– MBo
Jan 4 at 5:35
1
what about this: How to calculate rocket? see the rotation math at the end... beware it works only for rotations up to90deg
and the rotation is not linear but not too far from it either and works for any dimensionality...the dimming is done simply by decreasing thedang0
or bydang0*=0.95
each iteration etc ... you do not need theacos
for computinga
as you already know how much your original rotation rotates ...
– Spektre
Jan 4 at 11:00
Another idea: what about approximating your trigonometric functions with their Taylor expansions?
– Dominik Mokriš
Jan 17 at 20:03
@DominikMokriš, that sounds intriguing. Can you say more and/or provide details? Not quite sure how to implement that. BTW, I did consider something like this lookup: int iX = int((spin.x + 1) * 100); int iY = int((spin.y + 1) * 100); spin = DecayLookupX[iX][iY]; Where DecayLookup is a 200 x 200 array of pre-calculated vectors (could be tuned). A bit rough, but would work for a constant decay.
– Scott Schafer
Jan 19 at 0:28
add a comment |
1
Simple formulas exist only forSPIN_DECAY = 1/2
(and for arithmetic progressionan[i] = an0 - i*da
). Otherwise it would better to storeangle
to avoidatan2
. If you apply the same rotation to multiple points, single evaluation of sin/cos per step is not so bad.
– MBo
Jan 4 at 5:35
1
what about this: How to calculate rocket? see the rotation math at the end... beware it works only for rotations up to90deg
and the rotation is not linear but not too far from it either and works for any dimensionality...the dimming is done simply by decreasing thedang0
or bydang0*=0.95
each iteration etc ... you do not need theacos
for computinga
as you already know how much your original rotation rotates ...
– Spektre
Jan 4 at 11:00
Another idea: what about approximating your trigonometric functions with their Taylor expansions?
– Dominik Mokriš
Jan 17 at 20:03
@DominikMokriš, that sounds intriguing. Can you say more and/or provide details? Not quite sure how to implement that. BTW, I did consider something like this lookup: int iX = int((spin.x + 1) * 100); int iY = int((spin.y + 1) * 100); spin = DecayLookupX[iX][iY]; Where DecayLookup is a 200 x 200 array of pre-calculated vectors (could be tuned). A bit rough, but would work for a constant decay.
– Scott Schafer
Jan 19 at 0:28
1
1
Simple formulas exist only for
SPIN_DECAY = 1/2
(and for arithmetic progression an[i] = an0 - i*da
). Otherwise it would better to store angle
to avoid atan2
. If you apply the same rotation to multiple points, single evaluation of sin/cos per step is not so bad.– MBo
Jan 4 at 5:35
Simple formulas exist only for
SPIN_DECAY = 1/2
(and for arithmetic progression an[i] = an0 - i*da
). Otherwise it would better to store angle
to avoid atan2
. If you apply the same rotation to multiple points, single evaluation of sin/cos per step is not so bad.– MBo
Jan 4 at 5:35
1
1
what about this: How to calculate rocket? see the rotation math at the end... beware it works only for rotations up to
90deg
and the rotation is not linear but not too far from it either and works for any dimensionality...the dimming is done simply by decreasing the dang0
or by dang0*=0.95
each iteration etc ... you do not need the acos
for computing a
as you already know how much your original rotation rotates ...– Spektre
Jan 4 at 11:00
what about this: How to calculate rocket? see the rotation math at the end... beware it works only for rotations up to
90deg
and the rotation is not linear but not too far from it either and works for any dimensionality...the dimming is done simply by decreasing the dang0
or by dang0*=0.95
each iteration etc ... you do not need the acos
for computing a
as you already know how much your original rotation rotates ...– Spektre
Jan 4 at 11:00
Another idea: what about approximating your trigonometric functions with their Taylor expansions?
– Dominik Mokriš
Jan 17 at 20:03
Another idea: what about approximating your trigonometric functions with their Taylor expansions?
– Dominik Mokriš
Jan 17 at 20:03
@DominikMokriš, that sounds intriguing. Can you say more and/or provide details? Not quite sure how to implement that. BTW, I did consider something like this lookup: int iX = int((spin.x + 1) * 100); int iY = int((spin.y + 1) * 100); spin = DecayLookupX[iX][iY]; Where DecayLookup is a 200 x 200 array of pre-calculated vectors (could be tuned). A bit rough, but would work for a constant decay.
– Scott Schafer
Jan 19 at 0:28
@DominikMokriš, that sounds intriguing. Can you say more and/or provide details? Not quite sure how to implement that. BTW, I did consider something like this lookup: int iX = int((spin.x + 1) * 100); int iY = int((spin.y + 1) * 100); spin = DecayLookupX[iX][iY]; Where DecayLookup is a 200 x 200 array of pre-calculated vectors (could be tuned). A bit rough, but would work for a constant decay.
– Scott Schafer
Jan 19 at 0:28
add a comment |
1 Answer
1
active
oldest
votes
If it's really the trigonometric functions what is slowing down your computation, you might try to approximate them with their Taylor expansions.
For x
close to zero the following identities hold:
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! + ...
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! + ...
atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ...
Based on the degree of accuracy you need for your application you can trim the series. For instance,
cos(x) = 1 - (x^2)/2
with an error of the order of x^3
(actually, x^4
, as the term with x^3
is zero anyway).
However, I don't think that this is going to solve your problem: the actual implementation of atan
is likely to be already using the same trick, written by someone with lots of experience of speeding these things up. So this is not really a proper answer but I hope it could still be useful.
Ah. Thanks for that explanation. This might be worth looking into. Although since my decay should be constant I think I might be able to get away with a pre-calculated lookup table. Appreciate it though!
– Scott Schafer
Jan 23 at 0:57
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54031622%2fhow-can-i-scale-a-2d-rotation-vector-without-trig-functions%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
If it's really the trigonometric functions what is slowing down your computation, you might try to approximate them with their Taylor expansions.
For x
close to zero the following identities hold:
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! + ...
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! + ...
atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ...
Based on the degree of accuracy you need for your application you can trim the series. For instance,
cos(x) = 1 - (x^2)/2
with an error of the order of x^3
(actually, x^4
, as the term with x^3
is zero anyway).
However, I don't think that this is going to solve your problem: the actual implementation of atan
is likely to be already using the same trick, written by someone with lots of experience of speeding these things up. So this is not really a proper answer but I hope it could still be useful.
Ah. Thanks for that explanation. This might be worth looking into. Although since my decay should be constant I think I might be able to get away with a pre-calculated lookup table. Appreciate it though!
– Scott Schafer
Jan 23 at 0:57
add a comment |
If it's really the trigonometric functions what is slowing down your computation, you might try to approximate them with their Taylor expansions.
For x
close to zero the following identities hold:
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! + ...
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! + ...
atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ...
Based on the degree of accuracy you need for your application you can trim the series. For instance,
cos(x) = 1 - (x^2)/2
with an error of the order of x^3
(actually, x^4
, as the term with x^3
is zero anyway).
However, I don't think that this is going to solve your problem: the actual implementation of atan
is likely to be already using the same trick, written by someone with lots of experience of speeding these things up. So this is not really a proper answer but I hope it could still be useful.
Ah. Thanks for that explanation. This might be worth looking into. Although since my decay should be constant I think I might be able to get away with a pre-calculated lookup table. Appreciate it though!
– Scott Schafer
Jan 23 at 0:57
add a comment |
If it's really the trigonometric functions what is slowing down your computation, you might try to approximate them with their Taylor expansions.
For x
close to zero the following identities hold:
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! + ...
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! + ...
atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ...
Based on the degree of accuracy you need for your application you can trim the series. For instance,
cos(x) = 1 - (x^2)/2
with an error of the order of x^3
(actually, x^4
, as the term with x^3
is zero anyway).
However, I don't think that this is going to solve your problem: the actual implementation of atan
is likely to be already using the same trick, written by someone with lots of experience of speeding these things up. So this is not really a proper answer but I hope it could still be useful.
If it's really the trigonometric functions what is slowing down your computation, you might try to approximate them with their Taylor expansions.
For x
close to zero the following identities hold:
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! + ...
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! + ...
atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ...
Based on the degree of accuracy you need for your application you can trim the series. For instance,
cos(x) = 1 - (x^2)/2
with an error of the order of x^3
(actually, x^4
, as the term with x^3
is zero anyway).
However, I don't think that this is going to solve your problem: the actual implementation of atan
is likely to be already using the same trick, written by someone with lots of experience of speeding these things up. So this is not really a proper answer but I hope it could still be useful.
answered Jan 21 at 19:18
Dominik MokrišDominik Mokriš
4041213
4041213
Ah. Thanks for that explanation. This might be worth looking into. Although since my decay should be constant I think I might be able to get away with a pre-calculated lookup table. Appreciate it though!
– Scott Schafer
Jan 23 at 0:57
add a comment |
Ah. Thanks for that explanation. This might be worth looking into. Although since my decay should be constant I think I might be able to get away with a pre-calculated lookup table. Appreciate it though!
– Scott Schafer
Jan 23 at 0:57
Ah. Thanks for that explanation. This might be worth looking into. Although since my decay should be constant I think I might be able to get away with a pre-calculated lookup table. Appreciate it though!
– Scott Schafer
Jan 23 at 0:57
Ah. Thanks for that explanation. This might be worth looking into. Although since my decay should be constant I think I might be able to get away with a pre-calculated lookup table. Appreciate it though!
– Scott Schafer
Jan 23 at 0:57
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54031622%2fhow-can-i-scale-a-2d-rotation-vector-without-trig-functions%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Simple formulas exist only for
SPIN_DECAY = 1/2
(and for arithmetic progressionan[i] = an0 - i*da
). Otherwise it would better to storeangle
to avoidatan2
. If you apply the same rotation to multiple points, single evaluation of sin/cos per step is not so bad.– MBo
Jan 4 at 5:35
1
what about this: How to calculate rocket? see the rotation math at the end... beware it works only for rotations up to
90deg
and the rotation is not linear but not too far from it either and works for any dimensionality...the dimming is done simply by decreasing thedang0
or bydang0*=0.95
each iteration etc ... you do not need theacos
for computinga
as you already know how much your original rotation rotates ...– Spektre
Jan 4 at 11:00
Another idea: what about approximating your trigonometric functions with their Taylor expansions?
– Dominik Mokriš
Jan 17 at 20:03
@DominikMokriš, that sounds intriguing. Can you say more and/or provide details? Not quite sure how to implement that. BTW, I did consider something like this lookup: int iX = int((spin.x + 1) * 100); int iY = int((spin.y + 1) * 100); spin = DecayLookupX[iX][iY]; Where DecayLookup is a 200 x 200 array of pre-calculated vectors (could be tuned). A bit rough, but would work for a constant decay.
– Scott Schafer
Jan 19 at 0:28