core/indigo-core/common/math/transform3f.cpp (230 lines of code) (raw):

/**************************************************************************** * Copyright (C) from 2009 to Present EPAM Systems. * * This file is part of Indigo toolkit. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ #include <string.h> #include "math/algebra.h" using namespace indigo; IMPL_ERROR(Transform3f, "transform3f"); void Transform3f::copy(const Transform3f& other) { memcpy(elements, other.elements, 16 * sizeof(float)); } void Transform3f::getOrigin(Vec3f& origin) { origin.set(elements[12], elements[13], elements[14]); } bool Transform3f::inversion(const Transform3f& matr) { if (&matr == this) throw Error("can not do inversion() of self"); if ((float)fabs(matr.elements[3]) > EPSILON || (float)fabs(matr.elements[7]) > EPSILON || (float)fabs(matr.elements[11]) > EPSILON) return false; elements[0] = matr.elements[0]; elements[1] = matr.elements[4]; elements[2] = matr.elements[8]; elements[3] = 0; elements[4] = matr.elements[1]; elements[5] = matr.elements[5]; elements[6] = matr.elements[9]; elements[7] = 0; elements[8] = matr.elements[2]; elements[9] = matr.elements[6]; elements[10] = matr.elements[10]; elements[11] = 0; elements[12] = -matr.elements[0] * matr.elements[12] - matr.elements[1] * matr.elements[13] - matr.elements[2] * matr.elements[14]; elements[13] = -matr.elements[4] * matr.elements[12] - matr.elements[5] * matr.elements[13] - matr.elements[6] * matr.elements[14]; elements[14] = -matr.elements[8] * matr.elements[12] - matr.elements[9] * matr.elements[13] - matr.elements[10] * matr.elements[14]; elements[15] = 1.f; return true; } void Transform3f::rotation(float x, float y, float z, float angle) { float len = (float)sqrt(x * x + y * y + z * z); float Sin = (float)sin(angle), Cos = (float)cos(angle), Vers = 1 - Cos; if (len > EPSILON) { x /= len; y /= len; z /= len; } elements[0] = x * x + Cos * (1 - x * x); elements[1] = x * Vers * y - z * Sin; elements[2] = x * Vers * z + y * Sin; elements[3] = 0; elements[4] = x * Vers * y + z * Sin; elements[5] = y * y + Cos * (1 - y * y); elements[6] = y * Vers * z - x * Sin; elements[7] = 0; elements[8] = x * Vers * z - y * Sin; elements[9] = y * Vers * z + x * Sin; elements[10] = z * z + Cos * (1 - z * z); elements[11] = 0; elements[12] = 0; elements[13] = 0; elements[14] = 0; elements[15] = 1; } void Transform3f::transform(const Transform3f& transform) { Transform3f tmp; tmp.composition(*this, transform); copy(tmp); } void Transform3f::transformLocal(const Transform3f& transform) { Transform3f tmp; tmp.composition(transform, *this); copy(tmp); } void Transform3f::rotateX(float angle) { Transform3f rot; rot.rotationX(angle); transform(rot); } void Transform3f::rotateY(float angle) { Transform3f rot; rot.rotationY(angle); transform(rot); } void Transform3f::rotateZ(float angle) { Transform3f rot; rot.rotationZ(angle); transform(rot); } void Transform3f::rotateXLocal(float angle) { Transform3f rot; rot.rotationX(angle); transformLocal(rot); } void Transform3f::rotateYLocal(float angle) { Transform3f rot; rot.rotationY(angle); transformLocal(rot); } void Transform3f::rotateZLocal(float angle) { Transform3f rot; rot.rotationZ(angle); transformLocal(rot); } void Transform3f::translate(const Vec3f& translation) { elements[12] += translation.x; elements[13] += translation.y; elements[14] += translation.z; } void Transform3f::translateInv(const Vec3f& translation) { elements[12] -= translation.x; elements[13] -= translation.y; elements[14] -= translation.z; } void Transform3f::rotationX(float angle) { float sine = (float)sin(angle), cosine = (float)cos(angle); memset(elements, 0, 16 * sizeof(float)); elements[0] = 1.f; elements[5] = cosine; elements[6] = sine; elements[9] = -sine; elements[10] = cosine; elements[15] = 1.f; } void Transform3f::rotationY(float angle) { float sine = (float)sin(angle), cosine = (float)cos(angle); memset(elements, 0, 16 * sizeof(float)); elements[0] = cosine; elements[2] = -sine; elements[8] = sine; elements[10] = cosine; elements[5] = 1.f; elements[15] = 1.f; } void Transform3f::rotationZ(float angle) { float sine = (float)sin(angle), cosine = (float)cos(angle); memset(elements, 0, 16 * sizeof(float)); elements[0] = cosine; elements[1] = sine; elements[4] = -sine; elements[5] = cosine; elements[10] = 1.f; elements[15] = 1.f; } void Transform3f::composition(const Transform3f& a, const Transform3f& b) { elements[0] = a.elements[0] * b.elements[0] + a.elements[1] * b.elements[4] + a.elements[2] * b.elements[8]; elements[1] = a.elements[0] * b.elements[1] + a.elements[1] * b.elements[5] + a.elements[2] * b.elements[9]; elements[2] = a.elements[0] * b.elements[2] + a.elements[1] * b.elements[6] + a.elements[2] * b.elements[10]; elements[3] = 0; elements[4] = a.elements[4] * b.elements[0] + a.elements[5] * b.elements[4] + a.elements[6] * b.elements[8]; elements[5] = a.elements[4] * b.elements[1] + a.elements[5] * b.elements[5] + a.elements[6] * b.elements[9]; elements[6] = a.elements[4] * b.elements[2] + a.elements[5] * b.elements[6] + a.elements[6] * b.elements[10]; elements[7] = 0; elements[8] = a.elements[8] * b.elements[0] + a.elements[9] * b.elements[4] + a.elements[10] * b.elements[8]; elements[9] = a.elements[8] * b.elements[1] + a.elements[9] * b.elements[5] + a.elements[10] * b.elements[9]; elements[10] = a.elements[8] * b.elements[2] + a.elements[9] * b.elements[6] + a.elements[10] * b.elements[10]; elements[11] = 0; elements[12] = a.elements[12] * b.elements[0] + a.elements[13] * b.elements[4] + a.elements[14] * b.elements[8] + b.elements[12]; elements[13] = a.elements[12] * b.elements[1] + a.elements[13] * b.elements[5] + a.elements[14] * b.elements[9] + b.elements[13]; elements[14] = a.elements[12] * b.elements[2] + a.elements[13] * b.elements[6] + a.elements[14] * b.elements[10] + b.elements[14]; elements[15] = 1; } void Transform3f::identity(void) { memset(elements, 0, 16 * sizeof(float)); elements[0] = 1.f; elements[5] = 1.f; elements[10] = 1.f; elements[15] = 1.f; } void Transform3f::translateLocal(float x, float y, float z) { elements[12] += elements[0] * x + elements[4] * y + elements[8] * z; elements[13] += elements[1] * x + elements[5] * y + elements[9] * z; elements[14] += elements[2] * x + elements[6] * y + elements[10] * z; } void Transform3f::translateLocal(const Vec3f& translation) { translateLocal(translation.x, translation.y, translation.z); } void Transform3f::translateLocalInv(const Vec3f& translation) { translateLocal(-translation.x, -translation.y, -translation.z); } void Transform3f::setOrigin(float x, float y, float z) { elements[12] = x; elements[13] = y; elements[14] = z; } void Transform3f::setOrigin(const Vec3f& origin) { setOrigin(origin.x, origin.y, origin.z); } bool Transform3f::rotationVecVec(const Vec3f& v1, const Vec3f& v2) { Vec3f v1_norm, v2_norm; if (!v1_norm.normalization(v1) || !v2_norm.normalization(v2)) return false; Vec3f cross; cross.cross(v1_norm, v2_norm); if (!cross.normalize()) { // cross product have zero length -> v1 & v2 are codirectional identity(); return true; } float dot = Vec3f::dot(v1_norm, v2_norm); float ang; if (dot > 1.f - EPSILON) ang = 0.f; else if (dot < -1.f + EPSILON) ang = _2FLOAT(-M_PI); else ang = _2FLOAT(-acos(dot)); rotation(cross.x, cross.y, cross.z, ang); return true; }