Skip to content

Commit 3962f3b

Browse files
authored
Merge pull request #9 from dotnet-campus/t/sewzc/similarity_transformation
添加相似变换的应用变换方法
2 parents 122c1bc + 8cc9425 commit 3962f3b

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

DotNetCampus.Numerics.Geometry.Tests/SimilarityTransformation2DTest.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public class SimilarityTransformation2DTest
3030
// 组合变换
3131
{ new SimilarityTransformation2D(2, false, AngularMeasure.FromDegree(90), new Vector2D(1, 2)), new Point2D(1, 2), new Point2D(-3, 4) },
3232
{ new SimilarityTransformation2D(2, false, AngularMeasure.FromDegree(90), new Vector2D(1, 2)), new Point2D(3, 4), new Point2D(-7, 8) },
33+
{ new SimilarityTransformation2D(2, true, AngularMeasure.FromDegree(90), new Vector2D(1, 2)), new Point2D(1, 2), new Point2D(5, 4) },
34+
{ new SimilarityTransformation2D(2, true, AngularMeasure.FromDegree(90), new Vector2D(1, 2)), new Point2D(3, 4), new Point2D(9, 8) },
3335
};
3436

3537
#endregion
@@ -198,5 +200,31 @@ public void InverseTest(SimilarityTransformation2D similarityTransformation2D, P
198200
Assert.Equal(original, inverse.Transform(transformed), GeometryNumericsEqualHelper.IsAlmostEqual);
199201
}
200202

203+
[Theory(DisplayName = "测试应用另一个变换。")]
204+
[MemberData(nameof(TestData))]
205+
public void ApplyTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D expected)
206+
{
207+
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");
208+
209+
var newTransformation = SimilarityTransformation2D.Identity
210+
.Apply(new SimilarityTransformation2D(similarityTransformation2D.Scaling, false, AngularMeasure.Zero, Vector2D.Zero))
211+
.Apply(new SimilarityTransformation2D(1, similarityTransformation2D.IsYScaleNegative, AngularMeasure.Zero, Vector2D.Zero))
212+
.Apply(new SimilarityTransformation2D(1, false, similarityTransformation2D.Rotation, Vector2D.Zero))
213+
.Apply(new SimilarityTransformation2D(1, false, AngularMeasure.Zero, similarityTransformation2D.Translation));
214+
215+
Assert.Equal(expected, newTransformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
216+
}
217+
218+
[Theory(DisplayName = "测试应用变换后再应用其逆变换。")]
219+
[MemberData(nameof(TestData))]
220+
public void ApplyInverseTest(SimilarityTransformation2D similarityTransformation2D, Point2D point, Point2D expected)
221+
{
222+
Debug.Assert(similarityTransformation2D != null, nameof(similarityTransformation2D) + " != null");
223+
224+
var newTransformation = similarityTransformation2D.Apply(similarityTransformation2D).Apply(similarityTransformation2D.Inverse());
225+
226+
Assert.Equal(expected, newTransformation.Transform(point), GeometryNumericsEqualHelper.IsAlmostEqual);
227+
}
228+
201229
#endregion
202230
}

