// Copyright 2008 Google Inc. // // 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.google.android.stardroid.util; import java.util.Date; import com.google.android.stardroid.units.GeocentricCoordinates; import com.google.android.stardroid.units.LatLong; import com.google.android.stardroid.units.Matrix33; import com.google.android.stardroid.units.RaDec; import com.google.android.stardroid.units.Vector3; /** * Utilities for working with angles, distances, matrices, and time. * * @author Kevin Serafini * @author Brent Bryan * @author Dominic Widdows * @author John Taylor */ public class Geometry { // Convert Degrees to Radians public static final float DEGREES_TO_RADIANS = MathUtil.PI / 180.0f; // Convert Radians to Degrees public static final float RADIANS_TO_DEGREES = 180.0f / MathUtil.PI; private Geometry() { } /** * Return the integer part of a number */ public static float abs_floor(float x) { float result; if (x >= 0.0) result = MathUtil.floor(x); else result = MathUtil.ceil(x); return result; } /** * Returns the modulo the given value by 2\pi. Returns an angle in the range 0 * to 2\pi radians. */ public static float mod2pi(float x) { float factor = x / MathUtil.TWO_PI; float result = MathUtil.TWO_PI * (factor - abs_floor(factor)); if (result < 0.0) { result = MathUtil.TWO_PI + result; } return result; } public static float scalarProduct(Vector3 v1, Vector3 v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } public static Vector3 vectorProduct(Vector3 v1, Vector3 v2) { return new Vector3(v1.y * v2.z - v1.z * v2.y, -v1.x * v2.z + v1.z * v2.x, v1.x * v2.y - v1.y * v2.x); } /** * Scales the vector by the given amount */ public static Vector3 scaleVector(Vector3 v, float scale) { return new Vector3 (scale * v.x, scale * v.y, scale * v.z); } /** * Creates and returns a new Vector3 which is the sum of both arguments. * @param first * @param second * @return vector sum first + second */ public static Vector3 addVectors(Vector3 first, Vector3 second) { return new Vector3(first.x + second.x, first.y + second.y, first.z + second.z); } public static float cosineSimilarity(Vector3 v1, Vector3 v2) { // We might want to optimize this implementation at some point. return scalarProduct(v1, v2) / MathUtil.sqrt(scalarProduct(v1, v1) * scalarProduct(v2, v2)); } /** * Convert ra and dec to x,y,z where the point is place on the unit sphere. */ public static GeocentricCoordinates getXYZ(RaDec raDec) { float raRadians = raDec.ra * DEGREES_TO_RADIANS; float decRadians = raDec.dec * DEGREES_TO_RADIANS; GeocentricCoordinates result = new GeocentricCoordinates( MathUtil.cos(raRadians) * MathUtil.cos(decRadians), MathUtil.sin(raRadians) * MathUtil.cos(decRadians), MathUtil.sin(decRadians)); return result; } /** * Compute celestial coordinates of zenith from utc, lat long. */ public static RaDec calculateRADecOfZenith(Date utc, LatLong location) { // compute overhead RA in degrees float my_ra = TimeUtil.meanSiderealTime(utc, location.longitude); float my_dec = location.latitude; return new RaDec(my_ra, my_dec); } /** * Multiply two 3X3 matrices m1 * m2. */ public static Matrix33 matrixMultiply(Matrix33 m1, Matrix33 m2) { return new Matrix33(m1.xx*m2.xx + m1.xy*m2.yx + m1.xz*m2.zx, m1.xx*m2.xy + m1.xy*m2.yy + m1.xz*m2.zy, m1.xx*m2.xz + m1.xy*m2.yz + m1.xz*m2.zz, m1.yx*m2.xx + m1.yy*m2.yx + m1.yz*m2.zx, m1.yx*m2.xy + m1.yy*m2.yy + m1.yz*m2.zy, m1.yx*m2.xz + m1.yy*m2.yz + m1.yz*m2.zz, m1.zx*m2.xx + m1.zy*m2.yx + m1.zz*m2.zx, m1.zx*m2.xy + m1.zy*m2.yy + m1.zz*m2.zy, m1.zx*m2.xz + m1.zy*m2.yz + m1.zz*m2.zz); } /** * Calculate w = m * v where m is a 3X3 matrix and v a column vector. */ public static Vector3 matrixVectorMultiply(Matrix33 m, Vector3 v) { return new Vector3(m.xx*v.x + m.xy*v.y + m.xz*v.z, m.yx*v.x + m.yy*v.y + m.yz*v.z, m.zx*v.x + m.zy*v.y + m.zz*v.z); } /** * Calculate the rotation matrix for a certain number of degrees about the * give axis. * @param degrees * @param axis - must be a unit vector. */ public static Matrix33 calculateRotationMatrix(float degrees, Vector3 axis) { // Construct the rotation matrix about this vector float cosD = MathUtil.cos(degrees * Geometry.DEGREES_TO_RADIANS); float sinD = MathUtil.sin(degrees * Geometry.DEGREES_TO_RADIANS); float oneMinusCosD = 1f - cosD; float x = axis.x; float y = axis.y; float z = axis.z; float xs = x * sinD; float ys = y * sinD; float zs = z * sinD; float xm = x * oneMinusCosD; float ym = y * oneMinusCosD; float zm = z * oneMinusCosD; float xym = x * ym; float yzm = y * zm; float zxm = z * xm; Matrix33 rotationMatrix = new Matrix33(x * xm + cosD, xym + zs, zxm - ys, xym - zs, y * ym+cosD, yzm + xs, zxm + ys, yzm - xs, z * zm + cosD); return rotationMatrix; } }