/****************************************************************************** * $Id: AKFS_Direction.c 580 2012-03-29 09:56:21Z yamada.rj $ ****************************************************************************** * * Copyright (C) 2012 Asahi Kasei Microdevices Corporation, Japan * * 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 "AKFS_Direction.h" #include "AKFS_VNorm.h" #include "AKFS_Math.h" /* Coordinate system is right-handed. X-Axis: from left to right. Y-Axis: from bottom to top. Z-Axis: from reverse to obverse. azimuth: Rotaion around Z axis, with positive values when y-axis moves toward the x-axis. pitch: Rotation around X axis, with positive values when z-axis moves toward the y-axis. roll: Rotation around Y axis, with positive values when x-axis moves toward the z-axis. */ /* This function is used internaly, so output is RADIAN! */ static void AKFS_Angle( const AKFVEC* avec, AKFLOAT* pitch, /* radian */ AKFLOAT* roll /* radian */ ) { AKFLOAT av; /* Size of vector */ av = AKFS_SQRT((avec->u.x)*(avec->u.x) + (avec->u.y)*(avec->u.y) + (avec->u.z)*(avec->u.z)); *pitch = AKFS_ASIN(-(avec->u.y) / av); *roll = AKFS_ASIN((avec->u.x) / av); } /* This function is used internaly, so output is RADIAN! */ static void AKFS_Azimuth( const AKFVEC* hvec, const AKFLOAT pitch, /* radian */ const AKFLOAT roll, /* radian */ AKFLOAT* azimuth /* radian */ ) { AKFLOAT sinP; /* sin value of pitch angle */ AKFLOAT cosP; /* cos value of pitch angle */ AKFLOAT sinR; /* sin value of roll angle */ AKFLOAT cosR; /* cos value of roll angle */ AKFLOAT Xh; /* X axis element of vector which is projected to horizontal plane */ AKFLOAT Yh; /* Y axis element of vector which is projected to horizontal plane */ sinP = AKFS_SIN(pitch); cosP = AKFS_COS(pitch); sinR = AKFS_SIN(roll); cosR = AKFS_COS(roll); Yh = -(hvec->u.x)*cosR + (hvec->u.z)*sinR; Xh = (hvec->u.x)*sinP*sinR + (hvec->u.y)*cosP + (hvec->u.z)*sinP*cosR; /* atan2(y, x) -> divisor and dividend is opposite from mathematical equation. */ *azimuth = AKFS_ATAN2(Yh, Xh); } int16 AKFS_Direction( const int16 nhvec, const AKFVEC hvec[], const int16 hnave, const int16 navec, const AKFVEC avec[], const int16 anave, AKFLOAT* azimuth, AKFLOAT* pitch, AKFLOAT* roll ) { AKFVEC have, aave; AKFLOAT azimuthRad; AKFLOAT pitchRad; AKFLOAT rollRad; /* arguments check */ if ((nhvec <= 0) || (navec <= 0) || (hnave <= 0) || (anave <= 0)) { return AKFS_ERROR; } if ((nhvec < hnave) || (navec < anave)) { return AKFS_ERROR; } /* average */ if (AKFS_VbAve(nhvec, hvec, hnave, &have) != AKFS_SUCCESS) { return AKFS_ERROR; } if (AKFS_VbAve(navec, avec, anave, &aave) != AKFS_SUCCESS) { return AKFS_ERROR; } /* calculate pitch and roll */ AKFS_Angle(&aave, &pitchRad, &rollRad); /* calculate azimuth */ AKFS_Azimuth(&have, pitchRad, rollRad, &azimuthRad); *azimuth = RAD2DEG(azimuthRad); *pitch = RAD2DEG(pitchRad); *roll = RAD2DEG(rollRad); /* Adjust range of azimuth */ if (*azimuth < 0) { *azimuth += 360.0f; } return AKFS_SUCCESS; }