/* * Copyright 2014 Google Inc. All Rights Reserved. * * 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. */ package com.kitware.tangoutils; import android.opengl.Matrix; /** * Utility class to manage the calculation of a Model Matrix from the * translation and quaternion arrays obtained from an {@link TangoPose} object. * Delegates some mathematical computations to the {@link MathUtils}. */ public class ModelMatCalculator { private static float[] mConversionMatrix = new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; private float[] mModelMatrix = new float[16]; private float[] mPointCloudModelMatrix = new float[16]; private float[] mDevice2IMUMatrix = new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; private float[] mColorCamera2IMUMatrix = new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; private float[] mOpengl2ColorCameraMatrix = new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; public ModelMatCalculator() { Matrix.setIdentityM(mModelMatrix, 0); Matrix.setIdentityM(mPointCloudModelMatrix, 0); } /** * Updates the model matrix (rotation and translation). * * @param translation * a three-element array of translation data. * @param quaternion * a four-element array of rotation data. */ public void updatePointCloudModelMatrix(float[] translation, float[] quaternion) { float[] tempMultMatrix = new float[16]; Matrix.setIdentityM(tempMultMatrix, 0); Matrix.multiplyMM(tempMultMatrix, 0, mColorCamera2IMUMatrix, 0, mOpengl2ColorCameraMatrix, 0); float[] tempInvertMatrix = new float[16]; Matrix.setIdentityM(tempInvertMatrix, 0); Matrix.invertM(tempInvertMatrix, 0, mDevice2IMUMatrix, 0); float[] tempMultMatrix2 = new float[16]; Matrix.setIdentityM(tempMultMatrix2, 0); Matrix.multiplyMM(tempMultMatrix2, 0, tempInvertMatrix, 0, tempMultMatrix, 0); float[] quaternionMatrix = new float[16]; Matrix.setIdentityM(quaternionMatrix, 0); quaternionMatrix = quaternionMatrixOpenGL(quaternion); float[] tempMultMatrix3 = new float[16]; Matrix.setIdentityM(tempMultMatrix3, 0); Matrix.setIdentityM(mPointCloudModelMatrix, 0); Matrix.multiplyMM(tempMultMatrix3, 0, quaternionMatrix, 0, tempMultMatrix2, 0); Matrix.multiplyMM(mPointCloudModelMatrix, 0, mConversionMatrix, 0, tempMultMatrix3, 0); mPointCloudModelMatrix[12] += translation[0]; mPointCloudModelMatrix[13] += translation[2]; mPointCloudModelMatrix[14] += -1f * translation[1]; } /** * Updates the model matrix (rotation and translation). * * @param translation * a three-element array of translation data. * @param quaternion * a four-element array of rotation data. */ public void updateModelMatrix(float[] translation, float[] quaternion) { float[] tempMultMatrix = new float[16]; Matrix.setIdentityM(tempMultMatrix, 0); Matrix.multiplyMM(tempMultMatrix, 0, mColorCamera2IMUMatrix, 0, mOpengl2ColorCameraMatrix, 0); float[] tempInvertMatrix = new float[16]; Matrix.setIdentityM(tempInvertMatrix, 0); Matrix.invertM(tempInvertMatrix, 0, mDevice2IMUMatrix, 0); float[] tempMultMatrix2 = new float[16]; Matrix.setIdentityM(tempMultMatrix2, 0); Matrix.multiplyMM(tempMultMatrix2, 0, tempInvertMatrix, 0, tempMultMatrix, 0); float[] quaternionMatrix = new float[16]; Matrix.setIdentityM(quaternionMatrix, 0); quaternionMatrix = quaternionMatrixOpenGL(quaternion); float[] tempMultMatrix3 = new float[16]; Matrix.setIdentityM(tempMultMatrix3, 0); Matrix.setIdentityM(mModelMatrix, 0); Matrix.multiplyMM(tempMultMatrix3, 0, quaternionMatrix, 0, tempMultMatrix2, 0); Matrix.multiplyMM(mModelMatrix, 0, mConversionMatrix, 0, tempMultMatrix3, 0); mModelMatrix[12] += translation[0]; mModelMatrix[13] += translation[2]; mModelMatrix[14] += -1f * translation[1]; } public void SetDevice2IMUMatrix(float[] translation, float[] quaternion) { mDevice2IMUMatrix = quaternionMatrixOpenGL(quaternion); mDevice2IMUMatrix[12] = translation[0]; mDevice2IMUMatrix[13] = translation[1]; mDevice2IMUMatrix[14] = translation[2]; } public void SetColorCamera2IMUMatrix(float[] translation, float[] quaternion) { mOpengl2ColorCameraMatrix = new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; mColorCamera2IMUMatrix = quaternionMatrixOpenGL(quaternion); mColorCamera2IMUMatrix[12] = translation[0]; mColorCamera2IMUMatrix[13] = translation[1]; mColorCamera2IMUMatrix[14] = translation[2]; } public float[] getModelMatrix() { return mModelMatrix; } public float[] getModelMatrixCopy() { float[] modelMatCopy = new float[16]; System.arraycopy(mModelMatrix, 0, modelMatCopy, 0, 16); return modelMatCopy; } public float[] getPointCloudModelMatrixCopy() { float[] modelMatCopy = new float[16]; float[] tempMultMat = new float[16]; Matrix.setIdentityM(tempMultMat, 0); float[] invertYandZMatrix = new float[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; Matrix.multiplyMM(tempMultMat, 0, mPointCloudModelMatrix, 0, invertYandZMatrix, 0); System.arraycopy(tempMultMat, 0, modelMatCopy, 0, 16); return modelMatCopy; } public float[] getTranslation() { return new float[] { mModelMatrix[12], mModelMatrix[13], mModelMatrix[14] }; } /** * A function to convert a quaternion to quaternion Matrix. Please note that * Opengl.Matrix is Column Major and so we construct the matrix in Column * Major Format. - - - - | 0 4 8 12 | | 1 5 9 13 | | 2 6 10 14 | | 3 7 11 15 * | - - - - * * @param quaternion * Input quaternion with float[4] * @return Quaternion Matrix of float[16] */ public static float[] quaternionMatrixOpenGL(float[] quaternion) { float[] matrix = new float[16]; normalizeVector(quaternion); float x = quaternion[0]; float y = quaternion[1]; float z = quaternion[2]; float w = quaternion[3]; float x2 = x * x; float y2 = y * y; float z2 = z * z; float xy = x * y; float xz = x * z; float yz = y * z; float wx = w * x; float wy = w * y; float wz = w * z; matrix[0] = 1f - 2f * (y2 + z2); matrix[4] = 2f * (xy - wz); matrix[8] = 2f * (xz + wy); matrix[12] = 0f; matrix[1] = 2f * (xy + wz); matrix[5] = 1f - 2f * (x2 + z2); matrix[9] = 2f * (yz - wx); matrix[13] = 0f; matrix[2] = 2f * (xz - wy); matrix[6] = 2f * (yz + wx); matrix[10] = 1f - 2f * (x2 + y2); matrix[14] = 0f; matrix[3] = 0f; matrix[7] = 0f; matrix[11] = 0f; matrix[15] = 1f; return matrix; } /** * Creates a unit vector in the direction of an arbitrary vector. The * original vector is modified in place. * * @param v * the vector to normalize */ public static void normalizeVector(float[] v) { float mag2 = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; if (Math.abs(mag2) > 0.00001f && Math.abs(mag2 - 1.0f) > 0.00001f) { float mag = (float) Math.sqrt(mag2); v[0] = v[0] / mag; v[1] = v[1] / mag; v[2] = v[2] / mag; v[3] = v[3] / mag; } } }