Skip to content

Commit

Permalink
Merge pull request #10 from dotnet-campus/t/sewzc/similarity_transfor…
Browse files Browse the repository at this point in the history
…mation

修复将相似变换进行缩放和旋转时结果不正确的问题
  • Loading branch information
walterlv authored Dec 5, 2024
2 parents 3962f3b + 736cb0f commit c123d51
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,83 +69,70 @@ public void IdentityTest()
Assert.Equal(point, identity.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试缩放变换。")]
public void ScaleTest()
[Theory(DisplayName = "测试缩放变换。")]
[MemberData(nameof(TestData))]
public void ScaleTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D transformed)
{
var scaling = SimilarityTransformation2D.Identity.Scale(2);
var point = new Point2D(1, 2);
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

var transformation = similarityTransformation2D.Scale(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);
Assert.Equal(transformed * 2, transformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试 Y 轴方向翻转的缩放变换。")]
public void ScaleWithYScaleNegativeTest()
[Theory(DisplayName = "测试 Y 轴方向翻转的缩放变换。")]
[MemberData(nameof(TestData))]
public void ScaleWithYScaleNegativeTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D transformed)
{
var scaling = SimilarityTransformation2D.Identity.Scale(2, false, true);
var point = new Point2D(1, 2);
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

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);
var transformation = similarityTransformation2D.Scale(2, false, true);

Assert.Equal(new Point2D(transformed.X * 2, -transformed.Y * 2), transformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试 X 轴方向翻转的缩放变换。")]
public void ScaleWithXScaleNegativeTest()
[Theory(DisplayName = "测试 X 轴方向翻转的缩放变换。")]
[MemberData(nameof(TestData))]
public void ScaleWithXScaleNegativeTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D transformed)
{
var scaling = SimilarityTransformation2D.Identity.Scale(2, true, false);
var point = new Point2D(1, 2);
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

var transformation = similarityTransformation2D.Scale(2, true, false);

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);
Assert.Equal(new Point2D(-transformed.X * 2, transformed.Y * 2), transformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

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

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);
}
var transformation = similarityTransformation2D.Scale(2, true, true);

Assert.Equal(new Point2D(-transformed.X * 2, -transformed.Y * 2), transformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试旋转变换。")]
public void RotateTest()
[Theory(DisplayName = "测试旋转变换。")]
[MemberData(nameof(TestData))]
public void RotateTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D transformed)
{
var rotation = new SimilarityTransformation2D(1, false, AngularMeasure.FromDegree(90), Vector2D.Zero);
var point = new Point2D(1, 2);
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

var transformation = similarityTransformation2D.Rotate(AngularMeasure.Degree90);

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);
Assert.Equal(new Point2D(-transformed.Y, transformed.X), transformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试平移变换。")]
public void TranslateTest()
[Theory(DisplayName = "测试平移变换。")]
[MemberData(nameof(TestData))]
public void TranslateTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D transformed)
{
var translation = new SimilarityTransformation2D(1, false, AngularMeasure.Zero, new Vector2D(1, 2));
var point = new Point2D(1, 2);
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");

var transformation = similarityTransformation2D.Translate(new Vector2D(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);
Assert.Equal(transformed + new Vector2D(1, 2), transformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
}

[Fact(DisplayName = "测试通过 ISimilarityTransformable2D 接口进行变换。")]
Expand Down
24 changes: 20 additions & 4 deletions DotNetCampus.Numerics.Geometry/SimilarityTransformation2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public SimilarityTransformation2D Scale(double scale)
return this with
{
Scaling = Scaling * scale.CheckPositive(),
Translation = Translation * scale,
};
}

Expand All @@ -110,7 +111,14 @@ public SimilarityTransformation2D Scale(double scale, bool isXScaleNegative, boo
{
Scaling = Scaling * scale.CheckPositive(),
IsYScaleNegative = IsYScaleNegative ^ isXScaleNegative ^ isYScaleNegative,
Rotation = Rotation + (isXScaleNegative ? AngularMeasure.Pi : AngularMeasure.Zero),
Rotation = (isXScaleNegative, isYScaleNegative) switch
{
(true, true) => (AngularMeasure.Pi + Rotation).Normalized,
(true, false) => (AngularMeasure.Pi - Rotation).Normalized,
(false, true) => (AngularMeasure.Tau - Rotation).Normalized,
_ => Rotation,
},
Translation = scale * new Vector2D(isXScaleNegative ? -Translation.X : Translation.X, isYScaleNegative ? -Translation.Y : Translation.Y),
};
}

Expand All @@ -121,7 +129,15 @@ public SimilarityTransformation2D Scale(double scale, bool isXScaleNegative, boo
/// <returns>旋转后的相似变换。</returns>
public SimilarityTransformation2D Rotate(AngularMeasure rotation)
{
return this with { Rotation = Rotation + rotation };
var cos = rotation.Cos();
var sin = rotation.Sin();
return this with
{
Rotation = (Rotation + rotation).Normalized,
Translation = new Vector2D(
cos * Translation.X - sin * Translation.Y,
sin * Translation.X + cos * Translation.Y),
};
}

/// <summary>
Expand All @@ -145,7 +161,7 @@ public Point2D Transform(Point2D point)
}

/// <summary>
/// 将向量进行相似变换。与点的变换不同的是,向量的变换不会计算 <see cref="Translation"/>。
/// 将向量进行相似变换。与点的变换不同的是,向量的变换不会计算 <see cref="Translation" />。
/// </summary>
/// <param name="vector">要变换的向量。</param>
/// <returns>变换后的向量。</returns>
Expand Down Expand Up @@ -201,7 +217,7 @@ public SimilarityTransformation2D Inverse()
/// 应用另一个相似变换到当前相似变换上。
/// </summary>
/// <remarks>
/// 使用应用后的结果对目标进行变换时,相当于使用当前变换对目标进行变换,然后再使用 <paramref name="transformation"/> 对变换后的目标进行变换。
/// 使用应用后的结果对目标进行变换时,相当于使用当前变换对目标进行变换,然后再使用 <paramref name="transformation" /> 对变换后的目标进行变换。
/// </remarks>
/// <param name="transformation">要应用的相似变换。</param>
/// <returns>应用后的相似变换。</returns>
Expand Down

0 comments on commit c123d51

Please sign in to comment.