Jump to content

  • Log In with Google      Sign In   
  • Create Account

#ActualÁlvaro

Posted 15 January 2013 - 12:54 PM

I like to use complex numbers to do computations in 2D geometry. Applying a rotation is represented by multiplication by a complex number whose modulus is 1. If I have a vector A and I am trying to make it point towards vector B, the rotation I need to apply is B/A normalized. I can then limit that rotation to something close to 1 (1 being no rotation, since I am multiplying).

This code is in C++, but hopefully I managed to make it reasonably clear. Notice how the loop doesn't have any trigonometric functions at all. There are also basically no special cases.
#include <iostream>
#include <complex>
#include <cmath>

typedef std::complex<float> C;

float const pi = std::atan(1.0f)*4.0f;

C normalize(C z) {
  return z/std::abs(z);
}

C limited_rotation_towards(C original, C target, C max_rotation) {
  C rotation = normalize(target / original);
  if (rotation.real() < max_rotation.real())
    return rotation.imag() > 0.0f ? max_rotation : conj(max_rotation);
  return rotation;
}

int main() {
  C z = 1.0f;
  C target (-1.0f, -1.0f);
  float max_angle = pi*0.125f;
  C max_rotation(std::cos(max_angle), std::sin(max_angle));

  for (int i=0; i<20; ++i) {
    std::cout << z << '\n';
    z *= limited_rotation_towards(z, target, max_rotation);
  }
}

The output is this:
(1,0)
(0.92388,-0.382683)
(0.707107,-0.707107)
(0.382683,-0.92388)
(-1.49012e-07,-1)
(-0.382684,-0.923879)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)

#5Álvaro

Posted 15 January 2013 - 12:53 PM

I like to use complex numbers to do computations in 2D geometry. Applying a rotation is represented by multiplication by a complex number whose modulus is 1. If I have a vector A and I am trying to make it point towards vector B, the rotation I need to apply is B/A normalized. I can then limit that rotation to something close to 1 (1 being no rotation, since I am multiplying).

This code is in C++, but hopefully I managed to make it reasonably clear. Notice how the loop doesn't have any trigonometric functions at all. There are also basically no special cases.
#include <iostream>
#include <complex>
#include <cmath>

typedef std::complex<float> C;

float const pi = std::atan(1.0f)*4.0f;

C normalize(C z) {
  return z/std::abs(z);
}

C limited_rotation_towards(C original, C target, C max_rotation) {
  C rotation = normalize(target / original);
  if (rotation.real() < max_rotation.real())
    return rotation.imag() > 0.0f ? max_rotation : conj(max_rotation);
  return rotation;
}

int main() {
  C z = 1.0f;
  C target (-1.0f, -1.0f);
  float max_angle = pi*0.125f;
  C max_rotation(std::cos(max_angle), std::sin(max_angle));

  for (int i=0; i<20; ++i) {
    std::cout << z << '\n';
    z *= limited_rotation_towards(z, target, max_rotation);
  }
}

The output is this:
1,0)
(0.92388,-0.382683)
(0.707107,-0.707107)
(0.382683,-0.92388)
(-1.49012e-07,-1)
(-0.382684,-0.923879)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)

#4Álvaro

Posted 15 January 2013 - 12:53 PM

I like to use complex numbers to do computations in 2D geometry. Applying a rotation is represented by multiplication by a complex number whose modulus is 1. If I have a vector A and I am trying to make it point towards vector B, the rotation I need to apply is B/A normalized. I can then limit that rotation to something close to 1 (1 being no rotation, since I am multiplying).

This code is in C++, but hopefully I managed to make it reasonably clear. Notice how the loop doesn't have any trigonometric functions at all. There are also basically no special cases.
#include <iostream>
#include <complex>
#include <cmath>

typedef std::complex<float> C;

float const pi = std::atan(1.0f)*4.0f;

C normalize(C z) {
  return z/std::abs(z);
}

C limited_rotation_towards(C original, C target, C max_rotation) {
  C rotation = normalize(target / original);
  if (rotation.real() < max_rotation.real())
    return rotation.imag() > 0.0f ? max_rotation : conj(max_rotation);
  return rotation;
}

int main() {
  C z = 1.0f;
  C target (-1.0f, -1.0f);
  float max_angle = pi*0.125f;
  C max_rotation(std::cos(max_angle), std::sin(max_angle));

  for (int i=0; i<20; ++i) {
    std::cout << z << '\n';
    z *= limited_rotation_towards(z, target, max_rotation);
  }
}

The output is this:
(1,0)
(0.92388,-0.382683)
(0.707107,-0.707107)
(0.382683,-0.92388)
(-2.08616e-07,-1)
(-0.382684,-0.923879)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)

#3Álvaro

