diff --git a/AnyCAD.Math.Test/AnyCAD.Math.Test.csproj b/AnyCAD.Math.Test/AnyCAD.Math.Test.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..2cb5b863273c32a6f244c7e04f108c6af8ddb28e
--- /dev/null
+++ b/AnyCAD.Math.Test/AnyCAD.Math.Test.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AnyCAD.Math.Test/GPntTest.cs b/AnyCAD.Math.Test/GPntTest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2207b49e2da76c586fdb7da7bb2bdf0bf72c5c93
--- /dev/null
+++ b/AnyCAD.Math.Test/GPntTest.cs
@@ -0,0 +1,446 @@
+namespace AnyCAD.Math.Test
+{
+ ///
+ /// GPnt对象(三维坐标点)相关接口的单元测试集
+ /// API参考文档:http://anycad.cn/api/2024/class_g_pnt.html
+ ///
+ [TestClass]
+ public class GPntTest
+ {
+ [TestMethod]
+ public void TestDefaultConstructor()
+ {
+ // Arrange & Act
+ var point = new GPnt();
+
+ // Assert
+ Assert.AreEqual(0, point.X());
+ Assert.AreEqual(0, point.Y());
+ Assert.AreEqual(0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestConstructorWithParameters()
+ {
+ // Arrange
+ double x = 1.0;
+ double y = 2.0;
+ double z = 3.0;
+
+ // Act
+ var point = new GPnt(x, y, z);
+
+ // Assert
+ Assert.AreEqual(x, point.X());
+ Assert.AreEqual(y, point.Y());
+ Assert.AreEqual(z, point.Z());
+ }
+
+
+ [TestMethod]
+ public void TestBaryCenter_MidPoint()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var otherPoint = new GPnt(2.0, 3.0, 4.0);
+ double alpha = 1.0;
+ double beta = 1.0;
+
+ // Act
+ point.BaryCenter(alpha, otherPoint, beta);
+
+ // Assert
+ Assert.AreEqual(1.5, point.X());
+ Assert.AreEqual(2.5, point.Y());
+ Assert.AreEqual(3.5, point.Z());
+ }
+
+ [TestMethod]
+ public void TestBaryCenter_WeightedAverage()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var otherPoint = new GPnt(2.0, 3.0, 4.0);
+ double alpha = 1.0;
+ double beta = 2.0;
+
+ // Act
+ point.BaryCenter(alpha, otherPoint, beta);
+
+ // Assert
+ Assert.AreEqual(5.0 / 3.0, point.X());
+ Assert.AreEqual(8.0 / 3.0, point.Y());
+ Assert.AreEqual(11.0 / 3.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestIsEqual_SamePoint()
+ {
+ // Arrange
+ var point1 = new GPnt(1.0, 2.0, 3.0);
+ var point2 = new GPnt(1.0, 2.0, 3.0);
+ double tolerance = 0.1;
+
+ // Act
+ bool isEqual = point1.IsEqual(point2, tolerance);
+
+ // Assert
+ Assert.IsTrue(isEqual);
+ }
+
+ [TestMethod]
+ public void TestIsEqual_DifferentPointsWithinTolerance()
+ {
+ // Arrange
+ var point1 = new GPnt(1.0, 2.0, 3.0);
+ var point2 = new GPnt(1.01, 2.01, 3.01);
+ double tolerance = 0.05;
+
+ // Act
+ bool isEqual = point1.IsEqual(point2, tolerance);
+
+ // Assert
+ Assert.IsTrue(isEqual);
+ }
+
+ [TestMethod]
+ public void TestIsEqual_DifferentPointsOutsideTolerance()
+ {
+ // Arrange
+ var point1 = new GPnt(1.0, 2.0, 3.0);
+ var point2 = new GPnt(2.0, 3.0, 4.0);
+ double tolerance = 0.1;
+
+ // Act
+ bool isEqual = point1.IsEqual(point2, tolerance);
+
+ // Assert
+ Assert.IsFalse(isEqual);
+ }
+
+ [TestMethod]
+ public void TestDistance_SamePoint()
+ {
+ // Arrange
+ var point1 = new GPnt(1.0, 2.0, 3.0);
+ var point2 = new GPnt(1.0, 2.0, 3.0);
+
+ // Act
+ double distance = point1.Distance(point2);
+
+ // Assert
+ Assert.AreEqual(0, distance);
+ }
+
+ [TestMethod]
+ public void TestDistance_DifferentPoints()
+ {
+ // Arrange
+ var point1 = new GPnt(1.0, 2.0, 3.0);
+ var point2 = new GPnt(4.0, 5.0, 6.0);
+
+ // Act
+ double distance = point1.Distance(point2);
+
+ // Assert
+ Assert.AreEqual(System.Math.Sqrt(27.0), distance);
+ }
+
+ [TestMethod]
+ public void TestDistance_NegativeCoordinates()
+ {
+ // Arrange
+ var point1 = new GPnt(-1.0, -2.0, -3.0);
+ var point2 = new GPnt(-4.0, -5.0, -6.0);
+
+ // Act
+ double distance = point1.Distance(point2);
+
+ // Assert
+ Assert.AreEqual(System.Math.Sqrt(27.0), distance);
+ }
+
+ [TestMethod]
+ public void TestSquareDistance_SamePoint()
+ {
+ // Arrange
+ var point1 = new GPnt(1.0, 2.0, 3.0);
+ var point2 = new GPnt(1.0, 2.0, 3.0);
+
+ // Act
+ double squareDistance = point1.SquareDistance(point2);
+
+ // Assert
+ Assert.AreEqual(0.0, squareDistance);
+ }
+
+ [TestMethod]
+ public void TestSquareDistance_DifferentPoints()
+ {
+ // Arrange
+ var point1 = new GPnt(1.0, 2.0, 3.0);
+ var point2 = new GPnt(4.0, 5.0, 6.0);
+
+ // Act
+ double squareDistance = point1.SquareDistance(point2);
+
+ // Assert
+ Assert.AreEqual(27.0, squareDistance);
+ }
+
+ [TestMethod]
+ public void TestMirror_Origin()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var mirrorPoint = new GPnt(0.0, 0.0, 0.0);
+
+ // Act
+ var mirroredPoint = point.Mirrored(mirrorPoint);
+ point.Mirror(mirrorPoint);
+
+ // Assert
+ Assert.AreEqual(-1.0, mirroredPoint.X());
+ Assert.AreEqual(-2.0, mirroredPoint.Y());
+ Assert.AreEqual(-3.0, mirroredPoint.Z());
+
+ Assert.AreEqual(-1.0, point.X());
+ Assert.AreEqual(-2.0, point.Y());
+ Assert.AreEqual(-3.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestMirror_NonOrigin()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var mirrorPoint = new GPnt(1.0, 1.0, 1.0);
+
+ // Act
+ var mirroredPoint = point.Mirrored(mirrorPoint);
+ point.Mirror(mirrorPoint);
+
+ // Assert
+ Assert.AreEqual(1.0, mirroredPoint.X());
+ Assert.AreEqual(0.0, mirroredPoint.Y());
+ Assert.AreEqual(-1.0, mirroredPoint.Z());
+
+ Assert.AreEqual(1.0, point.X());
+ Assert.AreEqual(0.0, point.Y());
+ Assert.AreEqual(-1.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestScale_Origin()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var scalePoint = new GPnt(0.0, 0.0, 0.0);
+ double scaleValue = 2.0;
+
+ // Act
+ var scaledPoint = point.Scaled(scalePoint, scaleValue);
+ point.Scale(scalePoint, scaleValue);
+
+ // Assert
+ Assert.AreEqual(2.0, point.X());
+ Assert.AreEqual(4.0, point.Y());
+ Assert.AreEqual(6.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestScale_NonOrigin()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var scalePoint = new GPnt(1.0, 1.0, 1.0);
+ double scaleValue = 2.0;
+
+ // Act
+ point.Scale(scalePoint, scaleValue);
+
+ // Assert
+ Assert.AreEqual(1.0, point.X());
+ Assert.AreEqual(3.0, point.Y());
+ Assert.AreEqual(5.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestTranslate()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var point1 = new GPnt(1.0, 1.0, 1.0);
+ var point2 = new GPnt(2.0, 2.0, 2.0);
+ var expectedPoint = new GPnt(point.X() + point2.X() - point1.X(), point.Y() + point2.Y() - point1.Y(), point.Z() + point2.Z() - point1.Z());
+
+ // Act
+ point.Translate(point1, point2);
+
+ // Assert
+ Assert.AreEqual(expectedPoint.X(), point.X());
+ Assert.AreEqual(expectedPoint.Y(), point.Y());
+ Assert.AreEqual(expectedPoint.Z(), point.Z());
+ }
+
+ [TestMethod]
+ public void TestTranslate_Vector()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var vector = new GVec(1.0, 1.0, 1.0);
+
+ // Act
+ point.Translate(vector);
+
+ // Assert
+ Assert.AreEqual(2.0, point.X());
+ Assert.AreEqual(3.0, point.Y());
+ Assert.AreEqual(4.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestTranslate_NegativeVector()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var vector = new GVec(-1.0, -1.0, -1.0);
+
+ // Act
+ point.Translate(vector);
+
+ // Assert
+ Assert.AreEqual(0.0, point.X());
+ Assert.AreEqual(1.0, point.Y());
+ Assert.AreEqual(2.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestRotate_ZeroAngle()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var axis = new GAx1(new GPnt(0.0, 0.0, 0.0), new GDir(0.0, 0.0, 1.0));
+ double angle = 0.0;
+
+ // Act
+ point.Rotate(axis, angle);
+
+ // Assert
+ Assert.AreEqual(1.0, point.X());
+ Assert.AreEqual(2.0, point.Y());
+ Assert.AreEqual(3.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestRotate_NonZeroAngle()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 0.0, 0.0);
+ var axis = new GAx1(new GPnt(0.0, 0.0, 0.0), new GDir(0.0, 0.0, 1.0));
+ double angle = System.Math.PI / 2; // 90 degrees
+
+ // Act
+ point.Rotate(axis, angle);
+
+ // Assert
+ Assert.AreEqual(0.0, point.X(), 1e-10);
+ Assert.AreEqual(1.0, point.Y(), 1e-10);
+ Assert.AreEqual(0.0, point.Z(), 1e-10);
+ }
+
+ [TestMethod]
+ public void TestRotate_NonAlignedAxis()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var axis = new GAx1(new GPnt(1.0, 1.0, 1.0), new GDir(1.0, 1.0, 1.0));
+ double angle = System.Math.PI / 2; // 90 degrees
+
+ // Act
+ point.Rotate(axis, angle);
+
+ // Assert
+ Assert.AreEqual(2.5773502691896262, point.X(), 1e-10);
+ Assert.AreEqual(0.84529946162074832, point.Y(), 1e-10);
+ Assert.AreEqual(2.5773502691896257, point.Z(), 1e-10);
+ }
+
+ [TestMethod]
+ public void TestTransform_Translation()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var transformation = new GTrsf();
+ transformation.SetTranslation(new GVec(1.0, 1.0, 1.0));
+
+ // Act
+ point.Transform(transformation);
+
+ // Assert
+ Assert.AreEqual(2.0, point.X());
+ Assert.AreEqual(3.0, point.Y());
+ Assert.AreEqual(4.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestTransform_Rotation()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 0.0, 0.0);
+ var transformation = new GTrsf();
+ transformation.SetRotation(new GAx1(new GPnt(0.0, 0.0, 0.0), new GDir(0.0, 0.0, 1.0)), System.Math.PI / 2);
+
+ // Act
+ point.Transform(transformation);
+
+ // Assert
+ Assert.AreEqual(0.0, point.X(), 1e-10);
+ Assert.AreEqual(1.0, point.Y(), 1e-10);
+ Assert.AreEqual(0.0, point.Z(), 1e-10);
+ }
+
+ [TestMethod]
+ public void TestTransform_Scaling()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var transformation = new GTrsf();
+ transformation.SetScale(new GPnt(0.0, 0.0, 0.0), 2.0);
+
+ // Act
+ point.Transform(transformation);
+
+ // Assert
+ Assert.AreEqual(2.0, point.X());
+ Assert.AreEqual(4.0, point.Y());
+ Assert.AreEqual(6.0, point.Z());
+ }
+
+ [TestMethod]
+ public void TestTransform_ComplexTransformation()
+ {
+ // Arrange
+ var point = new GPnt(1.0, 2.0, 3.0);
+ var expectedPoint = new GPnt(point.X(), point.Y(), point.Z());
+ var transformation = new GTrsf();
+ transformation.SetScaleFactor(2.0);
+ var quaternion = new GQuaternion(new GVec(0.0, 0.0, 1.0), System.Math.PI / 2);
+ transformation.SetRotationPart(quaternion);
+ transformation.SetTranslationPart(new GVec(1.0, 1.0, 1.0));
+
+ // Apply the transformations to the expected point
+ expectedPoint.Scale(new GPnt(0.0, 0.0, 0.0), 2.0);
+ expectedPoint.Rotate(new GAx1(new GPnt(0.0, 0.0, 0.0), new GDir(0.0, 0.0, 1.0)), System.Math.PI / 2);
+ expectedPoint.Translate(new GVec(1.0, 1.0, 1.0));
+
+ // Act
+ point.Transform(transformation);
+
+ // Assert
+ Assert.AreEqual(expectedPoint.X(), point.X(), 1e-10);
+ Assert.AreEqual(expectedPoint.Y(), point.Y(), 1e-10);
+ Assert.AreEqual(expectedPoint.Z(), point.Z(), 1e-10);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AnyCAD.Math.Test/Usings.cs b/AnyCAD.Math.Test/Usings.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9486fdc5d9cf0f386624d7f48001a511acd76074
--- /dev/null
+++ b/AnyCAD.Math.Test/Usings.cs
@@ -0,0 +1,2 @@
+global using Microsoft.VisualStudio.TestTools.UnitTesting;
+global using AnyCAD.Foundation;
\ No newline at end of file
diff --git a/AnyCAD.WPF.sln b/AnyCAD.WPF.sln
index a8e71b3326e19fba2e13e19fb2f6596569c43003..2fed8e1f7d27c08d5192c7b15745409b00381b25 100644
--- a/AnyCAD.WPF.sln
+++ b/AnyCAD.WPF.sln
@@ -15,6 +15,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demo", "Demo", "{D5525FDA-F
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ThirdParty", "ThirdParty", "{A327B286-99C8-4A86-99A6-36B8B5E049B2}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UnitTest", "UnitTest", "{4A50FDEE-FAE5-47A0-98C0-E4DFB97C32D4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnyCAD.Math.Test", "AnyCAD.Math.Test\AnyCAD.Math.Test.csproj", "{AB11DAA2-1350-4834-8087-A06919B17785}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -33,6 +37,10 @@ Global
{26A2B2C6-7F2A-4AEC-A30C-2127F744CDD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26A2B2C6-7F2A-4AEC-A30C-2127F744CDD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26A2B2C6-7F2A-4AEC-A30C-2127F744CDD8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AB11DAA2-1350-4834-8087-A06919B17785}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AB11DAA2-1350-4834-8087-A06919B17785}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AB11DAA2-1350-4834-8087-A06919B17785}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AB11DAA2-1350-4834-8087-A06919B17785}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -41,6 +49,7 @@ Global
{06D82C47-4E79-48D8-A8EE-5C9D543CC2D8} = {E7BD2F7C-A826-4279-9DBB-4B759743B462}
{D09227E0-376D-4447-BA56-1BF23C881560} = {D5525FDA-F8A6-4E28-BBFE-3EEA850F27C5}
{26A2B2C6-7F2A-4AEC-A30C-2127F744CDD8} = {D5525FDA-F8A6-4E28-BBFE-3EEA850F27C5}
+ {AB11DAA2-1350-4834-8087-A06919B17785} = {4A50FDEE-FAE5-47A0-98C0-E4DFB97C32D4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E7B41709-A273-4FB1-A228-F92061A2833D}