4 Commits

Author SHA1 Message Date
Adam Hathcock ea3ccc7630 add note for readme for formatting 2025-01-23 10:41:15 +00:00
Adam Hathcock f45f34d9c4 update csharpier 2025-01-23 10:39:24 +00:00
Adam Hathcock e841fc7dc4 Update deps and run main GA on tag push too 2025-01-23 10:37:37 +00:00
Kristian Hellang eff10f3469 Add JSON converters for Vector, Quaternion and Plane types (#4)
* Add JSON converters for Vector, Quaternion and Plane types

* Add extension methods to convert between different types

* Add license headers

* ran formatter

---------

Co-authored-by: Adam Hathcock <adam@hathcock.uk>
2025-01-23 10:29:41 +00:00
21 changed files with 926 additions and 85 deletions
+3 -2
View File
@@ -3,10 +3,11 @@
"isRoot": true,
"tools": {
"csharpier": {
"version": "0.28.2",
"version": "0.30.6",
"commands": [
"dotnet-csharpier"
]
],
"rollForward": false
}
}
}
+1
View File
@@ -3,6 +3,7 @@ name: .NET Build and Publish
on:
push:
branches: ["master"]
tags:
jobs:
build:
+5 -5
View File
@@ -1,14 +1,14 @@
<Project>
<ItemGroup>
<GlobalPackageReference Include="PolySharp" Version="1.14.1" />
<GlobalPackageReference Include="MinVer" Version="5.0.0" />
<GlobalPackageReference Include="PolySharp" Version="1.15.0" />
<GlobalPackageReference Include="MinVer" Version="6.0.0" />
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageVersion Include="xunit" Version="2.8.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="Bullseye" Version="5.0.0" />
<PackageVersion Include="Glob" Version="1.1.9" />
<PackageVersion Include="SimpleExec" Version="12.0.0" />
</ItemGroup>
</Project>
</Project>
+2
View File
@@ -7,3 +7,5 @@ Forked from https://github.com/Weingartner/System.Numerics.DoubleVectors and upd
Needed because of:
- https://github.com/specklesystems/speckle-sharp/issues/2800
- https://github.com/dotnet/runtime/issues/24168
[CSharpier](https://csharpier.com/) used for formatting.
@@ -0,0 +1,222 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.Intrinsics;
using Xunit;
namespace Speckle.DoubleNumerics.Tests;
public class ConversionExtensionsTests
{
[Fact]
public void PlaneAsVector4Test()
{
var plane = new Plane(1, 2, 3, 4);
var vector4 = plane.AsVector4();
Assert.Equal(plane.Normal.X, vector4.X);
Assert.Equal(plane.Normal.Y, vector4.Y);
Assert.Equal(plane.Normal.Z, vector4.Z);
Assert.Equal(plane.D, vector4.W);
}
[Fact]
public void PlaneAsVector256Test()
{
var plane = new Plane(1, 2, 3, 4);
var vector256 = plane.AsVector256();
Assert.Equal(plane.Normal.X, vector256[0]);
Assert.Equal(plane.Normal.Y, vector256[1]);
Assert.Equal(plane.Normal.Z, vector256[2]);
Assert.Equal(plane.D, vector256[3]);
}
[Fact]
public void QuaternionAsVector4Test()
{
var quaternion = new Quaternion(1, 2, 3, 4);
var vector4 = quaternion.AsVector4();
Assert.Equal(quaternion.X, vector4.X);
Assert.Equal(quaternion.Y, vector4.Y);
Assert.Equal(quaternion.Z, vector4.Z);
Assert.Equal(quaternion.W, vector4.W);
}
[Fact]
public void QuaternionAsVector256Test()
{
var quaternion = new Quaternion(1, 2, 3, 4);
var vector256 = quaternion.AsVector256();
Assert.Equal(quaternion.X, vector256[0]);
Assert.Equal(quaternion.Y, vector256[1]);
Assert.Equal(quaternion.Z, vector256[2]);
Assert.Equal(quaternion.W, vector256[3]);
}
[Fact]
public void Vector2AsVector3Test()
{
var vector2 = new Vector2(1, 2);
var vector3 = vector2.AsVector3();
Assert.Equal(vector2.X, vector3.X);
Assert.Equal(vector2.Y, vector3.Y);
Assert.Equal(0, vector3.Z);
}
[Fact]
public void Vector2AsVector4Test()
{
var vector2 = new Vector2(1, 2);
var vector4 = vector2.AsVector4();
Assert.Equal(vector2.X, vector4.X);
Assert.Equal(vector2.Y, vector4.Y);
Assert.Equal(0, vector4.Z);
Assert.Equal(0, vector4.W);
}
[Fact]
public void Vector2AsVector256Test()
{
var vector2 = new Vector2(1, 2);
var vector256 = vector2.AsVector256();
Assert.Equal(vector2.X, vector256[0]);
Assert.Equal(vector2.Y, vector256[1]);
Assert.Equal(0, vector256[2]);
Assert.Equal(0, vector256[3]);
}
[Fact]
public void Vector3AsVector2Test()
{
var vector3 = new Vector3(1, 2, 3);
var vector2 = vector3.AsVector2();
Assert.Equal(vector3.X, vector2.X);
Assert.Equal(vector3.Y, vector2.Y);
}
[Fact]
public void Vector3AsVector4Test()
{
var vector3 = new Vector3(1, 2, 3);
var vector4 = vector3.AsVector4();
Assert.Equal(vector3.X, vector4.X);
Assert.Equal(vector3.Y, vector4.Y);
Assert.Equal(vector3.Z, vector4.Z);
Assert.Equal(0, vector4.W);
}
[Fact]
public void Vector3AsVector256Test()
{
var vector3 = new Vector3(1, 2, 3);
var vector256 = vector3.AsVector256();
Assert.Equal(vector3.X, vector256[0]);
Assert.Equal(vector3.Y, vector256[1]);
Assert.Equal(vector3.Z, vector256[2]);
Assert.Equal(0, vector256[3]);
}
[Fact]
public void Vector4AsQuaternionTest()
{
var vector4 = new Vector4(1, 2, 3, 4);
var quaternion = vector4.AsQuaternion();
Assert.Equal(vector4.X, quaternion.X);
Assert.Equal(vector4.Y, quaternion.Y);
Assert.Equal(vector4.Z, quaternion.Z);
Assert.Equal(vector4.W, quaternion.W);
}
[Fact]
public void Vector4AsPlaneTest()
{
var vector4 = new Vector4(1, 2, 3, 4);
var plane = vector4.AsPlane();
Assert.Equal(vector4.X, plane.Normal.X);
Assert.Equal(vector4.Y, plane.Normal.Y);
Assert.Equal(vector4.Z, plane.Normal.Z);
Assert.Equal(vector4.W, plane.D);
}
[Fact]
public void Vector4AsVector2Test()
{
var vector4 = new Vector4(1, 2, 3, 4);
var vector2 = vector4.AsVector2();
Assert.Equal(vector4.X, vector2.X);
Assert.Equal(vector4.Y, vector2.Y);
}
[Fact]
public void Vector4AsVector3Test()
{
var vector4 = new Vector4(1, 2, 3, 4);
var vector3 = vector4.AsVector3();
Assert.Equal(vector4.X, vector3.X);
Assert.Equal(vector4.Y, vector3.Y);
Assert.Equal(vector4.Z, vector3.Z);
}
[Fact]
public void Vector4AsVector256Test()
{
var vector4 = new Vector4(1, 2, 3, 4);
var vector256 = vector4.AsVector256();
Assert.Equal(vector4.X, vector256[0]);
Assert.Equal(vector4.Y, vector256[1]);
Assert.Equal(vector4.Z, vector256[2]);
Assert.Equal(vector4.W, vector256[3]);
}
[Fact]
public void Vector256AsPlaneTest()
{
var vector256 = Vector256.Create(1d, 2d, 3d, 4d);
var plane = vector256.AsPlane();
Assert.Equal(vector256[0], plane.Normal.X);
Assert.Equal(vector256[1], plane.Normal.Y);
Assert.Equal(vector256[2], plane.Normal.Z);
Assert.Equal(vector256[3], plane.D);
}
[Fact]
public void Vector256AsQuaternionTest()
{
var vector256 = Vector256.Create(1d, 2d, 3d, 4d);
var quaternion = vector256.AsQuaternion();
Assert.Equal(vector256[0], quaternion.X);
Assert.Equal(vector256[1], quaternion.Y);
Assert.Equal(vector256[2], quaternion.Z);
Assert.Equal(vector256[3], quaternion.W);
}
[Fact]
public void Vector256AsVector2Test()
{
var vector256 = Vector256.Create(1d, 2d, 0d, 0d);
var vector2 = vector256.AsVector2();
Assert.Equal(vector256[0], vector2.X);
Assert.Equal(vector256[1], vector2.Y);
}
[Fact]
public void Vector256AsVector3Test()
{
var vector256 = Vector256.Create(1d, 2d, 3d, 0d);
var vector3 = vector256.AsVector3();
Assert.Equal(vector256[0], vector3.X);
Assert.Equal(vector256[1], vector3.Y);
Assert.Equal(vector256[2], vector3.Z);
}
[Fact]
public void Vector256AsVector4Test()
{
var vector256 = Vector256.Create(1d, 2d, 3d, 4d);
var vector4 = vector256.AsVector4();
Assert.Equal(vector256[0], vector4.X);
Assert.Equal(vector256[1], vector4.Y);
Assert.Equal(vector256[2], vector4.Z);
Assert.Equal(vector256[3], vector4.W);
}
}
@@ -0,0 +1,33 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text.Json;
using Xunit;
namespace Speckle.DoubleNumerics.Tests;
public class ConverterTests
{
[Fact]
public void PlaneConverterTest() => AssertRoundTrip(new Plane(1, 2, 3, 4));
[Fact]
public void Vector2ConverterTest() => AssertRoundTrip(new Vector2(1, 2));
[Fact]
public void Vector3ConverterTest() => AssertRoundTrip(new Vector3(1, 2, 3));
[Fact]
public void Vector4ConverterTest() => AssertRoundTrip(new Vector4(1, 2, 3, 4));
[Fact]
public void QuaternionConverterTest() => AssertRoundTrip(new Quaternion(1, 2, 3, 4));
private static void AssertRoundTrip<T>(T value)
{
var json = JsonSerializer.Serialize(value);
var deserialized = JsonSerializer.Deserialize<T>(json);
Assert.Equal(value, deserialized);
}
}
@@ -615,7 +615,7 @@ public class Matrix4x4Tests
public void Matrix4x4CreateShadowTest02()
{
// Complex cases.
Plane[] planes = { new(0, 1, 0, 0), new(1, 2, 3, 4), new(5, 6, 7, 8), new(-1, -2, -3, -4), new(-5, -6, -7, -8), };
Plane[] planes = { new(0, 1, 0, 0), new(1, 2, 3, 4), new(5, 6, 7, 8), new(-1, -2, -3, -4), new(-5, -6, -7, -8) };
Vector3[] points =
{
@@ -715,9 +715,9 @@ public class Matrix4x4Tests
CreateReflectionTest(new Plane(Vector3.UnitX, 0), Matrix4x4.CreateScale(-1, 1, 1));
// Complex cases.
Plane[] planes = { new(0, 1, 0, 0), new(1, 2, 3, 4), new(5, 6, 7, 8), new(-1, -2, -3, -4), new(-5, -6, -7, -8), };
Plane[] planes = { new(0, 1, 0, 0), new(1, 2, 3, 4), new(5, 6, 7, 8), new(-1, -2, -3, -4), new(-5, -6, -7, -8) };
Vector3[] points = { new(1, 2, 3), new(5, 6, 7), new(-1, -2, -3), new(-5, -6, -7), };
Vector3[] points = { new(1, 2, 3), new(5, 6, 7), new(-1, -2, -3), new(-5, -6, -7) };
foreach (Plane p in planes)
{
@@ -221,6 +221,6 @@ public class Perf_Vector2
SquareRoot = 8,
Length_Squared = 9,
Normalize = 10,
Distance_Squared = 11
Distance_Squared = 11,
}
}
+3 -5
View File
@@ -133,11 +133,9 @@ public static class Util
where T : struct => (T)(~(dynamic)left);
public static double Clamp(double value, double min, double max) =>
value > max
? max
: value < min
? min
: value;
value > max ? max
: value < min ? min
: value;
public static T Zero<T>()
where T : struct => (T)(dynamic)0;
+37 -37
View File
@@ -4,12 +4,12 @@
"net8.0": {
"Microsoft.NET.Test.Sdk": {
"type": "Direct",
"requested": "[17.10.0, )",
"resolved": "17.10.0",
"contentHash": "0/2HeACkaHEYU3wc83YlcD2Fi4LMtECJjqrtvw0lPi9DCEa35zSPt1j4fuvM8NagjDqJuh1Ja35WcRtn1Um6/A==",
"requested": "[17.12.0, )",
"resolved": "17.12.0",
"contentHash": "kt/PKBZ91rFCWxVIJZSgVLk+YR+4KxTuHf799ho8WNiK5ZQpJNAEZCAWX86vcKrs+DiYjiibpYKdGZP6+/N17w==",
"dependencies": {
"Microsoft.CodeCoverage": "17.10.0",
"Microsoft.TestPlatform.TestHost": "17.10.0"
"Microsoft.CodeCoverage": "17.12.0",
"Microsoft.TestPlatform.TestHost": "17.12.0"
}
},
"Microsoft.SourceLink.GitHub": {
@@ -24,25 +24,25 @@
},
"MinVer": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw=="
"requested": "[6.0.0, )",
"resolved": "6.0.0",
"contentHash": "+/SsmiySsXJlvQLCGBqaZKNVt3s/Y/HbAdwtop7Km2CnuZbaScoqkWJEBQ5Cy9ebkn6kCYKrHsXgwrFdTgcb3g=="
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
"requested": "[1.15.0, )",
"resolved": "1.15.0",
"contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g=="
},
"xunit": {
"type": "Direct",
"requested": "[2.8.1, )",
"resolved": "2.8.1",
"contentHash": "MLBz2NQp3rtSIoJdjj3DBEr/EeOFlQYF3oCCljat3DY9GQ7yYmtjIAv8Zyfm5BcwYso5sjvIe5scuHaJPVCGIQ==",
"requested": "[2.9.3, )",
"resolved": "2.9.3",
"contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
"dependencies": {
"xunit.analyzers": "1.14.0",
"xunit.assert": "2.8.1",
"xunit.core": "[2.8.1]"
"xunit.analyzers": "1.18.0",
"xunit.assert": "2.9.3",
"xunit.core": "[2.9.3]"
}
},
"Microsoft.Build.Tasks.Git": {
@@ -52,8 +52,8 @@
},
"Microsoft.CodeCoverage": {
"type": "Transitive",
"resolved": "17.10.0",
"contentHash": "yC7oSlnR54XO5kOuHlVOKtxomNNN1BWXX8lK1G2jaPXT9sUok7kCOoA4Pgs0qyFaCtMrNsprztYMeoEGqCm4uA=="
"resolved": "17.12.0",
"contentHash": "4svMznBd5JM21JIG2xZKGNanAHNXplxf/kQDFfLHXQ3OnpJkayRK/TjacFjA+EYmoyuNXHo/sOETEfcYtAzIrA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
@@ -62,18 +62,18 @@
},
"Microsoft.TestPlatform.ObjectModel": {
"type": "Transitive",
"resolved": "17.10.0",
"contentHash": "KkwhjQevuDj0aBRoPLY6OLAhGqbPUEBuKLbaCs0kUVw29qiOYncdORd4mLVJbn9vGZ7/iFGQ/+AoJl0Tu5Umdg==",
"resolved": "17.12.0",
"contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ==",
"dependencies": {
"System.Reflection.Metadata": "1.6.0"
}
},
"Microsoft.TestPlatform.TestHost": {
"type": "Transitive",
"resolved": "17.10.0",
"contentHash": "LWpMdfqhHvcUkeMCvNYJO8QlPLlYz9XPPb+ZbaXIKhdmjAV0wqTSrTiW5FLaf7RRZT50AQADDOYMOe0HxDxNgA==",
"resolved": "17.12.0",
"contentHash": "MiPEJQNyADfwZ4pJNpQex+t9/jOClBGMiCiVVFuELCMSX2nmNfvUor3uFVxNNCg30uxDP8JDYfPnMXQzsfzYyg==",
"dependencies": {
"Microsoft.TestPlatform.ObjectModel": "17.10.0",
"Microsoft.TestPlatform.ObjectModel": "17.12.0",
"Newtonsoft.Json": "13.0.1"
}
},
@@ -94,37 +94,37 @@
},
"xunit.analyzers": {
"type": "Transitive",
"resolved": "1.14.0",
"contentHash": "KcFBmV2150xZHPUebV3YLR5gGl8R4wLuPOoxMiwCf1L4bL8ls0dcwtGFzr6NvQRgg6dWgSqbE52I6SYyeB0VnQ=="
"resolved": "1.18.0",
"contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
},
"xunit.assert": {
"type": "Transitive",
"resolved": "2.8.1",
"contentHash": "DDM18ur+PeNFhQ4w/vO+uvCUy8hA3OS5+AMf/CFov9Wco7Le49zzj0hovRWwa8f/3vaUfjL5r+IkPvqEHu2IIg=="
"resolved": "2.9.3",
"contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
},
"xunit.core": {
"type": "Transitive",
"resolved": "2.8.1",
"contentHash": "Ng4Q/DOwotESPl5CufcdqgP6O2KDpdEcIvNfA3upzfCiBrkj5WsmLhf/XUsCVolzvHA7b1WUlyeTo7j1ulG4gQ==",
"resolved": "2.9.3",
"contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
"dependencies": {
"xunit.extensibility.core": "[2.8.1]",
"xunit.extensibility.execution": "[2.8.1]"
"xunit.extensibility.core": "[2.9.3]",
"xunit.extensibility.execution": "[2.9.3]"
}
},
"xunit.extensibility.core": {
"type": "Transitive",
"resolved": "2.8.1",
"contentHash": "ilfAsxEhpne9AXXf3W+O65mRgGum94m2xHYm1yeJ1m7eiINM6OOwpaHhoNC/KWEQ2u/WF6/XiEs+Q0TOq7hiGA==",
"resolved": "2.9.3",
"contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
"dependencies": {
"xunit.abstractions": "2.0.3"
}
},
"xunit.extensibility.execution": {
"type": "Transitive",
"resolved": "2.8.1",
"contentHash": "38UnJW+64Wn8QIabujcNEw0HKvWw2AlYCgU8GNwCCDqyrSuRYb7zwetn7SHoHfbL9e9FAvEiAMXmc2wSUY8sVQ==",
"resolved": "2.9.3",
"contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
"dependencies": {
"xunit.extensibility.core": "[2.8.1]"
"xunit.extensibility.core": "[2.9.3]"
}
},
"speckle.doublenumerics": {
@@ -0,0 +1,168 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NET6_0_OR_GREATER
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
namespace Speckle.DoubleNumerics;
/// <summary>
/// Provides extension methods for converting between different numeric types.
/// </summary>
public static class ConversionExtensions
{
// TODO: When targeting .NET 8 and above, we can use the new Unsafe.BitCast method to reinterpret types.
/// <summary>
/// Reinterprets a <see cref="Plane"/> as a new <see cref="Vector4"/>.
/// </summary>
/// <param name="value">The <see cref="Plane"/> to convert.</param>
/// <returns>A <see cref="Vector4"/> representation of the <see cref="Plane"/>.</returns>
public static Vector4 AsVector4(this Plane value) => Unsafe.As<Plane, Vector4>(ref value);
/// <summary>
/// Reinterprets a <see cref="Plane"/> as a new <see cref="Vector256{Double}"/>.
/// </summary>
/// <param name="value">The <see cref="Plane"/> to convert.</param>
/// <returns>A <see cref="Vector256{Double}"/> representation of the <see cref="Plane"/>.</returns>
public static Vector256<double> AsVector256(this Plane value) => Unsafe.As<Plane, Vector256<double>>(ref value);
/// <summary>
/// Reinterprets a <see cref="Quaternion"/> as a new <see cref="Vector4"/>.
/// </summary>
/// <param name="value">The <see cref="Quaternion"/> to convert.</param>
/// <returns>A <see cref="Vector4"/> representation of the <see cref="Quaternion"/>.</returns>
public static Vector4 AsVector4(this Quaternion value) => Unsafe.As<Quaternion, Vector4>(ref value);
/// <summary>
/// Reinterprets a <see cref="Quaternion"/> as a new <see cref="Vector256{Double}"/>.
/// </summary>
/// <param name="value">The <see cref="Quaternion"/> to convert.</param>
/// <returns>A <see cref="Vector256{Double}"/> representation of the <see cref="Quaternion"/>.</returns>
public static Vector256<double> AsVector256(this Quaternion value) =>
Unsafe.As<Quaternion, Vector256<double>>(ref value);
/// <summary>
/// Reinterprets a <see cref="Vector2"/> as a new <see cref="Vector3"/> with the new element zeroed.
/// </summary>
/// <param name="value">The <see cref="Vector2"/> to convert.</param>
/// <returns><paramref name="value"/> reinterpreted as a new <see cref="Vector3"/> with the new element zeroed.</returns>
public static Vector3 AsVector3(this Vector2 value) => new(value, 0);
/// <summary>
/// Reinterprets a <see cref="Vector2"/> as a new <see cref="Vector4"/> with the new elements zeroed.
/// </summary>
/// <param name="value">The <see cref="Vector2"/> to convert.</param>
/// <returns><paramref name="value"/> reinterpreted as a new <see cref="Vector4"/> with the new elements zeroed.</returns>
public static Vector4 AsVector4(this Vector2 value) => new(value, 0, 0);
/// <summary>
/// Reinterprets a <see cref="Vector2"/> as a new <see cref="Vector256{Double}"/>.
/// </summary>
/// <param name="value">The <see cref="Vector2"/> to convert.</param>
/// <returns>A <see cref="Vector256{Double}"/> representation of the <see cref="Vector2"/>.</returns>
public static Vector256<double> AsVector256(this Vector2 value) => value.AsVector4().AsVector256();
/// <summary>
/// Reinterprets a <see cref="Vector3"/> as a new <see cref="Vector2"/>.
/// </summary>
/// <param name="value">The <see cref="Vector3"/> to convert.</param>
/// <returns><paramref name="value"/> reinterpreted as a new <see cref="Vector2"/>.</returns>
public static Vector2 AsVector2(this Vector3 value) => value.AsVector256().AsVector2();
/// <summary>
/// Reinterprets a <see cref="Vector3"/> as a new <see cref="Vector4"/> with the new element zeroed.
/// </summary>
/// <param name="value">The <see cref="Vector3"/> to convert.</param>
/// <returns><paramref name="value"/> reinterpreted as a new <see cref="Vector4"/> with the new element zeroed.</returns>
public static Vector4 AsVector4(this Vector3 value) => new(value, 0);
/// <summary>
/// Reinterprets a <see cref="Vector3"/> as a new <see cref="Vector256{Double}"/>.
/// </summary>
/// <param name="value">The <see cref="Vector3"/> to convert.</param>
/// <returns>A <see cref="Vector256{Double}"/> representation of the <see cref="Vector3"/>.</returns>
public static Vector256<double> AsVector256(this Vector3 value) => value.AsVector4().AsVector256();
/// <summary>
/// Reinterprets a <see cref="Vector4"/> as a new <see cref="Quaternion"/>.
/// </summary>
/// <param name="value">The <see cref="Vector4"/> to convert.</param>
/// <returns>A <see cref="Quaternion"/> representation of the <see cref="Vector4"/>.</returns>
public static Quaternion AsQuaternion(this Vector4 value) => Unsafe.As<Vector4, Quaternion>(ref value);
/// <summary>
/// Reinterprets a <see cref="Vector4"/> as a new <see cref="Plane"/>.
/// </summary>
/// <param name="value">The <see cref="Vector4"/> to convert.</param>
/// <returns>A <see cref="Plane"/> representation of the <see cref="Vector4"/>.</returns>
public static Plane AsPlane(this Vector4 value) => Unsafe.As<Vector4, Plane>(ref value);
/// <summary>
/// Reinterprets a <see cref="Vector4"/> as a new <see cref="Vector2"/>.
/// </summary>
/// <param name="value">The <see cref="Vector4"/> to convert.</param>
/// <returns>A <see cref="Vector2"/> representation of the <see cref="Vector4"/>.</returns>
public static Vector2 AsVector2(this Vector4 value) => value.AsVector256().AsVector2();
/// <summary>
/// Reinterprets a <see cref="Vector4"/> as a new <see cref="Vector3"/>.
/// </summary>
/// <param name="value">The <see cref="Vector4"/> to convert.</param>
/// <returns>A <see cref="Vector3"/> representation of the <see cref="Vector4"/>.</returns>
public static Vector3 AsVector3(this Vector4 value) => value.AsVector256().AsVector3();
/// <summary>
/// Reinterprets a <see cref="Vector4"/> as a new <see cref="Vector256{Double}"/>.
/// </summary>
/// <param name="value">The <see cref="Vector4"/> to convert.</param>
/// <returns>A <see cref="Vector256{Double}"/> representation of the <see cref="Vector4"/>.</returns>
public static Vector256<double> AsVector256(this Vector4 value) => Unsafe.As<Vector4, Vector256<double>>(ref value);
/// <summary>
/// Reinterprets a <see cref="Vector256{Double}"/> as a new <see cref="Plane"/>.
/// </summary>
/// <param name="value">The <see cref="Vector256{Double}"/> to convert.</param>
/// <returns>A <see cref="Plane"/> representation of the <see cref="Vector256{Double}"/>.</returns>
public static Plane AsPlane(this Vector256<double> value) => Unsafe.As<Vector256<double>, Plane>(ref value);
/// <summary>
/// Reinterprets a <see cref="Vector256{Double}"/> as a new <see cref="Quaternion"/>.
/// </summary>
/// <param name="value">The <see cref="Vector256{Double}"/> to convert.</param>
/// <returns>A <see cref="Quaternion"/> representation of the <see cref="Vector256{Double}"/>.</returns>
public static Quaternion AsQuaternion(this Vector256<double> value) =>
Unsafe.As<Vector256<double>, Quaternion>(ref value);
/// <summary>
/// Reinterprets a <see cref="Vector256{Double}"/> as a new <see cref="Vector2"/>.
/// </summary>
/// <param name="value">The <see cref="Vector256{Double}"/> to convert.</param>
/// <returns>A <see cref="Vector2"/> representation of the <see cref="Vector256{Double}"/>.</returns>
public static Vector2 AsVector2(this Vector256<double> value)
{
ref byte address = ref Unsafe.As<Vector256<double>, byte>(ref value);
return Unsafe.ReadUnaligned<Vector2>(ref address);
}
/// <summary>
/// Reinterprets a <see cref="Vector256{Double}"/> as a new <see cref="Vector3"/>.
/// </summary>
/// <param name="value">The <see cref="Vector256{Double}"/> to convert.</param>
/// <returns>A <see cref="Vector3"/> representation of the <see cref="Vector256{Double}"/>.</returns>
public static Vector3 AsVector3(this Vector256<double> value)
{
ref byte address = ref Unsafe.As<Vector256<double>, byte>(ref value);
return Unsafe.ReadUnaligned<Vector3>(ref address);
}
/// <summary>
/// Reinterprets a <see cref="Vector256{Double}"/> as a new <see cref="Vector4"/>.
/// </summary>
/// <param name="value">The <see cref="Vector256{Double}"/> to convert.</param>
/// <returns>A <see cref="Vector4"/> representation of the <see cref="Vector256{Double}"/>.</returns>
public static Vector4 AsVector4(this Vector256<double> value) => Unsafe.As<Vector256<double>, Vector4>(ref value);
}
#endif
+10 -12
View File
@@ -221,12 +221,11 @@ public struct Matrix4x4 : IEquatable<Matrix4x4>
{
const double epsilon = 1e-4;
Vector3 zaxis =
new(
objectPosition.X - cameraPosition.X,
objectPosition.Y - cameraPosition.Y,
objectPosition.Z - cameraPosition.Z
);
Vector3 zaxis = new(
objectPosition.X - cameraPosition.X,
objectPosition.Y - cameraPosition.Y,
objectPosition.Z - cameraPosition.Z
);
double norm = zaxis.LengthSquared();
@@ -287,12 +286,11 @@ public struct Matrix4x4 : IEquatable<Matrix4x4>
const double minAngle = 1.0 - (0.1 * (Math.PI / 180.0)); // 0.1 degrees
// Treat the case when object and camera positions are too close.
Vector3 faceDir =
new(
objectPosition.X - cameraPosition.X,
objectPosition.Y - cameraPosition.Y,
objectPosition.Z - cameraPosition.Z
);
Vector3 faceDir = new(
objectPosition.X - cameraPosition.X,
objectPosition.Y - cameraPosition.Y,
objectPosition.Z - cameraPosition.Z
);
double norm = faceDir.LengthSquared();
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Speckle.DoubleNumerics;
/// <summary>
/// A structure encapsulating a 3D Plane
/// </summary>
public struct Plane : IEquatable<Plane>
public partial struct Plane : IEquatable<Plane>
{
/// <summary>
/// The normal vector of the Plane.
+80
View File
@@ -0,0 +1,80 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NET6_0_OR_GREATER
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Speckle.DoubleNumerics;
[JsonConverter(typeof(PlaneJsonConverter))]
public partial struct Plane;
/// <summary>
/// Converter for <see cref="Plane"/> to and from JSON.
/// </summary>
public class PlaneJsonConverter : JsonConverter<Plane>
{
public override Plane Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
Vector3 normal = default;
double d = 0;
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return new Plane(normal, d);
}
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
var propertyName = reader.GetString();
reader.Read();
var comparison = options.PropertyNameCaseInsensitive
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
if (string.Equals(propertyName, nameof(Plane.Normal), comparison))
{
var vectorConverter = (JsonConverter<Vector3>)options.GetConverter(typeof(Vector3));
normal = vectorConverter.Read(ref reader, typeof(Vector3), options);
}
else if (string.Equals(propertyName, nameof(Plane.D), comparison))
{
d = reader.GetDouble();
}
else
{
reader.Skip();
}
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, Plane value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName(ConvertName(nameof(value.Normal), options));
var vectorConverter = (JsonConverter<Vector3>)options.GetConverter(typeof(Vector3));
vectorConverter.Write(writer, value.Normal, options);
writer.WriteNumber(ConvertName(nameof(value.D), options), value.D);
writer.WriteEndObject();
}
private static string ConvertName(string name, JsonSerializerOptions options) =>
options.PropertyNamingPolicy?.ConvertName(name) ?? name;
}
#endif
+1 -1
View File
@@ -10,7 +10,7 @@ namespace Speckle.DoubleNumerics;
/// A structure encapsulating a four-dimensional vector (x,y,z,w),
/// which is used to efficiently rotate an object about the (x,y,z) vector by the angle theta, where w = cos(theta/2).
/// </summary>
public struct Quaternion : IEquatable<Quaternion>
public partial struct Quaternion : IEquatable<Quaternion>
{
/// <summary>
/// Specifies the X-value of the vector component of the Quaternion.
@@ -0,0 +1,89 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NET6_0_OR_GREATER
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Speckle.DoubleNumerics;
[JsonConverter(typeof(QuaternionJsonConverter))]
public partial struct Quaternion;
/// <summary>
/// Converter for <see cref="Quaternion"/> to and from JSON.
/// </summary>
public class QuaternionJsonConverter : JsonConverter<Quaternion>
{
public override Quaternion Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
double x = 0;
double y = 0;
double z = 0;
double w = 0;
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return new Quaternion(x, y, z, w);
}
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
var propertyName = reader.GetString();
reader.Read();
var comparison = options.PropertyNameCaseInsensitive
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
if (string.Equals(propertyName, nameof(Quaternion.X), comparison))
{
x = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Quaternion.Y), comparison))
{
y = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Quaternion.Z), comparison))
{
z = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Quaternion.W), comparison))
{
w = reader.GetDouble();
}
else
{
reader.Skip();
}
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, Quaternion value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteNumber(ConvertName(nameof(value.X), options), value.X);
writer.WriteNumber(ConvertName(nameof(value.Y), options), value.Y);
writer.WriteNumber(ConvertName(nameof(value.Z), options), value.Z);
writer.WriteNumber(ConvertName(nameof(value.W), options), value.W);
writer.WriteEndObject();
}
private static string ConvertName(string name, JsonSerializerOptions options) =>
options.PropertyNamingPolicy?.ConvertName(name) ?? name;
}
#endif
@@ -0,0 +1,77 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NET6_0_OR_GREATER
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Speckle.DoubleNumerics;
[JsonConverter(typeof(Vector2JsonConverter))]
public partial struct Vector2;
/// <summary>
/// Converter for <see cref="Vector2"/> to and from JSON.
/// </summary>
public class Vector2JsonConverter : JsonConverter<Vector2>
{
public override Vector2 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
double x = 0;
double y = 0;
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return new Vector2(x, y);
}
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
var propertyName = reader.GetString();
reader.Read();
var comparison = options.PropertyNameCaseInsensitive
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
if (string.Equals(propertyName, nameof(Vector2.X), comparison))
{
x = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Vector2.Y), comparison))
{
y = reader.GetDouble();
}
else
{
reader.Skip();
}
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, Vector2 value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteNumber(ConvertName(nameof(value.X), options), value.X);
writer.WriteNumber(ConvertName(nameof(value.Y), options), value.Y);
writer.WriteEndObject();
}
private static string ConvertName(string name, JsonSerializerOptions options) =>
options.PropertyNamingPolicy?.ConvertName(name) ?? name;
}
#endif
@@ -0,0 +1,83 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NET6_0_OR_GREATER
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Speckle.DoubleNumerics;
[JsonConverter(typeof(Vector3JsonConverter))]
public partial struct Vector3;
/// <summary>
/// Converter for <see cref="Vector3"/> to and from JSON.
/// </summary>
public class Vector3JsonConverter : JsonConverter<Vector3>
{
public override Vector3 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
double x = 0;
double y = 0;
double z = 0;
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return new Vector3(x, y, z);
}
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
var propertyName = reader.GetString();
reader.Read();
var comparison = options.PropertyNameCaseInsensitive
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
if (string.Equals(propertyName, nameof(Vector3.X), comparison))
{
x = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Vector3.Y), comparison))
{
y = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Vector3.Z), comparison))
{
z = reader.GetDouble();
}
else
{
reader.Skip();
}
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, Vector3 value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteNumber(ConvertName(nameof(value.X), options), value.X);
writer.WriteNumber(ConvertName(nameof(value.Y), options), value.Y);
writer.WriteNumber(ConvertName(nameof(value.Z), options), value.Z);
writer.WriteEndObject();
}
private static string ConvertName(string name, JsonSerializerOptions options) =>
options.PropertyNamingPolicy?.ConvertName(name) ?? name;
}
#endif
@@ -0,0 +1,89 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if NET6_0_OR_GREATER
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Speckle.DoubleNumerics;
[JsonConverter(typeof(Vector4JsonConverter))]
public partial struct Vector4;
/// <summary>
/// Converter for <see cref="Vector4"/> to and from JSON.
/// </summary>
public class Vector4JsonConverter : JsonConverter<Vector4>
{
public override Vector4 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
double x = 0;
double y = 0;
double z = 0;
double w = 0;
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return new Vector4(x, y, z, w);
}
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
var propertyName = reader.GetString();
reader.Read();
var comparison = options.PropertyNameCaseInsensitive
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;
if (string.Equals(propertyName, nameof(Vector4.X), comparison))
{
x = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Vector4.Y), comparison))
{
y = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Vector4.Z), comparison))
{
z = reader.GetDouble();
}
else if (string.Equals(propertyName, nameof(Vector4.W), comparison))
{
w = reader.GetDouble();
}
else
{
reader.Skip();
}
}
throw new JsonException();
}
public override void Write(Utf8JsonWriter writer, Vector4 value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WriteNumber(ConvertName(nameof(value.X), options), value.X);
writer.WriteNumber(ConvertName(nameof(value.Y), options), value.Y);
writer.WriteNumber(ConvertName(nameof(value.Z), options), value.Z);
writer.WriteNumber(ConvertName(nameof(value.W), options), value.W);
writer.WriteEndObject();
}
private static string ConvertName(string name, JsonSerializerOptions options) =>
options.PropertyNamingPolicy?.ConvertName(name) ?? name;
}
#endif
+12 -12
View File
@@ -14,9 +14,9 @@
},
"MinVer": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw=="
"requested": "[6.0.0, )",
"resolved": "6.0.0",
"contentHash": "+/SsmiySsXJlvQLCGBqaZKNVt3s/Y/HbAdwtop7Km2CnuZbaScoqkWJEBQ5Cy9ebkn6kCYKrHsXgwrFdTgcb3g=="
},
"NETStandard.Library": {
"type": "Direct",
@@ -29,9 +29,9 @@
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
"requested": "[1.15.0, )",
"resolved": "1.15.0",
"contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
@@ -62,15 +62,15 @@
},
"MinVer": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw=="
"requested": "[6.0.0, )",
"resolved": "6.0.0",
"contentHash": "+/SsmiySsXJlvQLCGBqaZKNVt3s/Y/HbAdwtop7Km2CnuZbaScoqkWJEBQ5Cy9ebkn6kCYKrHsXgwrFdTgcb3g=="
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
"requested": "[1.15.0, )",
"resolved": "1.15.0",
"contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
+6 -6
View File
@@ -26,15 +26,15 @@
},
"MinVer": {
"type": "Direct",
"requested": "[5.0.0, )",
"resolved": "5.0.0",
"contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw=="
"requested": "[6.0.0, )",
"resolved": "6.0.0",
"contentHash": "+/SsmiySsXJlvQLCGBqaZKNVt3s/Y/HbAdwtop7Km2CnuZbaScoqkWJEBQ5Cy9ebkn6kCYKrHsXgwrFdTgcb3g=="
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
"requested": "[1.15.0, )",
"resolved": "1.15.0",
"contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g=="
},
"SimpleExec": {
"type": "Direct",