/** * @file * * @author Mamadou Babaei * * @section LICENSE * * (The MIT License) * * Copyright (c) 2020 - 2022 SenseGlove * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * @section DESCRIPTION * * */ #include "SGCoreImpl/SGQuatImpl.h" #include "Containers/StringConv.h" #include "Runtime/Launch/Resources/Version.h" #include "SGBuildHacks/SGInclude_Core_Quat.h" #include "SGBuildHacks/SGInclude_Core_Vect3D.h" #include "SGCoreImpl/SGVect3DImpl.h" struct FSGQuatImpl::FImpl { /************************ * Member variables ************************/ FQuatType Quat; /************************ * Owner object ************************/ FSGQuatImpl* Owner; /************************ * Constructor / Destructor ************************/ explicit FImpl(FSGQuatImpl* InOwner); ~FImpl(); /************************ * Default copy constructor & copy assignment operator ************************/ FImpl(const FImpl& Rhs) = default; FImpl& operator=(const FImpl& Rhs) = default; }; const FSGQuatImpl& FSGQuatImpl::Identity() { static const FSGQuatImpl I(FQuatType::Identity()); return I; } FSGQuatImpl FSGQuatImpl::FromEuler(const float XAngle, const float YAngle, const float ZAngle) { return FSGQuatImpl(FQuatType::FromEuler(XAngle, YAngle, ZAngle)); } FSGQuatImpl FSGQuatImpl::FromEuler(const FSGVect3DImpl& Euler) { return FSGQuatImpl(FQuatType::FromEuler(Euler.ToVect3D())); } FSGQuatImpl FSGQuatImpl::FromEuler(const FVector& Euler) { return FSGQuatImpl(FQuatType::FromEuler(FSGVect3DImpl(Euler).ToVect3D())); } FSGQuatImpl FSGQuatImpl::FromAngleAxis(const float Angle, const float XAxis, const float YAxis, const float ZAxis) { return FSGQuatImpl(FQuatType::FromAngleAxis(Angle, XAxis, YAxis, ZAxis)); } FSGQuatImpl FSGQuatImpl::FromAngleAxis(const float Angle, const FSGVect3DImpl& Axis) { return FSGQuatImpl(FQuatType::FromAngleAxis(Angle, Axis.ToVect3D())); } FSGQuatImpl FSGQuatImpl::FromAngleAxis(const float Angle, const FVector& Axis) { return FSGQuatImpl(FQuatType::FromAngleAxis(Angle, FSGVect3DImpl(Axis).ToVect3D())); } FSGQuatImpl FSGQuatImpl::Invert(const FSGQuatImpl& QuatImpl) { return FSGQuatImpl(FQuatType::Invert(QuatImpl.ToQuat())); } FSGQuatImpl FSGQuatImpl::Normalize(const FSGQuatImpl& QuatImpl) { return FSGQuatImpl(FQuatType::Normalize(QuatImpl.ToQuat())); } bool FSGQuatImpl::Deserialize(const FString& String, FSGQuatImpl& OutResult, const ANSICHAR Delimiter) { FQuatType Quat; const bool bReturn = FQuatType::Deserialize(TCHAR_TO_UTF8(*String), Quat, Delimiter); OutResult = FSGQuatImpl(Quat); return bReturn; } FSGQuatImpl::FSGQuatImpl() : #if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) Pimpl(TUniquePtr(new FImpl{this}, PimplDeleter)) #else Pimpl(TUniquePtr(new FImpl{this})) #endif /* ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) */ { } FSGQuatImpl::FSGQuatImpl(const float X, const float Y, const float Z, const float W) : #if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) Pimpl(TUniquePtr(new FImpl{this}, PimplDeleter)) #else Pimpl(TUniquePtr(new FImpl{this})) #endif /* ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) */ { Pimpl->Quat = FQuatType(X, Y, Z, W); } FSGQuatImpl::FSGQuatImpl(const FQuatType& Quat) : #if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) Pimpl(TUniquePtr(new FImpl{this}, PimplDeleter)) #else Pimpl(TUniquePtr(new FImpl{this})) #endif /* ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) */ { Pimpl->Quat = Quat; } FSGQuatImpl::FSGQuatImpl(const FQuat& Quat) : #if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) Pimpl(TUniquePtr(new FImpl{this}, PimplDeleter)) #else Pimpl(TUniquePtr(new FImpl{this})) #endif /* ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) */ { /// NOTE /// Unreal Engine uses a left-handed, z-up world coordinate system, which yealds clockwise rotations: /// Forward X /// Right Y /// Up Z /// SenseGlove uses a right-handed, z-up corrdinate systenm, which yealds counter-clockwise rotations: /// Forward X /// Right Y /// Up Z Pimpl->Quat = FQuatType(-Quat.X, Quat.Y, -Quat.Z, Quat.W); } FSGQuatImpl::FSGQuatImpl(const FSGQuatImpl& Rhs) : #if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) Pimpl(TUniquePtr(new FImpl{*Rhs.Pimpl}, PimplDeleter)) #else Pimpl(TUniquePtr(new FImpl{*Rhs.Pimpl})) #endif /* ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) */ { Pimpl->Owner = this; } FSGQuatImpl::FSGQuatImpl(FSGQuatImpl&& Rhs) #if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) noexcept #endif /* ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) */ = default; FSGQuatImpl::~FSGQuatImpl() = default; FSGQuatImpl& FSGQuatImpl::operator=(const FSGQuatImpl& Rhs) { *Pimpl = *Rhs.Pimpl; Pimpl->Owner = this; return *this; } FSGQuatImpl& FSGQuatImpl::operator=(FSGQuatImpl&& Rhs) #if ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) noexcept #endif /* ENGINE_MAJOR_VERSION == 5 || ( ENGINE_MAJOR_VERSION == 4 && ENGINE_MINOR_VERSION > 24 && SG_CPP17 ) */ = default; const FSGQuatImpl::FQuatType& FSGQuatImpl::ToQuat() const { return Pimpl->Quat; } FQuat FSGQuatImpl::ToFQuat() const { /// NOTE /// Unreal Engine uses a left-handed, z-up world coordinate system, which yealds clockwise rotations: /// Forward X /// Right Y /// Up Z /// SenseGlove uses a right-handed, z-up corrdinate systenm, which yealds counter-clockwise rotations: /// Forward X /// Left Y /// Up Z return FQuat(-Pimpl->Quat.GetX(), Pimpl->Quat.GetY(), -Pimpl->Quat.GetZ(), Pimpl->Quat.GetW()); } FSGQuatImpl FSGQuatImpl::operator*(const FSGQuatImpl& QuatImpl) const { return FSGQuatImpl(Pimpl->Quat.operator*(QuatImpl.ToQuat())); } FSGVect3DImpl FSGQuatImpl::operator*(const FSGVect3DImpl& Vect3DImpl) const { return FSGVect3DImpl(Pimpl->Quat.operator*(Vect3DImpl.ToVect3D())); } FVector FSGQuatImpl::operator*(const FVector& Vector) const { return FSGVect3DImpl(Pimpl->Quat.operator*(FSGVect3DImpl(Vector).ToVect3D())).ToFVector(); } float FSGQuatImpl::GetX() const { return Pimpl->Quat.GetX(); } void FSGQuatImpl::SetX(const float X) { Pimpl->Quat.SetX(X); } float FSGQuatImpl::GetY() const { return Pimpl->Quat.GetY(); } void FSGQuatImpl::SetY(const float Y) { Pimpl->Quat.SetY(Y); } float FSGQuatImpl::GetZ() const { return Pimpl->Quat.GetZ(); } void FSGQuatImpl::SetZ(const float Z) { Pimpl->Quat.SetZ(Z); } float FSGQuatImpl::GetW() const { return Pimpl->Quat.GetW(); } void FSGQuatImpl::SetW(const float W) { Pimpl->Quat.SetW(W); } FSGVect3DImpl FSGQuatImpl::ToEulerImpl() const { return FSGVect3DImpl(Pimpl->Quat.ToEuler()); } FVector FSGQuatImpl::ToEuler() const { return FSGVect3DImpl(Pimpl->Quat.ToEuler()).ToFVector(); } FSGVect3DImpl FSGQuatImpl::Rotate(const FSGVect3DImpl& Vect3DImpl) const { return FSGVect3DImpl(Pimpl->Quat.Rotate(Vect3DImpl.ToVect3D())); } FVector FSGQuatImpl::Rotate(const FVector& Vector) const { return FSGVect3DImpl(Pimpl->Quat.Rotate(FSGVect3DImpl(Vector).ToVect3D())).ToFVector(); } bool FSGQuatImpl::Equals(const FSGQuatImpl& QuatImpl) const { return Pimpl->Quat.Equals(QuatImpl.ToQuat()); } bool FSGQuatImpl::IsIdentity() const { return Pimpl->Quat.IsIdentity(); } float FSGQuatImpl::Magnitude() const { return Pimpl->Quat.Magnitude(); } FString FSGQuatImpl::ToString() const { return UTF8_TO_TCHAR(Pimpl->Quat.ToString().c_str()); } FString FSGQuatImpl::Serialize(const ANSICHAR Delimiter) const { return UTF8_TO_TCHAR(Pimpl->Quat.Serialize(Delimiter).c_str()); } FSGQuatImpl::FImpl::FImpl(FSGQuatImpl* InOwner) : Owner(InOwner) { } FSGQuatImpl::FImpl::~FImpl() = default; void FSGQuatImpl::FImplDeleter::operator()(const FImpl* P) const { delete P; }