diff -r 2a9601315dfc -r 98ccebc37403 javauis/amms_qt/ammscontrol/audio3D/src/cammsorientationcontrolgroup.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javauis/amms_qt/ammscontrol/audio3D/src/cammsorientationcontrolgroup.cpp Fri May 14 15:47:24 2010 +0300 @@ -0,0 +1,600 @@ +/* +* Copyright (c) 2005-2007 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Group for orientation controls +* +*/ + + +// INCLUDE FILES +#include +#include +#include "cammsorientationcontrolgroup.h" +#include "cammsorientationcontrol.h" +#include "ammsutil.h" + + +// CONSTANTS +namespace +{ +// since orientation vectors consist of integers rather than real values, +// normalized vectors have to be multiplied by a large constant to keep +// adequate precision +const TInt KAMMSAxisMultiplier = 1000; + +// Some calculations are done with real values and then rounded to integers. +// Rounding may cause loss of precision. KAMMSMaxOrientationErrorPercentage +// tells how much error (in percentages) is acceptable when rounding values. +const TInt KAMMSMaxOrientationErrorPercentage = 5; +} + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::NewLC +// Two-phased constructor. +// ----------------------------------------------------------------------------- +CAMMSOrientationControlGroup* CAMMSOrientationControlGroup::NewLC() +{ + CAMMSOrientationControlGroup* self = + new(ELeave) CAMMSOrientationControlGroup; + + CleanupStack::PushL(self); + self->ConstructL(); + + return self; + +} + +// Destructor +CAMMSOrientationControlGroup::~CAMMSOrientationControlGroup() +{ +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::OrientationVectorsL +// Gets the orientation of the object using two vectors +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +void CAMMSOrientationControlGroup::OrientationVectorsL( + TInt aOrientation[ KAMMSTwoVectorComponents ]) +{ + // If the orientation was set by using "front" and "above" vectors, + // return "front" and "up" vectors. + if (iCommited.iOrientationVector) + { + // Get "up" vector. + TInt upVector[ KAMMSVectorComponents ]; + GetUpVectorL(iCommited, upVector); + + // Return the "front" and "up" vectors. + for (TInt i = 0; i < KAMMSVectorComponents; i ++) + { + aOrientation[ i ] = iCommited.iOrientation[ i ]; + aOrientation[ i + KAMMSVectorComponents ] = upVector[ i ]; + } + } + // If the orientation was set by using angles, convert set angles + // to "front" and "up" vectors. + else + { + // Start rotation from these axis vectors. + TReal xAxisVector[ KAMMSVectorComponents ] = { 1, 0, 0 }; + TReal yAxisVector[ KAMMSVectorComponents ] = { 0, 1, 0 }; + TReal zAxisVector[ KAMMSVectorComponents ] = { 0, 0, 1 }; + + // Result axis vectors after rotation. + TReal xAxisVector2[ KAMMSVectorComponents ]; + TReal yAxisVector2[ KAMMSVectorComponents ]; + TReal zAxisVector2[ KAMMSVectorComponents ]; + + // rotate round y axis + AMMSUtil::RotateVectorL(zAxisVector, yAxisVector, + iCommited.iOrientation[ EHeading ], zAxisVector2); + AMMSUtil::RotateVectorL(xAxisVector, yAxisVector, + iCommited.iOrientation[ EHeading ], xAxisVector2); + + // rotate round x axis + AMMSUtil::RotateVectorL(yAxisVector, xAxisVector2, + iCommited.iOrientation[ EPitch ], yAxisVector2); + AMMSUtil::RotateVectorL(zAxisVector2, xAxisVector2, + iCommited.iOrientation[ EPitch ], zAxisVector); + + // rotate round z axis + AMMSUtil::RotateVectorL(yAxisVector2, zAxisVector, + iCommited.iOrientation[ ERoll ], yAxisVector); + + // round and save "front" vector to the given parameter + TReal roundedValue; + for (TInt i = 0; i < KAMMSVectorComponents; i++) + { + User::LeaveIfError(Math::Round(roundedValue, zAxisVector[ i ] * // CSI: 2 Wrong index means implementation error # + KAMMSAxisMultiplier, 0)); + // "front" vector is opposite to z-axis + aOrientation[ i ] = -(TInt)roundedValue; // CSI: 2 Wrong index means implementation error # + } + + // round and save "up" vector to the given parameter + for (TInt e = 0; e < KAMMSVectorComponents; e++) + { + User::LeaveIfError(Math::Round(roundedValue, yAxisVector[ e ] * // CSI: 2 Wrong index means implementation error # + KAMMSAxisMultiplier, 0)); + aOrientation[ e + KAMMSVectorComponents ] = (TInt)roundedValue; // CSI: 2 Wrong index means implementation error # + } + } +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::SetOrientationL +// Turns the object to the new orientation +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +void CAMMSOrientationControlGroup::SetOrientationL( + TInt aHeading, + TInt aPitch, + TInt aRoll) +{ + iUncommited.iOrientation[ EHeading ] = aHeading; + iUncommited.iOrientation[ EPitch ] = aPitch; + iUncommited.iOrientation[ ERoll ] = aRoll; + iUncommited.iOrientationVector = EFalse; + + UpdateL(EOrientation); +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::SetOrientationVectorsL +// Turns the object to the new orientation +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +void CAMMSOrientationControlGroup::SetOrientationVectorsL( + TInt aFrontVector[ KAMMSVectorComponents ], + TInt aAboveVector[ KAMMSVectorComponents ]) +{ + for (TInt i = 0; i < KAMMSVectorComponents; i++) + { + iUncommited.iOrientation[ i ] = aFrontVector[ i ]; + iUncommited.iOrientation[ i + KAMMSVectorComponents ] = + aAboveVector[ i ]; + } + iUncommited.iOrientationVector = ETrue; + + UpdateL(EOrientation); +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::TypeSafeControl +// Gets control. Ownership is not tranferred. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +CAMMSOrientationControl* +CAMMSOrientationControlGroup::TypeSafeControl(TInt aIndex) const +{ + return static_cast(Control(aIndex)); +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::GetUpVectorL +// Calculates and returns "up" vector by using "front" and "above" vectors. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +void CAMMSOrientationControlGroup::GetUpVectorL( + TVariables& aVariables, + TInt aUpVector[ KAMMSVectorComponents ]) +{ + __ASSERT_DEBUG(aVariables.iOrientationVector, User::Invariant()); + + // Calculate first "right" vector and then "up" vector. + // The "right" vector is calculated as cross product of the "front" + // and "above" vectors. + // The "up" vector is calculated as cross product of the "right" + // and "front" vectors. + + TReal frontVector[ KAMMSVectorComponents ] = + { + aVariables.iOrientation[ EFrontX ], + aVariables.iOrientation[ EFrontY ], + aVariables.iOrientation[ EFrontZ ] + }; + + TReal aboveVector[ KAMMSVectorComponents ] = + { + aVariables.iOrientation[ EAboveX ], + aVariables.iOrientation[ EAboveY ], + aVariables.iOrientation[ EAboveZ ] + }; + + TReal rightVector[ KAMMSVectorComponents ]; + + TReal vectorLength = Min(AMMSUtil::VectorLengthL(frontVector), + (TReal)KMaxTInt); + + // Perform cross product with unit vectors. + AMMSUtil::ConvertToUnitVectorL(frontVector); + AMMSUtil::ConvertToUnitVectorL(aboveVector); + + TReal upVector[ KAMMSVectorComponents ]; + + AMMSUtil::CrossProduct(frontVector, aboveVector, rightVector); + AMMSUtil::CrossProduct(rightVector, frontVector, upVector); + + AMMSUtil::ConvertToUnitVectorL(upVector); + + // Multiply the unit vector so that the result "up" vector has the same + // length as the "front" vector. + + AMMSUtil::MultiplyVector(upVector, vectorLength); + + // Round the vector. + AMMSUtil::RoundVectorL(upVector, aUpVector); + + // Check the rounding error. If it is too high, multiply the original + // vector before rounding. + if (!AMMSUtil::AreVectorsSimilar(upVector, + aUpVector, + KAMMSMaxOrientationErrorPercentage)) + { + AMMSUtil::MultiplyVector(upVector, (TReal)KAMMSAxisMultiplier); + + // Accept this multiplied vector only if it can be fit into TInt. + if ((AMMSUtil::MinVectorComponent(upVector) >= KMinTInt) && + (AMMSUtil::MaxVectorComponent(upVector) <= KMaxTInt)) + { + AMMSUtil::RoundVectorL(upVector, aUpVector); + } + } +} + + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::ConvertOrientationToAnglesL +// Converts orientation from vectors to angles. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +void CAMMSOrientationControlGroup::ConvertOrientationToAnglesL( + TVariables& aVariables, + TInt aSphericalOrientation[ KAMMSVectorComponents ]) +{ + // Get vector for y-axis. + TInt temp[ KAMMSVectorComponents ]; + GetUpVectorL(aVariables, temp); + TReal yAxisVector[] = { temp[ EComponentX ], temp[ EComponentY ], + temp[ EComponentZ ] + }; + + AMMSUtil::ConvertToUnitVectorL(yAxisVector); + + + // Get vector for z-axis. + TReal frontVector[] = + { + aVariables.iOrientation[ EFrontX ], + aVariables.iOrientation[ EFrontY ], + aVariables.iOrientation[ EFrontZ ] + }; + + // Z-axis is opposite to the front vector. + AMMSUtil::ConvertToUnitVectorL(frontVector); + TReal zAxisVector[ KAMMSVectorComponents ] = + { + -frontVector[ EFrontX ], + -frontVector[ EFrontY ], + -frontVector[ EFrontZ ] + }; + + + // Calculate orientation vector for the x-axis. + // The vector is calculated as cross product of the y- + // and z-axis vectors. + TReal xAxisVector[ KAMMSVectorComponents ]; + + AMMSUtil::CrossProduct(yAxisVector, zAxisVector, xAxisVector); + AMMSUtil::ConvertToUnitVectorL(xAxisVector); + + + // First rotate the object coordinate axels so that the object y-axel is + // parallel to the global y-axis (this gives us roll and pitch angles). + // Then rotate the object coordinate axels so that x- and z-axels are + // parallel to the global x- and z-axels, respectively (this gives the + // heading). + + + // Calculate how much the axels should be rotated round the z-axis. + TReal rotateRollDeg = CalculatePartialRotationL(yAxisVector, zAxisVector, EComponentY); + + AMMSUtil::RotateVectorL(xAxisVector, zAxisVector, rotateRollDeg, xAxisVector); + AMMSUtil::RotateVectorL(yAxisVector, zAxisVector, rotateRollDeg, yAxisVector); + + + // Calculate how much the axels should be rotated round the x-axis. + TReal rotatePitchDeg = CalculatePartialRotationL(yAxisVector, xAxisVector, EComponentY); + + AMMSUtil::RotateVectorL(yAxisVector, xAxisVector, rotatePitchDeg, yAxisVector); + AMMSUtil::RotateVectorL(zAxisVector, xAxisVector, rotatePitchDeg, zAxisVector); + + // Calculate how much the axels should be rotated round the y-axis. + TReal rotateHeadingDeg = CalculatePartialRotationL(xAxisVector, yAxisVector, EComponentX); + + TReal resultAngles[] = { -rotateHeadingDeg, + -rotatePitchDeg, + -rotateRollDeg + }; + + AMMSUtil::RoundVectorL(resultAngles, aSphericalOrientation); +} + + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::CalculatePartialRotationL +// Calculates how much the given vector should be rotated around the given +// rotation vector so that the value of the specified vector component is +// maximized. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +TReal CAMMSOrientationControlGroup::CalculatePartialRotationL( + TReal aVector[ KAMMSVectorComponents ], + TReal aRotationAxelVector[ KAMMSVectorComponents ], + TInt aMaximizeComponent) +{ + __ASSERT_DEBUG((aMaximizeComponent >= EComponentX) && + (aMaximizeComponent <= EComponentZ), + User::Invariant()); + + TReal x = aRotationAxelVector[ EComponentX ]; + TReal y = aRotationAxelVector[ EComponentY ]; + TReal z = aRotationAxelVector[ EComponentZ ]; + + // calculate the length of the axis vector + TReal lengthSquare = x * x + y * y + z * z; + TReal length; + User::LeaveIfError(Math::Sqrt(length, lengthSquare)); + + // check that the vector is long enough + __ASSERT_DEBUG(length > 0, User::Invariant()); + + + // Find out the components that are tried to set 0. + TInt zeroComponents[ KAMMSVectorComponents - 1 ]; + TInt counter = 0; + + for (TInt i = 0; i < KAMMSVectorComponents; i++) + { + if (i != aMaximizeComponent) + { + zeroComponents[ counter ] = i; + counter++; + } + } + + // normalize the axis vector + x = x / length; + y = y / length; + z = z / length; + + // calculate some help variables + TReal xx = x * x; + TReal yy = y * y; + TReal zz = z * z; + + TReal x2 = aVector[ EComponentX ]; + TReal y2 = aVector[ EComponentY ]; + TReal z2 = aVector[ EComponentZ ]; + + TReal xx2 = x * x2; + TReal yy2 = y * y2; + TReal zz2 = z * z2; + + TReal xxx2 = xx * x2; + TReal yyy2 = yy * y2; + TReal zzz2 = zz * z2; + + TReal constants[] = + { + xxx2 + x *(yy2 + zz2), + yyy2 + y *(xx2 + zz2), + zzz2 + z *(xx2 + yy2) + }; + + TReal cosMultipliers[] = + { + constants[ EComponentX ] - x2, + constants[ EComponentY ] - y2, + constants[ EComponentZ ] - z2 + }; + + TReal sinMultipliers[] = + { + z * y2 - y * z2, + x * z2 - z * x2, + y * x2 - x * y2 + }; + + // The angles where some component of the vector is zero. + TReal zeroAngles[ 4 ]; // CSI: 47 Two components may have zero points in 4 angles. # + TInt angleCounter = 0; + + // Find rotation angles that makes (at least) one of the vector components + // to be 0 (however, dismiss the component to be maximized). + for (int i = 0; i < KAMMSVectorComponents - 1; i++) + { + TInt componentIndex = zeroComponents[ i ]; + + TReal cosMultiplier = cosMultipliers[ componentIndex ]; + TReal sinMultiplier = sinMultipliers[ componentIndex ]; + + TReal angleDeg = 0; + + // If both multipliers are zero, this vector is parallel or opposite + // to the target vector. Thus, no need to calculate the angle. + if ((cosMultiplier != 0) || + (sinMultiplier != 0)) + { + // Calculate the angle that makes this vector element to be 0. + TReal temp = cosMultiplier * cosMultiplier + + sinMultiplier * sinMultiplier; + + TReal divider = 0; + User::LeaveIfError(Math::Sqrt(divider, temp)); + + TReal arcTan = 0; + User::LeaveIfError( + Math::ATan(arcTan, sinMultiplier, cosMultiplier)); + + TReal arcCos = 0; + User::LeaveIfError(Math::ACos( + arcCos, constants[ i ] / divider)); // CSI: 2 Wrong index means implementation error # + + TReal angleRad = arcCos + arcTan; + + // Save the angle in degrees. + angleDeg = angleRad * 180 / KPi; // CSI: 47 Value 180 means 180 degrees # + } + + zeroAngles[ angleCounter ] = angleDeg; + + zeroAngles[ angleCounter + 1 ] = angleDeg + 180; // CSI: 47 Save also the opposite direction (+ 180 degrees) # + + angleCounter += 2; // CSI: 47 Two angles have been found # + } + + + // Find the angle that gives the maximum value for the component + // to be maximized. + TReal maxValue = -0xFFFF; + TInt maxIndex = KErrNotFound; + + for (TInt i = 0; i < angleCounter; i++) + { + // Rotate the original vector. + TReal rotatedVector[ KAMMSVectorComponents ]; + + AMMSUtil::RotateVectorL(aVector, aRotationAxelVector, + zeroAngles[ i ], rotatedVector); // CSI: 2 Wrong index means implementation error # + + // Check the value of the component that should be maximized. + TReal value = rotatedVector[ aMaximizeComponent ]; + + if (value > maxValue) + { + maxValue = value; + maxIndex = i; + } + } + + return zeroAngles[ maxIndex ]; +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::ClassName +// Returns class name that identifies this control group. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +const TDesC16& CAMMSOrientationControlGroup::ClassName() +{ + return KAMMSOrientationControlClassName; +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::CommitL +// Transfers all the pending parameters to the audio processing system. +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +void CAMMSOrientationControlGroup::CommitL(TInt aCommit) +{ + if (aCommit & EOrientation) + { + TInt controls = ControlCount(); + + if (controls > 0) + { + TInt angleVector[] = + { + iUncommited.iOrientation[ EHeading ], + iUncommited.iOrientation[ EPitch ], + iUncommited.iOrientation[ ERoll ] + }; + + // If the orientation was given in vectors, convert + // the vectors to angles because at the moment the Effect API + // can handle only angles. + if (iUncommited.iOrientationVector) + { + ConvertOrientationToAnglesL(iUncommited, angleVector); + } + + for (TInt i = 0; i < controls; i++) + { + CAMMSOrientationControl* control = TypeSafeControl(i); + + control->SetOrientationL( + angleVector[ EHeading ], + angleVector[ EPitch ], + angleVector[ ERoll ]); + } + } + + iCommited = iUncommited; + } +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::NotifyPlayerAddedL +// Called by when a new player is added +// (other items were commented in a header). +// ----------------------------------------------------------------------------- +void CAMMSOrientationControlGroup::NotifyPlayerAddedL( + CMMAPlayer* aPlayer, + CMMAControl* aControl) +{ + CAMMSAudio3DControlGroup::NotifyPlayerAddedL(aPlayer, aControl); + + CAMMSOrientationControl* control = + static_cast(aControl); + + // set the current parameters + if (iCommited.iOrientationVector) + { + TInt angleVector[ KAMMSVectorComponents ]; + + ConvertOrientationToAnglesL(iCommited, angleVector); + + control->SetOrientationL( + angleVector[ EHeading ], + angleVector[ EPitch ], + angleVector[ ERoll ]); + } + else + { + control->SetOrientationL( + iCommited.iOrientation[ EHeading ], + iCommited.iOrientation[ EPitch ], + iCommited.iOrientation[ ERoll ]); + } +} + +// ----------------------------------------------------------------------------- +// CAMMSOrientationControlGroup::CAMMSOrientationControlGroup +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +CAMMSOrientationControlGroup::CAMMSOrientationControlGroup() + : CAMMSAudio3DControlGroup(KAMMSOrientationControl) +{ + // Default orientation is: + // heading = 0 + // pitch = 0 + // roll = 0 + iCommited.iOrientationVector = EFalse; +} + +// End of File