DotNetCampus.Numerics.Geometry/AffineTransformation2D.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ public AffineTransformation2D Translate(Vector2D offset)
217217
/// <summary>
218218
/// 应用另一个仿射变换到当前仿射变换。
219219
/// </summary>
220+
/// <remarks>
221+
/// 使用应用后的结果对目标进行变换时,相当于使用当前变换对目标进行变换,然后再使用 <paramref name="transformation"/> 对变换后的目标进行变换。
222+
/// </remarks>
220223
/// <param name="transformation">要应用的仿射变换。</param>
221224
/// <returns>应用后的仿射变换。</returns>
222225
public AffineTransformation2D Apply(AffineTransformation2D transformation)
@@ -323,4 +326,4 @@ public static implicit operator Matrix3X3D(AffineTransformation2D affineTransfor
323326
/// <param name="Rotation">旋转角度。</param>
324327
/// <param name="Shearing">剪切系数。</param>
325328
/// <param name="Scaling">缩放参数。</param>
326-
public record AffineTransformation2DDecomposition(Vector2D Translation, AngularMeasure Rotation, double Shearing, Scaling2D Scaling);
329+
public record AffineTransformation2DDecomposition(Vector2D Translation, AngularMeasure Rotation, double Shearing, Scaling2D Scaling);

DotNetCampus.Numerics.Geometry/SimilarityTransformation2D.cs

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public SimilarityTransformation2D Scale(double scale, bool isXScaleNegative, boo
110110
{
111111
Scaling = Scaling * scale.CheckPositive(),
112112
IsYScaleNegative = IsYScaleNegative ^ isXScaleNegative ^ isYScaleNegative,
113-
Rotation = Rotation + AngularMeasure.Pi * (isXScaleNegative ? 1 : 0),
113+
Rotation = Rotation + (isXScaleNegative ? AngularMeasure.Pi : AngularMeasure.Zero),
114114
};
115115
}
116116

@@ -137,16 +137,32 @@ public SimilarityTransformation2D Translate(Vector2D translation)
137137
/// <summary>
138138
/// 将点进行相似变换。
139139
/// </summary>
140-
/// <param name="point"></param>
141-
/// <returns></returns>
140+
/// <param name="point">要变换的点。</param>
141+
/// <returns>变换后的点。</returns>
142142
public Point2D Transform(Point2D point)
143+
{
144+
return (Point2D)(Transform(point.ToVector()) + Translation);
145+
}
146+
147+
/// <summary>
148+
/// 将向量进行相似变换。与点的变换不同的是,向量的变换不会计算 <see cref="Translation"/>。
149+
/// </summary>
150+
/// <param name="vector">要变换的向量。</param>
151+
/// <returns>变换后的向量。</returns>
152+
public Vector2D Transform(Vector2D vector)
143153
{
144154
var sin = Rotation.Sin();
145155
var cos = Rotation.Cos();
146-
return new Point2D(
147-
Scaling * (cos * point.X - sin * point.Y) + Translation.X,
148-
(IsYScaleNegative ? -1 : 1) * Scaling * (sin * point.X + cos * point.Y) + Translation.Y
149-
);
156+
157+
return IsYScaleNegative
158+
? new Vector2D(
159+
Scaling * (cos * vector.X + sin * vector.Y),
160+
Scaling * (sin * vector.X - cos * vector.Y)
161+
)
162+
: new Vector2D(
163+
Scaling * (cos * vector.X - sin * vector.Y),
164+
Scaling * (sin * vector.X + cos * vector.Y)
165+
);
150166
}
151167

152168
/// <summary>
@@ -169,16 +185,38 @@ public SimilarityTransformation2D Inverse()
169185
{
170186
var sin = Rotation.Sin();
171187
var cos = Rotation.Cos();
188+
var yScaleFactor = IsYScaleNegative ? -1 : 1;
172189
return this with
173190
{
174191
Scaling = 1 / Scaling,
175-
Rotation = (-Rotation).Normalized,
192+
Rotation = (yScaleFactor * -Rotation).Normalized,
193+
IsYScaleNegative = IsYScaleNegative,
176194
Translation = new Vector2D(
177195
-(cos * Translation.X + sin * Translation.Y) / Scaling,
178-
(IsYScaleNegative ? -1 : 1) * (sin * Translation.X - cos * Translation.Y) / Scaling),
196+
yScaleFactor * (sin * Translation.X - cos * Translation.Y) / Scaling),
179197
};
180198
}
181199

200+
/// <summary>
201+
/// 应用另一个相似变换到当前相似变换上。
202+
/// </summary>
203+
/// <remarks>
204+
/// 使用应用后的结果对目标进行变换时,相当于使用当前变换对目标进行变换,然后再使用 <paramref name="transformation"/> 对变换后的目标进行变换。
205+
/// </remarks>
206+
/// <param name="transformation">要应用的相似变换。</param>
207+
/// <returns>应用后的相似变换。</returns>
208+
public SimilarityTransformation2D Apply(SimilarityTransformation2D transformation)
209+
{
210+
ArgumentNullException.ThrowIfNull(transformation);
211+
212+
var yScaleFactor = transformation.IsYScaleNegative ? -1 : 1;
213+
return new SimilarityTransformation2D(
214+
Scaling * transformation.Scaling,
215+
IsYScaleNegative ^ transformation.IsYScaleNegative,
216+
yScaleFactor * Rotation + transformation.Rotation,
217+
transformation.Transform(Translation) + transformation.Translation);
218+
}
219+
182220
#endregion
183221
}
184222

0 commit comments

Comments
 (0)