Skip to content

Commit

Permalink
Merge pull request #8 from dotnet-campus/t/sewzc/similarity_transform…
Browse files Browse the repository at this point in the history
…ation

添加相似变换;移除 .NET6 的支持
  • Loading branch information
SeWZC authored Nov 26, 2024
2 parents a783d40 + d4ab9fb commit 122c1bc
Show file tree
Hide file tree
Showing 14 changed files with 468 additions and 81 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/nuget_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x

- name: Install dotnet tool
run: dotnet tool update -g dotnetCampus.TagToVersion
Expand All @@ -24,4 +24,4 @@ jobs:
- name: Generate NuGet package
run: dotnet pack -c Release --no-build -o ./bin/Release/
- name: Publish to NuGet
run: dotnet nuget push ./bin/Release/*.nupkg --api-key ${{ secrets.NUGETKEY }} --source "https://api.nuget.org/v3/index.json"
run: dotnet nuget push ./bin/Release/*.nupkg --api-key ${{ secrets.NUGETKEY }} --source "https://api.nuget.org/v3/index.json"
3 changes: 2 additions & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
<!-- 生成注释xml文件 -->
<GenerateDocumentationFile>true</GenerateDocumentationFile>

<LangVersion>latest</LangVersion>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<AnalysisLevel>latest-all</AnalysisLevel>
<NoWarn>$(NoWarn);NU1507</NoWarn>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
Expand Down
202 changes: 202 additions & 0 deletions DotNetCampus.Numerics.Geometry.Tests/SimilarityTransformation2DTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
using System;
using System.Diagnostics;
using JetBrains.Annotations;
using Xunit;

namespace DotNetCampus.Numerics.Geometry.Tests;

[TestSubject(typeof(SimilarityTransformation2D))]
public class SimilarityTransformation2DTest
{
#region 静态变量

public static readonly TheoryData<SimilarityTransformation2D, Point2D, Point2D> TestData = new()
{
// 恒等变换
{ new SimilarityTransformation2D(1, false, AngularMeasure.Zero, Vector2D.Zero), new Point2D(1, 2), new Point2D(1, 2) },
{ new SimilarityTransformation2D(1, false, AngularMeasure.Zero, Vector2D.Zero), new Point2D(3, 4), new Point2D(3, 4) },
// 缩放变换
{ new SimilarityTransformation2D(2, false, AngularMeasure.Zero, Vector2D.Zero), new Point2D(1, 2), new Point2D(2, 4) },
{ new SimilarityTransformation2D(2, false, AngularMeasure.Zero, Vector2D.Zero), new Point2D(3, 4), new Point2D(6, 8) },
// 带 Y 轴方向翻转的缩放变换
{ new SimilarityTransformation2D(2, true, AngularMeasure.Zero, Vector2D.Zero), new Point2D(1, 2), new Point2D(2, -4) },
{ new SimilarityTransformation2D(2, true, AngularMeasure.Zero, Vector2D.Zero), new Point2D(3, 4), new Point2D(6, -8) },
// 旋转变换
{ new SimilarityTransformation2D(1, false, AngularMeasure.FromDegree(90), Vector2D.Zero), new Point2D(1, 2), new Point2D(-2, 1) },
{ new SimilarityTransformation2D(1, false, AngularMeasure.FromDegree(90), Vector2D.Zero), new Point2D(3, 4), new Point2D(-4, 3) },
// 平移变换
{ new SimilarityTransformation2D(1, false, AngularMeasure.Zero, new Vector2D(1, 2)), new Point2D(1, 2), new Point2D(2, 4) },
{ new SimilarityTransformation2D(1, false, AngularMeasure.Zero, new Vector2D(1, 2)), new Point2D(3, 4), new Point2D(4, 6) },
// 组合变换
{ new SimilarityTransformation2D(2, false, AngularMeasure.FromDegree(90), new Vector2D(1, 2)), new Point2D(1, 2), new Point2D(-3, 4) },
{ new SimilarityTransformation2D(2, false, AngularMeasure.FromDegree(90), new Vector2D(1, 2)), new Point2D(3, 4), new Point2D(-7, 8) },
};

#endregion

#region 成员方法

[Fact(DisplayName = "测试创建新的相似变换。")]
public void NewTest()
{
var similarityTransformation2D = new SimilarityTransformation2D(1, AngularMeasure.Zero, Vector2D.Zero);

Assert.Equal(1, similarityTransformation2D.Scaling, NumericsEqualHelper.IsAlmostEqual);
Assert.False(similarityTransformation2D.IsYScaleNegative);
Assert.Equal(AngularMeasure.Zero, similarityTransformation2D.Rotation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(Vector2D.Zero, similarityTransformation2D.Translation, NumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试创建缩放值不为正数的相似变换。")]
public void NewScalingOutOfRangeTest()
{
Assert.Throws<ArgumentOutOfRangeException>(() => new SimilarityTransformation2D(0, false, AngularMeasure.Zero, Vector2D.Zero));
Assert.Throws<ArgumentOutOfRangeException>(() => new SimilarityTransformation2D(-1, false, AngularMeasure.Zero, Vector2D.Zero));
}

[Fact(DisplayName = "测试恒等变换。")]
public void IdentityTest()
{
var identity = SimilarityTransformation2D.Identity;
var point = new Point2D(1, 2);

Assert.Equal(1, identity.Scaling, NumericsEqualHelper.IsAlmostEqual);
Assert.False(identity.IsYScaleNegative);
Assert.Equal(AngularMeasure.Zero, identity.Rotation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(Vector2D.Zero, identity.Translation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(point, identity.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试缩放变换。")]
public void ScaleTest()
{
var scaling = SimilarityTransformation2D.Identity.Scale(2);
var point = new Point2D(1, 2);

Assert.Equal(2, scaling.Scaling, NumericsEqualHelper.IsAlmostEqual);
Assert.False(scaling.IsYScaleNegative);
Assert.Equal(AngularMeasure.Zero, scaling.Rotation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(Vector2D.Zero, scaling.Translation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(new Point2D(2, 4), scaling.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试 Y 轴方向翻转的缩放变换。")]
public void ScaleWithYScaleNegativeTest()
{
var scaling = SimilarityTransformation2D.Identity.Scale(2, false, true);
var point = new Point2D(1, 2);

Assert.Equal(2, scaling.Scaling, NumericsEqualHelper.IsAlmostEqual);
Assert.True(scaling.IsYScaleNegative);
Assert.Equal(AngularMeasure.Zero, scaling.Rotation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(Vector2D.Zero, scaling.Translation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(new Point2D(2, -4), scaling.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试 X 轴方向翻转的缩放变换。")]
public void ScaleWithXScaleNegativeTest()
{
var scaling = SimilarityTransformation2D.Identity.Scale(2, true, false);
var point = new Point2D(1, 2);

Assert.Equal(2, scaling.Scaling, NumericsEqualHelper.IsAlmostEqual);
Assert.True(scaling.IsYScaleNegative);
Assert.Equal(AngularMeasure.Pi, scaling.Rotation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(Vector2D.Zero, scaling.Translation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(new Point2D(-2, 4), scaling.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试 X 轴和 Y 轴方向同时翻转的缩放变换。")]
public void ScaleWithXYScaleNegativeTest()
{
var scaling = SimilarityTransformation2D.Identity.Scale(2, true, true);
var point = new Point2D(1, 2);

Assert.Equal(2, scaling.Scaling, NumericsEqualHelper.IsAlmostEqual);
Assert.False(scaling.IsYScaleNegative);
Assert.Equal(AngularMeasure.Pi, scaling.Rotation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(Vector2D.Zero, scaling.Translation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(new Point2D(-2, -4), scaling.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}


[Fact(DisplayName = "测试旋转变换。")]
public void RotateTest()
{
var rotation = new SimilarityTransformation2D(1, false, AngularMeasure.FromDegree(90), Vector2D.Zero);
var point = new Point2D(1, 2);

Assert.Equal(1, rotation.Scaling, NumericsEqualHelper.IsAlmostEqual);
Assert.False(rotation.IsYScaleNegative);
Assert.Equal(AngularMeasure.FromDegree(90), rotation.Rotation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(Vector2D.Zero, rotation.Translation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(new Point2D(-2, 1), rotation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试平移变换。")]
public void TranslateTest()
{
var translation = new SimilarityTransformation2D(1, false, AngularMeasure.Zero, new Vector2D(1, 2));
var point = new Point2D(1, 2);

Assert.Equal(1, translation.Scaling, NumericsEqualHelper.IsAlmostEqual);
Assert.False(translation.IsYScaleNegative);
Assert.Equal(AngularMeasure.Zero, translation.Rotation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(new Vector2D(1, 2), translation.Translation, NumericsEqualHelper.IsAlmostEqual);
Assert.Equal(new Point2D(2, 4), translation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试通过 ISimilarityTransformable2D 接口进行变换。")]
public void TransformByISimilarityTransformable2DTest()
{
var point = new Point2D(1, 2);
var similarityTransformation2D = new SimilarityTransformation2D(2, false, AngularMeasure.FromDegree(90), new Vector2D(1, 2));

Assert.Equal(new Point2D(-3, 4), similarityTransformation2D.Transform<Point2D, Point2D>(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Theory(DisplayName = "测试通过缩放、旋转和平移创建的变换。")]
[MemberData(nameof(TestData))]
public void ScaleRotateTranslateTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D expected)
{
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

var newTransformation = SimilarityTransformation2D.Identity
.Scale(similarityTransformation2D.Scaling, false, similarityTransformation2D.IsYScaleNegative)
.Rotate(similarityTransformation2D.Rotation)
.Translate(similarityTransformation2D.Translation);

Assert.Equal(expected, newTransformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Theory(DisplayName = "测试变换。")]
[MemberData(nameof(TestData))]
public void TransformTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D expected)
{
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

Assert.Equal(expected, similarityTransformation2D.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Theory(DisplayName = "测试转换为仿射变换。")]
[MemberData(nameof(TestData))]
public void ToAffineTransformation2DTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D expected)
{
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

var affineTransformation2D = similarityTransformation2D.ToAffineTransformation2D();
Assert.Equal(expected, affineTransformation2D.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Theory(DisplayName = "测试逆变换。")]
[MemberData(nameof(TestData))]
public void InverseTest(SimilarityTransformation2D similarityTransformation2D, Point2D original, Point2D transformed)
{
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

var inverse = similarityTransformation2D.Inverse();
Assert.Equal(original, inverse.Transform(transformed), GeometryNumericsEqualHelper.IsAlmostEqual);
}

#endregion
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

Expand Down
17 changes: 16 additions & 1 deletion DotNetCampus.Numerics.Geometry/IAffineTransformable2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,27 @@ namespace DotNetCampus.Numerics.Geometry;
/// 可进行 2 维仿射变换的对象。
/// </summary>
/// <typeparam name="T">可变换成的对象类型。</typeparam>
public interface IAffineTransformable2D<out T>
public interface IAffineTransformable2D<out T> : ISimilarityTransformable2D<T>
{
/// <summary>
/// 进行仿射变换。
/// </summary>
/// <param name="transformation">要进行的仿射变换。</param>
/// <returns>变换后的对象。</returns>
T Transform(AffineTransformation2D transformation);

/// <summary>
/// 进行相似变换。
/// </summary>
/// <remarks>
/// 该方法会将相似变换转换为仿射变换后进行变换。如果对象支持相似变换,应当重写该方法以提供更高效的变换。
/// </remarks>
/// <param name="transformation">要进行的相似变换。</param>
/// <returns>变换后的对象。</returns>
T ISimilarityTransformable2D<T>.Transform(SimilarityTransformation2D transformation)
{
ArgumentNullException.ThrowIfNull(transformation);

return Transform(transformation.ToAffineTransformation2D());
}
}
11 changes: 6 additions & 5 deletions DotNetCampus.Numerics.Geometry/IBezierCurve.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ namespace DotNetCampus.Numerics.Geometry;
/// 贝塞尔曲线接口。
/// </summary>
public interface IBezierCurve<TPoint, TVector, TNum> : ICurve
where TPoint :unmanaged, IPoint<TPoint, TVector, TNum>
where TPoint : unmanaged, IPoint<TPoint, TVector, TNum>
where TVector : unmanaged, IVector<TVector, TNum>
where TNum : unmanaged
#if NET8_0_OR_GREATER
, IFloatingPoint<TNum>
#endif
where TNum : unmanaged, IFloatingPoint<TNum>
{
#region 成员方法

/// <summary>
/// 获取曲线上的点。
/// </summary>
Expand All @@ -39,4 +38,6 @@ public interface IBezierCurve<TPoint, TVector, TNum> : ICurve
/// <param name="t">比例参数,范围为 [0, 1]。</param>
/// <returns>曲线的曲率。如果曲线是直线,则曲率为 0。</returns>
double GetCurvature(TNum t);

#endregion
}
5 changes: 1 addition & 4 deletions DotNetCampus.Numerics.Geometry/IPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ namespace DotNetCampus.Numerics.Geometry;
public interface IPoint<TSelf, TVector, TNum>
where TSelf : unmanaged, IPoint<TSelf, TVector, TNum>
where TVector : unmanaged, IVector<TVector, TNum>
where TNum : unmanaged
#if NET8_0_OR_GREATER
, IFloatingPoint<TNum>
#endif
where TNum : unmanaged, IFloatingPoint<TNum>
{
/// <summary>
/// 获取两个点的中点。
Expand Down
15 changes: 15 additions & 0 deletions DotNetCampus.Numerics.Geometry/ISimilarityTransformable2D.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace DotNetCampus.Numerics.Geometry;

/// <summary>
/// 可进行 2 维相似变换的对象。
/// </summary>
/// <typeparam name="T">可变换成的对象类型。</typeparam>
public interface ISimilarityTransformable2D<out T>
{
/// <summary>
/// 进行相似变换。
/// </summary>
/// <param name="transformation">要进行的相似变换。</param>
/// <returns>变换后的对象。</returns>
T Transform(SimilarityTransformation2D transformation);
}
Loading

0 comments on commit 122c1bc

Please sign in to comment.