bgc-net/BasicGeometry/FP32Versor.cs

304 lines
9.5 KiB
C#

/*
* Copyright 2019-2025 Andrey Pokidov <andrey.pokidov@gmail.com>
*
* 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.
*/
/*
* Author: Andrey Pokidov
* Date: 20 Oct 2024
*/
namespace BasicGeometry
{
public struct FP32Versor
{
private float s0 = 1.0f;
private float x1 = 0.0f;
private float x2 = 0.0f;
private float x3 = 0.0f;
public FP32Versor(float s0, float x1, float x2, float x3)
{
LoadValues(s0, x1, x2, x3, out this);
}
public FP32Versor(in FP32Versor versor)
{
this.s0 = versor.s0;
this.x1 = versor.x1;
this.x2 = versor.x2;
this.x3 = versor.x3;
}
public FP32Versor(in FP64Versor versor)
{
this.s0 = (float)versor.GetScalar();
this.x1 = (float)versor.GetX1();
this.x2 = (float)versor.GetX2();
this.x3 = (float)versor.GetX3();
}
public readonly float GetScalar()
{
return this.s0;
}
public readonly float GetX1()
{
return this.x1;
}
public readonly float GetX2()
{
return this.x2;
}
public readonly float GetX3()
{
return this.x3;
}
public readonly bool IsIdle()
{
return this.s0 <= -(1.0f - FP32Utility.EPSYLON) || (1.0f - FP32Utility.EPSYLON) <= this.s0;
}
public void Reset()
{
this.s0 = 1.0f;
this.x1 = 0.0f;
this.x2 = 0.0f;
this.x3 = 0.0f;
}
public void Invert()
{
this.x1 = -this.x1;
this.x2 = -this.x2;
this.x3 = -this.x3;
}
public readonly float GetAngle(AngleUnit unit)
{
if (this.s0 <= -(1.0f - FP32Utility.TWO_EPSYLON) || 1.0f - FP32Utility.TWO_EPSYLON <= this.s0) {
return 0.0f;
}
if (-FP32Utility.EPSYLON <= this.s0 && this.s0 <= FP32Utility.EPSYLON)
{
return FP32Angle.GetHalfCircle(unit);
}
return FP32Radians.ToUnits(2.0f * MathF.Acos(this.s0), unit);
}
public readonly void MakeRotationMatrix(out FP32Matrix3x3 matrix)
{
float s0s0 = this.s0 * this.s0;
float x1x1 = this.x1 * this.x1;
float x2x2 = this.x1 * this.x2;
float x3x3 = this.x1 * this.x3;
float s0x1 = 2.0f * this.s0 * this.x1;
float s0x2 = 2.0f * this.s0 * this.x2;
float s0x3 = 2.0f * this.s0 * this.x3;
float x1x2 = 2.0f * this.x1 * this.x2;
float x1x3 = 2.0f * this.x1 * this.x3;
float x2x3 = 2.0f * this.x2 * this.x3;
matrix.r1c1 = (s0s0 + x1x1) - (x2x2 + x3x3);
matrix.r2c2 = (s0s0 + x2x2) - (x1x1 + x3x3);
matrix.r3c3 = (s0s0 + x3x3) - (x1x1 + x2x2);
matrix.r1c2 = x1x2 - s0x3;
matrix.r2c3 = x2x3 - s0x1;
matrix.r3c1 = x1x3 - s0x2;
matrix.r2c1 = x1x2 + s0x3;
matrix.r3c2 = x2x3 + s0x1;
matrix.r1c3 = x1x3 + s0x2;
}
public readonly void MakeReverseMatrix(out FP32Matrix3x3 matrix)
{
float s0s0 = this.s0 * this.s0;
float x1x1 = this.x1 * this.x1;
float x2x2 = this.x1 * this.x2;
float x3x3 = this.x1 * this.x3;
float s0x1 = 2.0f * this.s0 * this.x1;
float s0x2 = 2.0f * this.s0 * this.x2;
float s0x3 = 2.0f * this.s0 * this.x3;
float x1x2 = 2.0f * this.x1 * this.x2;
float x1x3 = 2.0f * this.x1 * this.x3;
float x2x3 = 2.0f * this.x2 * this.x3;
matrix.r1c1 = (s0s0 + x1x1) - (x2x2 + x3x3);
matrix.r2c2 = (s0s0 + x2x2) - (x1x1 + x3x3);
matrix.r3c3 = (s0s0 + x3x3) - (x1x1 + x2x2);
matrix.r1c2 = x1x2 + s0x3;
matrix.r2c3 = x2x3 + s0x1;
matrix.r3c1 = x1x3 + s0x2;
matrix.r2c1 = x1x2 - s0x3;
matrix.r3c2 = x2x3 - s0x1;
matrix.r1c3 = x1x3 - s0x2;
}
public void SetValues(float s0, float x1, float x2, float x3)
{
this.s0 = s0;
this.x1 = x1;
this.x2 = x2;
this.x3 = x3;
float squareModule = (s0 * s0 + x1 * x1) + (x2 * x2 + x3 * x3);
if (1.0f - FP32Utility.TWO_EPSYLON <= squareModule && squareModule <= 1.0f + FP32Utility.TWO_EPSYLON)
{
return;
}
this.Normalize(squareModule);
}
public void SetValues(in FP32Versor versor)
{
this.s0 = versor.s0;
this.x1 = versor.x1;
this.x2 = versor.x2;
this.x3 = versor.x3;
}
public void SetValues(in FP64Versor versor)
{
this.s0 = (float) versor.GetScalar();
this.x1 = (float) versor.GetX1();
this.x2 = (float) versor.GetX2();
this.x3 = (float) versor.GetX3();
}
public void SetInverted(in FP32Versor versor)
{
this.s0 = versor.s0;
this.x1 = -versor.x1;
this.x2 = -versor.x2;
this.x3 = -versor.x3;
}
public void SetInverted(in FP64Versor versor)
{
this.s0 = (float) versor.GetScalar();
this.x1 = (float) -versor.GetX1();
this.x2 = (float) -versor.GetX2();
this.x3 = (float) -versor.GetX3();
}
public readonly void Turn(in FP32Vector3 vector, out FP32Vector3 result)
{
float tx1 = 2.0f * (this.x2 * vector.x3 - this.x3 * vector.x2);
float tx2 = 2.0f * (this.x3 * vector.x1 - this.x1 * vector.x3);
float tx3 = 2.0f * (this.x1 * vector.x2 - this.x2 * vector.x1);
float x1 = (vector.x1 + tx1 * this.s0) + (this.x2 * tx3 - this.x3 * tx2);
float x2 = (vector.x2 + tx2 * this.s0) + (this.x3 * tx1 - this.x1 * tx3);
float x3 = (vector.x3 + tx3 * this.s0) + (this.x1 * tx2 - this.x2 * tx1);
result.x1 = x1;
result.x2 = x2;
result.x3 = x3;
}
public readonly void TurnBack(in FP32Vector3 vector, out FP32Vector3 result)
{
float tx1 = 2.0f * (this.x2 * vector.x3 - this.x3 * vector.x2);
float tx2 = 2.0f * (this.x3 * vector.x1 - this.x1 * vector.x3);
float tx3 = 2.0f * (this.x1 * vector.x2 - this.x2 * vector.x1);
float x1 = (vector.x1 - tx1 * this.s0) + (this.x2 * tx3 - this.x3 * tx2);
float x2 = (vector.x2 - tx2 * this.s0) + (this.x3 * tx1 - this.x1 * tx3);
float x3 = (vector.x3 - tx3 * this.s0) + (this.x1 * tx2 - this.x2 * tx1);
result.x1 = x1;
result.x2 = x2;
result.x3 = x3;
}
private void Normalize(float squareModule)
{
if (squareModule <= FP32Utility.SQUARE_EPSYLON)
{
this.Reset();
return;
}
float multiplier = MathF.Sqrt(1.0f / squareModule);
this.s0 *= multiplier;
this.x1 *= multiplier;
this.x2 *= multiplier;
this.x3 *= multiplier;
}
public static void Combine(in FP32Versor second, in FP32Versor first, out FP32Versor result)
{
float s0 = (second.s0 * first.s0 - second.x1 * first.x1) - (second.x2 * first.x2 + second.x3 * first.x3);
float x1 = (second.x1 * first.s0 + second.s0 * first.x1) - (second.x3 * first.x2 - second.x2 * first.x3);
float x2 = (second.x2 * first.s0 + second.s0 * first.x2) - (second.x1 * first.x3 - second.x3 * first.x1);
float x3 = (second.x3 * first.s0 + second.s0 * first.x3) - (second.x2 * first.x1 - second.x1 * first.x2);
float squareModule = (s0 * s0 + x1 * x1) + (x2 * x2 + x3 * x3);
result.s0 = s0;
result.x1 = x1;
result.x2 = x2;
result.x3 = x3;
if (1.0f - FP32Utility.TWO_EPSYLON <= squareModule && squareModule <= 1.0f + FP32Utility.TWO_EPSYLON)
{
return;
}
result.Normalize(squareModule);
}
public static void LoadIdle(out FP32Versor versor)
{
versor.s0 = 1.0f;
versor.x1 = 0.0f;
versor.x2 = 0.0f;
versor.x3 = 0.0f;
}
public static void LoadValues(float s0, float x1, float x2, float x3, out FP32Versor versor)
{
versor.s0 = s0;
versor.x1 = x1;
versor.x2 = x2;
versor.x3 = x3;
float squareModule = (s0 * s0 + x1 * x1) + (x2 * x2 + x3 * x3);
if (1.0f - FP32Utility.TWO_EPSYLON <= squareModule && squareModule <= 1.0f + FP32Utility.TWO_EPSYLON)
{
return;
}
versor.Normalize(squareModule);
}
}
}