Posted 15 January 2013 - 12:52 PM

I like to use complex numbers to do computations in 2D geometry. Applying a rotation is represented by multiplication by a complex number whose modulus is 1. If I have a vector A and I am trying to make it point towards vector B, the rotation I need to apply is B/A normalized. I can then limit that rotation to something close to 1 (1 being no rotation, since I am multiplying).

This code is in C++, but hopefully I managed to make it reasonably clear. Notice how the loop doesn't have any trigonometric functions at all. There are also basically no special cases.
#include <iostream>
#include <complex>
#include <cmath>

typedef std::complex<float> C;

float sign(float x) {
  return (x > 0.0f) ? 1.0f : -1.0f;
}

float const pi = std::atan(1.0f)*4.0f;

C normalize(C z) {
  return z/std::abs(z);
}

C limited_rotation_towards(C original, C target, C max_rotation) {
  C rotation = normalize(target / original);
  if (rotation.real() < max_rotation.real())
    return C(max_rotation.real(),
             sign(rotation.imag())*max_rotation.imag());
  return rotation;
}

int main() {
  C z = 1.0f;
  C target (-1.0f, -1.0f);
  float max_angle = pi*0.125f;
  C max_rotation(std::cos(max_angle), std::sin(max_angle));

  for (int i=0; i<20; ++i) {
    std::cout << z << '\n';
    z *= limited_rotation_towards(z, target, max_rotation);
  }
}

The output is this:
(1,0)
(0.92388,-0.382683)
(0.707107,-0.707107)
(0.382683,-0.92388)
(-2.08616e-07,-1)
(-0.382684,-0.923879)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)

#2Álvaro

Posted 15 January 2013 - 12:50 PM

I like to use complex numbers to do computations in 2D geometry. Applying a rotation is represented by multiplication by a complex number whose modulus is 1. If I have a vector A and I am trying to make it point towards vector B, the rotation I need to apply is B/A normalized. I can then limit that rotation to something close to 1 (1 being no rotation, since I am multiplying).

This code is in C++, but hopefully I managed to make it reasonably clear.
#include <iostream>
#include <complex>
#include <cmath>

typedef std::complex<float> C;

float sign(float x) {
  return (x > 0.0f) - (x < 0.0f);
}

float const pi = std::atan(1.0f)*4.0f;

C normalize(C z) {
  return z/std::abs(z);
}

C limited_rotation_towards(C original, C target, C max_rotation) {
  C rotation = normalize(target / original);
  if (rotation.real() < max_rotation.real())
    return C(max_rotation.real(),
             sign(rotation.imag())*max_rotation.imag());
  return rotation;
}

int main() {
  C z = 1.0f;
  C target (-1.0f, -1.0f);
  float max_angle = pi*0.125f;
  C max_rotation(std::cos(max_angle), std::sin(max_angle));

  for (int i=0; i<20; ++i) {
    std::cout << z << '\n';
    z *= limited_rotation_towards(z, target, max_rotation);
  }
}

The output is this:
(1,0)
(0.92388,-0.382683)
(0.707107,-0.707107)
(0.382683,-0.92388)
(-2.08616e-07,-1)
(-0.382684,-0.923879)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)

#1Álvaro

Posted 15 January 2013 - 12:47 PM

I like to use complex numbers to do computations in 2D geometry. Applying a rotation is represented by multiplication by a complex number whose modulus is 1. If I have a vector A and I am trying to make it point towards vector B, the rotation I need to apply is B/A normalized. I can then limit that rotation to something close to 1 (1 being no rotation, since I am multiplying).

This code is in C++, but hopefully I managed to make it reasonably clear.
#include <iostream>
#include <complex>
#include <cmath>

typedef std::complex<float> C;

float sign(float x) {
  return (x > 0.0f) - (x < 0.0f);
}

float const pi = std::atan(1.0f)*4.0f;

C normalize(C z) {
  return z / std::abs(z);
}

C limited_rotation_towards(C original, C target, float min_cosine) {
  C rotation = normalize(target / original);
  if (rotation.real() < min_cosine)
    return C(min_cosine,
             sign(rotation.imag())*std::sqrt(1.0f-min_cosine*min_cosine));
  return rotation;
}

int main() {
  C z = 1.0f;
  C target (-1.0f, -1.0f);
  float max_angle = pi*0.125f;
  float min_cosine = std::cos(max_angle);

  for (int i=0; i<20; ++i) {
    std::cout << z << '\n';
    z *= limited_rotation_towards(z, target, min_cosine);
  }
}

The output is this:
(1,0)
(0.92388,-0.382683)
(0.707107,-0.707107)
(0.382683,-0.92388)
(-2.08616e-07,-1)
(-0.382684,-0.923879)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)
(-0.707107,-0.707107)

PARTNERS