Various corrections in 2D math.

This is the follow up for the 2D changes mentioned in PR #6865. It fixes various mistakes regarding the order of matrix indices, order of transformation operations, usage of atan2 function and ensures that the sense of rotation is compatible with a left-handed coordinate system with Y-axis pointing down (which flips the sense of rotations along the z-axis). Also replaced float with real_t, and tried to make use of Matrix32 methods rather than accessing its elements directly.

Affected code in the Godot code base is also fixed in this commit.

The user code using functions involving angles such as atan2, angle_to, get_rotation, set_rotation will need to be updated to conform with the new behavior. Furthermore, the sign of the rotation angles in existing 2D scene files need to be flipped as well.
This commit is contained in:
Ferenc Arn
2017-01-05 23:27:48 -06:00
parent 99ceddd11e
commit f271591ac2
8 changed files with 126 additions and 116 deletions

View File

@ -31,22 +31,22 @@
real_t Vector2::angle() const {
return Math::atan2(x,y);
return Math::atan2(y,x);
}
float Vector2::length() const {
real_t Vector2::length() const {
return Math::sqrt( x*x + y*y );
}
float Vector2::length_squared() const {
real_t Vector2::length_squared() const {
return x*x + y*y;
}
void Vector2::normalize() {
float l = x*x + y*y;
real_t l = x*x + y*y;
if (l!=0) {
l=Math::sqrt(l);
@ -62,32 +62,32 @@ Vector2 Vector2::normalized() const {
return v;
}
float Vector2::distance_to(const Vector2& p_vector2) const {
real_t Vector2::distance_to(const Vector2& p_vector2) const {
return Math::sqrt( (x-p_vector2.x)*(x-p_vector2.x) + (y-p_vector2.y)*(y-p_vector2.y));
}
float Vector2::distance_squared_to(const Vector2& p_vector2) const {
real_t Vector2::distance_squared_to(const Vector2& p_vector2) const {
return (x-p_vector2.x)*(x-p_vector2.x) + (y-p_vector2.y)*(y-p_vector2.y);
}
float Vector2::angle_to(const Vector2& p_vector2) const {
real_t Vector2::angle_to(const Vector2& p_vector2) const {
return Math::atan2( tangent().dot(p_vector2), dot(p_vector2) );
return Math::atan2( cross(p_vector2), dot(p_vector2) );
}
float Vector2::angle_to_point(const Vector2& p_vector2) const {
real_t Vector2::angle_to_point(const Vector2& p_vector2) const {
return Math::atan2( x-p_vector2.x, y - p_vector2.y );
return Math::atan2( y - p_vector2.y, x-p_vector2.x );
}
float Vector2::dot(const Vector2& p_other) const {
real_t Vector2::dot(const Vector2& p_other) const {
return x*p_other.x + y*p_other.y;
}
float Vector2::cross(const Vector2& p_other) const {
real_t Vector2::cross(const Vector2& p_other) const {
return x*p_other.y - y*p_other.x;
}
@ -120,11 +120,11 @@ Vector2 Vector2::operator*(const Vector2 &p_v1) const {
return Vector2(x * p_v1.x, y * p_v1.y);
};
Vector2 Vector2::operator*(const float &rvalue) const {
Vector2 Vector2::operator*(const real_t &rvalue) const {
return Vector2(x * rvalue, y * rvalue);
};
void Vector2::operator*=(const float &rvalue) {
void Vector2::operator*=(const real_t &rvalue) {
x *= rvalue; y *= rvalue;
};
@ -134,12 +134,12 @@ Vector2 Vector2::operator/(const Vector2 &p_v1) const {
return Vector2(x / p_v1.x, y / p_v1.y);
};
Vector2 Vector2::operator/(const float &rvalue) const {
Vector2 Vector2::operator/(const real_t &rvalue) const {
return Vector2(x / rvalue, y / rvalue);
};
void Vector2::operator/=(const float &rvalue) {
void Vector2::operator/=(const real_t &rvalue) {
x /= rvalue; y /= rvalue;
};
@ -162,7 +162,7 @@ Vector2 Vector2::floor() const {
return Vector2( Math::floor(x), Math::floor(y) );
}
Vector2 Vector2::rotated(float p_by) const {
Vector2 Vector2::rotated(real_t p_by) const {
Vector2 v;
v.set_rotation(angle()+p_by);
@ -198,7 +198,7 @@ Vector2 Vector2::clamped(real_t p_len) const {
return v;
}
Vector2 Vector2::cubic_interpolate_soft(const Vector2& p_b,const Vector2& p_pre_a, const Vector2& p_post_b,float p_t) const {
Vector2 Vector2::cubic_interpolate_soft(const Vector2& p_b,const Vector2& p_pre_a, const Vector2& p_post_b,real_t p_t) const {
#if 0
k[0] = ((*this) (vi[0] + 1, vi[1], vi[2])) - ((*this) (vi[0],
vi[1],vi[2])); //fk = a0
@ -219,13 +219,13 @@ Vector2 Vector2::cubic_interpolate_soft(const Vector2& p_b,const Vector2& p_pre_
//dk = (fk+1 - fk-1)*0.5
//Dk = (fk+1 - fk)
float dk =
real_t dk =
#endif
return Vector2();
}
Vector2 Vector2::cubic_interpolate(const Vector2& p_b,const Vector2& p_pre_a, const Vector2& p_post_b,float p_t) const {
Vector2 Vector2::cubic_interpolate(const Vector2& p_b,const Vector2& p_pre_a, const Vector2& p_post_b,real_t p_t) const {
@ -234,9 +234,9 @@ Vector2 Vector2::cubic_interpolate(const Vector2& p_b,const Vector2& p_pre_a, co
Vector2 p2=p_b;
Vector2 p3=p_post_b;
float t = p_t;
float t2 = t * t;
float t3 = t2 * t;
real_t t = p_t;
real_t t2 = t * t;
real_t t3 = t2 * t;
Vector2 out;
out = 0.5f * ( ( p1 * 2.0f) +
@ -246,8 +246,8 @@ Vector2 Vector2::cubic_interpolate(const Vector2& p_b,const Vector2& p_pre_a, co
return out;
/*
float mu = p_t;
float mu2 = mu*mu;
real_t mu = p_t;
real_t mu2 = mu*mu;
Vector2 a0 = p_post_b - p_b - p_pre_a + *this;
Vector2 a1 = p_pre_a - *this - a0;
@ -257,7 +257,7 @@ Vector2 Vector2::cubic_interpolate(const Vector2& p_b,const Vector2& p_pre_a, co
return ( a0*mu*mu2 + a1*mu2 + a2*mu + a3 );
*/
/*
float t = p_t;
real_t t = p_t;
real_t t2 = t*t;
real_t t3 = t2*t;
@ -291,7 +291,7 @@ bool Rect2::intersects_segment(const Point2& p_from, const Point2& p_to, Point2*
real_t min=0,max=1;
int axis=0;
float sign=0;
real_t sign=0;
for(int i=0;i<2;i++) {
real_t seg_from=p_from[i];
@ -299,7 +299,7 @@ bool Rect2::intersects_segment(const Point2& p_from, const Point2& p_to, Point2*
real_t box_begin=pos[i];
real_t box_end=box_begin+size[i];
real_t cmin,cmax;
float csign;
real_t csign;
if (seg_from < seg_to) {
@ -409,7 +409,8 @@ bool Point2i::operator!=(const Point2i& p_vec2) const {
}
void Matrix32::invert() {
// FIXME: this function assumes the basis is a rotation matrix, with no scaling.
// Matrix32::affine_inverse can handle matrices with scaling, so GDScript should eventually use that.
SWAP(elements[0][1],elements[1][0]);
elements[2] = basis_xform(-elements[2]);
}
@ -424,9 +425,9 @@ Matrix32 Matrix32::inverse() const {
void Matrix32::affine_invert() {
float det = basis_determinant();
real_t det = basis_determinant();
ERR_FAIL_COND(det==0);
float idet = 1.0 / det;
real_t idet = 1.0 / det;
SWAP( elements[0][0],elements[1][1] );
elements[0]*=Vector2(idet,-idet);
@ -444,14 +445,16 @@ Matrix32 Matrix32::affine_inverse() const {
}
void Matrix32::rotate(real_t p_phi) {
Matrix32 rot(p_phi,Vector2());
*this *= rot;
*this = Matrix32(p_phi,Vector2()) * (*this);
}
real_t Matrix32::get_rotation() const {
return Math::atan2(elements[1].x,elements[1].y);
real_t det = basis_determinant();
Matrix32 m = orthonormalized();
if (det < 0) {
m.scale_basis(Size2(-1,-1));
}
return Math::atan2(m[0].y,m[0].x);
}
void Matrix32::set_rotation(real_t p_rot) {
@ -459,9 +462,9 @@ void Matrix32::set_rotation(real_t p_rot) {
real_t cr = Math::cos(p_rot);
real_t sr = Math::sin(p_rot);
elements[0][0]=cr;
elements[0][1]=sr;
elements[1][0]=-sr;
elements[1][1]=cr;
elements[0][1]=-sr;
elements[1][0]=sr;
}
Matrix32::Matrix32(real_t p_rot, const Vector2& p_pos) {
@ -469,27 +472,27 @@ Matrix32::Matrix32(real_t p_rot, const Vector2& p_pos) {
real_t cr = Math::cos(p_rot);
real_t sr = Math::sin(p_rot);
elements[0][0]=cr;
elements[0][1]=sr;
elements[1][0]=-sr;
elements[1][1]=cr;
elements[0][1]=-sr;
elements[1][0]=sr;
elements[2]=p_pos;
}
Size2 Matrix32::get_scale() const {
return Size2( elements[0].length(), elements[1].length() );
real_t det_sign = basis_determinant() > 0 ? 1 : -1;
return det_sign * Size2( elements[0].length(), elements[1].length() );
}
void Matrix32::scale(const Size2& p_scale) {
elements[0]*=p_scale;
elements[1]*=p_scale;
scale_basis(p_scale);
elements[2]*=p_scale;
}
void Matrix32::scale_basis(const Size2& p_scale) {
elements[0]*=p_scale;
elements[1]*=p_scale;
elements[0][0]*=p_scale.x;
elements[0][1]*=p_scale.y;
elements[1][0]*=p_scale.x;
elements[1][1]*=p_scale.y;
}
void Matrix32::translate( real_t p_tx, real_t p_ty) {
@ -548,7 +551,7 @@ void Matrix32::operator*=(const Matrix32& p_transform) {
elements[2] = xform(p_transform.elements[2]);
float x0,x1,y0,y1;
real_t x0,x1,y0,y1;
x0 = tdotx(p_transform.elements[0]);
x1 = tdoty(p_transform.elements[0]);
@ -601,7 +604,7 @@ Matrix32 Matrix32::translated(const Vector2& p_offset) const {
}
Matrix32 Matrix32::rotated(float p_phi) const {
Matrix32 Matrix32::rotated(real_t p_phi) const {
Matrix32 copy=*this;
copy.rotate(p_phi);
@ -609,12 +612,12 @@ Matrix32 Matrix32::rotated(float p_phi) const {
}
float Matrix32::basis_determinant() const {
real_t Matrix32::basis_determinant() const {
return elements[0].x * elements[1].y - elements[0].y * elements[1].x;
}
Matrix32 Matrix32::interpolate_with(const Matrix32& p_transform, float p_c) const {
Matrix32 Matrix32::interpolate_with(const Matrix32& p_transform, real_t p_c) const {
//extract parameters
Vector2 p1 = get_origin();