Align terminal rail normals and object space rendering
This commit is contained in:
parent
e9128282b5
commit
1cf4fe5967
@ -56,6 +56,7 @@
|
|||||||
<Compile Include="UnitTests\CoordinateSystem\HostCoordinateAdapterTests.cs" />
|
<Compile Include="UnitTests\CoordinateSystem\HostCoordinateAdapterTests.cs" />
|
||||||
<Compile Include="UnitTests\CoordinateSystem\CanonicalRailPoseBuilderTests.cs" />
|
<Compile Include="UnitTests\CoordinateSystem\CanonicalRailPoseBuilderTests.cs" />
|
||||||
<Compile Include="UnitTests\CoordinateSystem\CanonicalPlanarPoseBuilderTests.cs" />
|
<Compile Include="UnitTests\CoordinateSystem\CanonicalPlanarPoseBuilderTests.cs" />
|
||||||
|
<Compile Include="UnitTests\CoordinateSystem\ObjectSpaceOrientationHelperTests.cs" />
|
||||||
<Compile Include="UnitTests\CoordinateSystem\CanonicalRailOffsetResolverTests.cs" />
|
<Compile Include="UnitTests\CoordinateSystem\CanonicalRailOffsetResolverTests.cs" />
|
||||||
<Compile Include="UnitTests\CoordinateSystem\CanonicalTrackedPositionResolverTests.cs" />
|
<Compile Include="UnitTests\CoordinateSystem\CanonicalTrackedPositionResolverTests.cs" />
|
||||||
<Compile Include="UnitTests\CoordinateSystem\HoistingCoordinateHelperTests.cs" />
|
<Compile Include="UnitTests\CoordinateSystem\HoistingCoordinateHelperTests.cs" />
|
||||||
|
|||||||
@ -338,6 +338,7 @@
|
|||||||
<Compile Include="src\Utils\CoordinateSystem\CanonicalRailOffsetResolver.cs" />
|
<Compile Include="src\Utils\CoordinateSystem\CanonicalRailOffsetResolver.cs" />
|
||||||
<Compile Include="src\Utils\CoordinateSystem\CanonicalRailPoseBuilder.cs" />
|
<Compile Include="src\Utils\CoordinateSystem\CanonicalRailPoseBuilder.cs" />
|
||||||
<Compile Include="src\Utils\CoordinateSystem\CanonicalTrackedPositionResolver.cs" />
|
<Compile Include="src\Utils\CoordinateSystem\CanonicalTrackedPositionResolver.cs" />
|
||||||
|
<Compile Include="src\Utils\CoordinateSystem\ObjectSpaceOrientationHelper.cs" />
|
||||||
<Compile Include="src\Utils\CoordinateSystem\HostCoordinateAdapter.cs" />
|
<Compile Include="src\Utils\CoordinateSystem\HostCoordinateAdapter.cs" />
|
||||||
<Compile Include="src\Utils\CoordinateSystem\HoistingCoordinateHelper.cs" />
|
<Compile Include="src\Utils\CoordinateSystem\HoistingCoordinateHelper.cs" />
|
||||||
<Compile Include="src\Utils\CoordinateSystem\LocalAxisDirection.cs" />
|
<Compile Include="src\Utils\CoordinateSystem\LocalAxisDirection.cs" />
|
||||||
|
|||||||
@ -27,6 +27,61 @@ namespace NavisworksTransport.UnitTests.CoordinateSystem
|
|||||||
Assert.AreEqual(0f, Vector3.Dot(result.PlaneNormal, result.PlaneSpanDirection), 1e-4f);
|
Assert.AreEqual(0f, Vector3.Dot(result.PlaneNormal, result.PlaneSpanDirection), 1e-4f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void BuildFromTwoPoints_ShouldCreatePlaneParallelToOpticalAxisAndContainBothPoints()
|
||||||
|
{
|
||||||
|
Vector3 axisBase = new Vector3(0f, 0f, 0f);
|
||||||
|
Vector3 axisDirection = Vector3.UnitX;
|
||||||
|
Vector3 pickPoint1 = new Vector3(2f, 3f, 4f);
|
||||||
|
Vector3 pickPoint2 = new Vector3(6f, 3f, 6f);
|
||||||
|
|
||||||
|
AssemblyInstallationReferenceResult result =
|
||||||
|
AssemblyInstallationReferenceBuilder.Build(axisBase, axisDirection, pickPoint1, pickPoint2);
|
||||||
|
|
||||||
|
Assert.AreEqual(3f, result.OffsetDistance, 1e-4f);
|
||||||
|
Assert.AreEqual(4f, result.AnchorPoint.X, 1e-4f);
|
||||||
|
Assert.AreEqual(3f, result.AnchorPoint.Y, 1e-4f);
|
||||||
|
Assert.AreEqual(0f, result.AnchorPoint.Z, 1e-4f);
|
||||||
|
Assert.AreEqual(0f, Vector3.Dot(result.PlaneNormal, result.OpticalAxisDirection), 1e-4f);
|
||||||
|
Assert.AreEqual(0f, Vector3.Dot(result.PlaneSpanDirection, result.OpticalAxisDirection), 1e-4f);
|
||||||
|
Assert.AreEqual(0f, Vector3.Dot(result.PlaneNormal, result.PlaneSpanDirection), 1e-4f);
|
||||||
|
Assert.AreEqual(0f, Vector3.Dot(pickPoint1 - result.AnchorPoint, result.PlaneNormal), 1e-4f);
|
||||||
|
Assert.AreEqual(0f, Vector3.Dot(pickPoint2 - result.AnchorPoint, result.PlaneNormal), 1e-4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void BuildFromTwoPoints_ShouldUseOpticalAxisProjectionAsInstallationCenterLine()
|
||||||
|
{
|
||||||
|
Vector3 axisBase = new Vector3(0f, 0f, 0f);
|
||||||
|
Vector3 axisDirection = Vector3.UnitX;
|
||||||
|
Vector3 pickPoint1 = new Vector3(2f, 3f, 4f);
|
||||||
|
Vector3 pickPoint2 = new Vector3(6f, 3f, 6f);
|
||||||
|
|
||||||
|
AssemblyInstallationReferenceResult result =
|
||||||
|
AssemblyInstallationReferenceBuilder.Build(axisBase, axisDirection, pickPoint1, pickPoint2);
|
||||||
|
|
||||||
|
Assert.AreEqual(0f, result.InstallLineBasePoint.X, 1e-4f);
|
||||||
|
Assert.AreEqual(3f, result.InstallLineBasePoint.Y, 1e-4f);
|
||||||
|
Assert.AreEqual(0f, result.InstallLineBasePoint.Z, 1e-4f);
|
||||||
|
Assert.AreEqual(4f, result.AnchorPoint.X, 1e-4f);
|
||||||
|
Assert.AreEqual(3f, result.AnchorPoint.Y, 1e-4f);
|
||||||
|
Assert.AreEqual(0f, result.AnchorPoint.Z, 1e-4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void BuildFromTwoPoints_WhenPlanePointsAreNearlyAxisAligned_ShouldThrow()
|
||||||
|
{
|
||||||
|
Vector3 axisBase = new Vector3(0f, 0f, 0f);
|
||||||
|
Vector3 axisDirection = Vector3.UnitX;
|
||||||
|
Vector3 pickPoint1 = new Vector3(2f, 3f, 4f);
|
||||||
|
Vector3 pickPoint2 = new Vector3(6f, 3.00001f, 4.00001f);
|
||||||
|
|
||||||
|
InvalidOperationException ex = Assert.ThrowsException<InvalidOperationException>(
|
||||||
|
() => AssemblyInstallationReferenceBuilder.Build(axisBase, axisDirection, pickPoint1, pickPoint2));
|
||||||
|
|
||||||
|
StringAssert.Contains(ex.Message, "无法确定安装参考面");
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Build_WhenPickPointTooCloseToOpticalAxis_ShouldThrow()
|
public void Build_WhenPickPointTooCloseToOpticalAxis_ShouldThrow()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -137,6 +137,23 @@ namespace NavisworksTransport.UnitTests.CoordinateSystem
|
|||||||
AssertVector(mappedUp, 0, 0, 1);
|
AssertVector(mappedUp, 0, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PreferredNormal_ShouldOverrideCanonicalUpForRailFrame()
|
||||||
|
{
|
||||||
|
bool ok = CanonicalRailPoseBuilder.TryCreateLocalFrame(
|
||||||
|
new Vector3(0, 0, 0),
|
||||||
|
new Vector3(1, 0, 0),
|
||||||
|
new Vector3(2, 0, 0),
|
||||||
|
Vector3.UnitZ,
|
||||||
|
Vector3.UnitY,
|
||||||
|
out RailLocalFrame frame);
|
||||||
|
|
||||||
|
Assert.IsTrue(ok);
|
||||||
|
AssertVector(frame.Forward, 1, 0, 0);
|
||||||
|
AssertVector(frame.Normal, 0, 1, 0);
|
||||||
|
AssertVector(frame.Lateral, 0, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
private static void AssertColumn(Matrix4x4 matrix, int column, double x, double y, double z)
|
private static void AssertColumn(Matrix4x4 matrix, int column, double x, double y, double z)
|
||||||
{
|
{
|
||||||
switch (column)
|
switch (column)
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using NavisworksTransport.Utils.CoordinateSystem;
|
||||||
|
|
||||||
|
namespace NavisworksTransport.UnitTests.CoordinateSystem
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ObjectSpaceOrientationHelperTests
|
||||||
|
{
|
||||||
|
[TestMethod]
|
||||||
|
public void CalculateAxes_ShouldHonorProvidedUpReference()
|
||||||
|
{
|
||||||
|
var segmentDirection = new Vector3(10f, 0f, 0f);
|
||||||
|
var upReference = new Vector3(0f, 1f, 0f);
|
||||||
|
|
||||||
|
var (_, up) = ObjectSpaceOrientationHelper.CalculateAxes(segmentDirection, upReference);
|
||||||
|
|
||||||
|
Assert.AreEqual(0.0, up.X, 1e-6);
|
||||||
|
Assert.AreEqual(1.0, System.Math.Abs(up.Y), 1e-6);
|
||||||
|
Assert.AreEqual(0.0, up.Z, 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void CalculateAxes_ForVerticalSegment_ShouldUseHorizontalDirectionWithProvidedUpReference()
|
||||||
|
{
|
||||||
|
var segmentDirection = new Vector3(0f, 10f, 0f);
|
||||||
|
var upReference = new Vector3(0f, 1f, 0f);
|
||||||
|
var horizontalDirection = new Vector3(1f, 0f, 0f);
|
||||||
|
|
||||||
|
var (right, up) = ObjectSpaceOrientationHelper.CalculateAxes(segmentDirection, upReference, horizontalDirection);
|
||||||
|
|
||||||
|
Assert.AreEqual(0.0, right.X, 1e-6);
|
||||||
|
Assert.AreEqual(0.0, right.Y, 1e-6);
|
||||||
|
Assert.AreEqual(1.0, right.Z, 1e-6);
|
||||||
|
Assert.AreEqual(1.0, up.X, 1e-6);
|
||||||
|
Assert.AreEqual(0.0, up.Y, 1e-6);
|
||||||
|
Assert.AreEqual(0.0, up.Z, 1e-6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -671,6 +671,7 @@ namespace NavisworksTransport.Core.Animation
|
|||||||
LogManager.Debug($"[移动到起点] Rail路径调整: 参考点=({_pathPoints[0].X:F2},{_pathPoints[0].Y:F2},{_pathPoints[0].Z:F2}), 物体中心=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2}), 物体高度={objectHeight:F2}, 安装={_route.RailMountMode}, 对接={(PathRoute.IsTopPayloadAnchorForMountMode(_route.RailMountMode) ? "顶面对接" : "底面对接")}");
|
LogManager.Debug($"[移动到起点] Rail路径调整: 参考点=({_pathPoints[0].X:F2},{_pathPoints[0].Y:F2},{_pathPoints[0].Z:F2}), 物体中心=({startPosition.X:F2},{startPosition.Y:F2},{startPosition.Z:F2}), 物体高度={objectHeight:F2}, 安装={_route.RailMountMode}, 对接={(PathRoute.IsTopPayloadAnchorForMountMode(_route.RailMountMode) ? "顶面对接" : "底面对接")}");
|
||||||
|
|
||||||
if (RailPathPoseHelper.TryCreateRailRotation(
|
if (RailPathPoseHelper.TryCreateRailRotation(
|
||||||
|
_route,
|
||||||
previousPoint,
|
previousPoint,
|
||||||
_pathPoints[0],
|
_pathPoints[0],
|
||||||
nextPoint,
|
nextPoint,
|
||||||
@ -1034,6 +1035,7 @@ namespace NavisworksTransport.Core.Animation
|
|||||||
|
|
||||||
if (_route.PathType == PathType.Rail &&
|
if (_route.PathType == PathType.Rail &&
|
||||||
RailPathPoseHelper.TryCreateRailRotation(
|
RailPathPoseHelper.TryCreateRailRotation(
|
||||||
|
_route,
|
||||||
previousFramePoint,
|
previousFramePoint,
|
||||||
framePosition,
|
framePosition,
|
||||||
nextFramePoint,
|
nextFramePoint,
|
||||||
|
|||||||
@ -737,6 +737,12 @@ namespace NavisworksTransport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public RailPathDefinitionMode RailPathDefinitionMode { get; set; }
|
public RailPathDefinitionMode RailPathDefinitionMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rail 路径优先法向(宿主坐标)。
|
||||||
|
/// 仅在存在显式安装面/业务法向时使用;为空时退回当前默认求解。
|
||||||
|
/// </summary>
|
||||||
|
public Point3D RailPreferredNormal { get; set; }
|
||||||
|
|
||||||
// 数据库分析相关属性
|
// 数据库分析相关属性
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 碰撞数量(从数据库加载)
|
/// 碰撞数量(从数据库加载)
|
||||||
@ -777,6 +783,7 @@ namespace NavisworksTransport
|
|||||||
IsCurved = false;
|
IsCurved = false;
|
||||||
RailMountMode = RailMountMode.UnderRail;
|
RailMountMode = RailMountMode.UnderRail;
|
||||||
RailPathDefinitionMode = RailPathDefinitionMode.LegacySuspensionPoint;
|
RailPathDefinitionMode = RailPathDefinitionMode.LegacySuspensionPoint;
|
||||||
|
RailPreferredNormal = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -297,6 +297,11 @@ namespace NavisworksTransport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector3D HorizontalDirection { get; set; }
|
public Vector3D HorizontalDirection { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通行空间的优先 up 方向(例如 Rail 安装面法向)
|
||||||
|
/// </summary>
|
||||||
|
public Vector3D UpDirection { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"LineMarker[{FromIndex}->{ToIndex}, 类型={SegmentType}, 起点=({StartPoint.X:F2},{StartPoint.Y:F2},{StartPoint.Z:F2}), 终点=({EndPoint.X:F2},{EndPoint.Y:F2},{EndPoint.Z:F2})]";
|
return $"LineMarker[{FromIndex}->{ToIndex}, 类型={SegmentType}, 起点=({StartPoint.X:F2},{StartPoint.Y:F2},{StartPoint.Z:F2}), 终点=({EndPoint.X:F2},{EndPoint.Y:F2},{EndPoint.Z:F2})]";
|
||||||
@ -1658,7 +1663,8 @@ namespace NavisworksTransport
|
|||||||
var endPoint = edge.SampledPoints.Last();
|
var endPoint = edge.SampledPoints.Last();
|
||||||
|
|
||||||
// 计算长方体的轴向量(right和up向量)
|
// 计算长方体的轴向量(right和up向量)
|
||||||
var (right, up) = CalculateCuboidAxes(startPoint, endPoint);
|
var preferredUp = ResolveObjectSpaceUpDirection(visualization.PathRoute);
|
||||||
|
var (right, up) = CalculateCuboidAxes(startPoint, endPoint, preferredUp);
|
||||||
|
|
||||||
// 根据路径类型调整起点和终点位置
|
// 根据路径类型调整起点和终点位置
|
||||||
// 关键修复:垂直偏移应该沿着长方体的轴线方向(up向量)平移
|
// 关键修复:垂直偏移应该沿着长方体的轴线方向(up向量)平移
|
||||||
@ -1710,7 +1716,8 @@ namespace NavisworksTransport
|
|||||||
SampledPoints = edge.SampledPoints,
|
SampledPoints = edge.SampledPoints,
|
||||||
Height = height, // 根据模式设置高度
|
Height = height, // 根据模式设置高度
|
||||||
Width = width, // 根据模式设置宽度
|
Width = width, // 根据模式设置宽度
|
||||||
Opacity = lineOpacity // 根据模式设置透明度
|
Opacity = lineOpacity, // 根据模式设置透明度
|
||||||
|
UpDirection = preferredUp
|
||||||
};
|
};
|
||||||
visualization.PathLineMarkers.Add(lineMarker);
|
visualization.PathLineMarkers.Add(lineMarker);
|
||||||
}
|
}
|
||||||
@ -1736,7 +1743,8 @@ namespace NavisworksTransport
|
|||||||
var endPoint = edge.Trajectory.Te;
|
var endPoint = edge.Trajectory.Te;
|
||||||
|
|
||||||
// 计算长方体的轴向量(right和up向量)
|
// 计算长方体的轴向量(right和up向量)
|
||||||
var (right, up) = CalculateCuboidAxes(startPoint, endPoint);
|
var preferredUp = ResolveObjectSpaceUpDirection(visualization.PathRoute);
|
||||||
|
var (right, up) = CalculateCuboidAxes(startPoint, endPoint, preferredUp);
|
||||||
|
|
||||||
// 根据路径类型调整起点和终点位置
|
// 根据路径类型调整起点和终点位置
|
||||||
// 关键修复:垂直偏移应该沿着长方体的轴线方向(up向量)平移
|
// 关键修复:垂直偏移应该沿着长方体的轴线方向(up向量)平移
|
||||||
@ -1818,7 +1826,8 @@ namespace NavisworksTransport
|
|||||||
SampledPoints = adjustedSampledPoints,
|
SampledPoints = adjustedSampledPoints,
|
||||||
Height = height, // 根据模式设置高度
|
Height = height, // 根据模式设置高度
|
||||||
Width = width, // 根据模式设置宽度
|
Width = width, // 根据模式设置宽度
|
||||||
Opacity = arcLineOpacity // 根据模式设置透明度
|
Opacity = arcLineOpacity, // 根据模式设置透明度
|
||||||
|
UpDirection = preferredUp
|
||||||
};
|
};
|
||||||
visualization.PathLineMarkers.Add(arcMarker);
|
visualization.PathLineMarkers.Add(arcMarker);
|
||||||
|
|
||||||
@ -1838,73 +1847,13 @@ namespace NavisworksTransport
|
|||||||
/// <param name="endPoint">路径段终点</param>
|
/// <param name="endPoint">路径段终点</param>
|
||||||
/// <param name="horizontalDirection">水平段方向向量(用于垂直路径渲染时确定通行空间方向)</param>
|
/// <param name="horizontalDirection">水平段方向向量(用于垂直路径渲染时确定通行空间方向)</param>
|
||||||
/// <returns>元组(right向量,up向量)</returns>
|
/// <returns>元组(right向量,up向量)</returns>
|
||||||
private (Vector3D right, Vector3D up) CalculateCuboidAxes(Point3D startPoint, Point3D endPoint, Vector3D horizontalDirection = null)
|
private (Vector3D right, Vector3D up) CalculateCuboidAxes(Point3D startPoint, Point3D endPoint, Vector3D upReference = null, Vector3D horizontalDirection = null)
|
||||||
{
|
{
|
||||||
// 计算路径段的方向向量
|
return ObjectSpaceOrientationHelper.CalculateAxes(
|
||||||
var segmentDirection = new Vector3D(
|
startPoint,
|
||||||
endPoint.X - startPoint.X,
|
endPoint,
|
||||||
endPoint.Y - startPoint.Y,
|
upReference ?? GetHostUpVector(),
|
||||||
endPoint.Z - startPoint.Z
|
horizontalDirection);
|
||||||
);
|
|
||||||
var segmentLength = Math.Sqrt(
|
|
||||||
segmentDirection.X * segmentDirection.X +
|
|
||||||
segmentDirection.Y * segmentDirection.Y +
|
|
||||||
segmentDirection.Z * segmentDirection.Z
|
|
||||||
);
|
|
||||||
|
|
||||||
// 归一化方向向量
|
|
||||||
var normalizedDirection = new Vector3D(
|
|
||||||
segmentDirection.X / segmentLength,
|
|
||||||
segmentDirection.Y / segmentLength,
|
|
||||||
segmentDirection.Z / segmentLength
|
|
||||||
);
|
|
||||||
|
|
||||||
// 使用宿主 up 方向构造水平 right 向量,避免把世界 Z 写死到 Y-up 项目里。
|
|
||||||
var hostUp = GetHostUpVector();
|
|
||||||
var right = Cross(normalizedDirection, hostUp);
|
|
||||||
|
|
||||||
// 如果方向向量接近宿主 up(垂直段),则使用水平段方向重新构造 right。
|
|
||||||
double parallelToUp = Math.Abs(
|
|
||||||
normalizedDirection.X * hostUp.X +
|
|
||||||
normalizedDirection.Y * hostUp.Y +
|
|
||||||
normalizedDirection.Z * hostUp.Z);
|
|
||||||
if (parallelToUp > 0.9)
|
|
||||||
{
|
|
||||||
if (horizontalDirection != null)
|
|
||||||
{
|
|
||||||
right = Cross(horizontalDirection, hostUp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
right = Math.Abs(hostUp.X) < 0.9
|
|
||||||
? Normalize(Cross(hostUp, new Vector3D(1, 0, 0)))
|
|
||||||
: Normalize(Cross(hostUp, new Vector3D(0, 1, 0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 归一化right向量
|
|
||||||
var rightLength = Math.Sqrt(right.X * right.X + right.Y * right.Y + right.Z * right.Z);
|
|
||||||
if (rightLength > 0.001)
|
|
||||||
{
|
|
||||||
right = new Vector3D(right.X / rightLength, right.Y / rightLength, right.Z / rightLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算高度向量(垂直于方向向量和宽度向量)- 这是长方体的轴线方向
|
|
||||||
// up = direction × right
|
|
||||||
var up = new Vector3D(
|
|
||||||
normalizedDirection.Y * right.Z - normalizedDirection.Z * right.Y,
|
|
||||||
normalizedDirection.Z * right.X - normalizedDirection.X * right.Z,
|
|
||||||
normalizedDirection.X * right.Y - normalizedDirection.Y * right.X
|
|
||||||
);
|
|
||||||
|
|
||||||
// 归一化up向量
|
|
||||||
var upLength = Math.Sqrt(up.X * up.X + up.Y * up.Y + up.Z * up.Z);
|
|
||||||
if (upLength > 0.001)
|
|
||||||
{
|
|
||||||
up = new Vector3D(up.X / upLength, up.Y / upLength, up.Z / upLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (right, up);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -2009,7 +1958,8 @@ namespace NavisworksTransport
|
|||||||
CalculatePassageSpaceParameters(visualization, isVerticalSegment, isTurn90Horizontal, isFirstOrLastSegment);
|
CalculatePassageSpaceParameters(visualization, isVerticalSegment, isTurn90Horizontal, isFirstOrLastSegment);
|
||||||
|
|
||||||
// 计算长方体的轴向量(right和up向量)
|
// 计算长方体的轴向量(right和up向量)
|
||||||
var (right, up) = CalculateCuboidAxes(startPoint.Position, endPoint.Position, horizontalDirection);
|
var preferredUp = ResolveObjectSpaceUpDirection(visualization.PathRoute);
|
||||||
|
var (right, up) = CalculateCuboidAxes(startPoint.Position, endPoint.Position, preferredUp, horizontalDirection);
|
||||||
|
|
||||||
// 根据路径类型调整起点和终点位置
|
// 根据路径类型调整起点和终点位置
|
||||||
// 关键修复:垂直偏移应该沿着长方体的轴线方向(up向量)平移,而不是简单地添加到Z坐标上
|
// 关键修复:垂直偏移应该沿着长方体的轴线方向(up向量)平移,而不是简单地添加到Z坐标上
|
||||||
@ -2099,7 +2049,8 @@ namespace NavisworksTransport
|
|||||||
Height = height,
|
Height = height,
|
||||||
Width = width,
|
Width = width,
|
||||||
Opacity = lineOpacity,
|
Opacity = lineOpacity,
|
||||||
HorizontalDirection = horizontalDirection // 设置水平段方向向量
|
HorizontalDirection = horizontalDirection, // 设置水平段方向向量
|
||||||
|
UpDirection = preferredUp
|
||||||
};
|
};
|
||||||
visualization.PathLineMarkers.Add(lineMarker);
|
visualization.PathLineMarkers.Add(lineMarker);
|
||||||
}
|
}
|
||||||
@ -2797,7 +2748,7 @@ namespace NavisworksTransport
|
|||||||
/// <param name="width">宽度</param>
|
/// <param name="width">宽度</param>
|
||||||
/// <param name="height">高度</param>
|
/// <param name="height">高度</param>
|
||||||
/// <param name="horizontalDirection">水平段方向向量(用于垂直路径渲染时确定通行空间方向)</param>
|
/// <param name="horizontalDirection">水平段方向向量(用于垂直路径渲染时确定通行空间方向)</param>
|
||||||
private void RenderCuboidMarker(Graphics graphics, Point3D startPoint, Point3D endPoint, double width, double height, Vector3D horizontalDirection = null)
|
private void RenderCuboidMarker(Graphics graphics, Point3D startPoint, Point3D endPoint, double width, double height, Vector3D horizontalDirection = null, Vector3D upReference = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -2817,47 +2768,11 @@ namespace NavisworksTransport
|
|||||||
// 归一化方向向量
|
// 归一化方向向量
|
||||||
direction = new Vector3D(direction.X / length, direction.Y / length, direction.Z / length);
|
direction = new Vector3D(direction.X / length, direction.Y / length, direction.Z / length);
|
||||||
|
|
||||||
var hostUp = GetHostUpVector();
|
var (right, up) = ObjectSpaceOrientationHelper.CalculateAxes(
|
||||||
var right = Cross(direction, hostUp);
|
startPoint,
|
||||||
|
endPoint,
|
||||||
double parallelToUp = Math.Abs(
|
upReference ?? GetHostUpVector(),
|
||||||
direction.X * hostUp.X +
|
horizontalDirection);
|
||||||
direction.Y * hostUp.Y +
|
|
||||||
direction.Z * hostUp.Z);
|
|
||||||
if (parallelToUp > 0.9)
|
|
||||||
{
|
|
||||||
if (horizontalDirection != null)
|
|
||||||
{
|
|
||||||
right = Cross(horizontalDirection, hostUp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
right = Math.Abs(hostUp.X) < 0.9
|
|
||||||
? Normalize(Cross(hostUp, new Vector3D(1, 0, 0)))
|
|
||||||
: Normalize(Cross(hostUp, new Vector3D(0, 1, 0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 归一化right向量
|
|
||||||
var rightLength = Math.Sqrt(right.X * right.X + right.Y * right.Y + right.Z * right.Z);
|
|
||||||
if (rightLength > 0.001)
|
|
||||||
{
|
|
||||||
right = new Vector3D(right.X / rightLength, right.Y / rightLength, right.Z / rightLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算高度向量(垂直于方向向量和宽度向量)
|
|
||||||
var up = new Vector3D(
|
|
||||||
direction.Y * right.Z - direction.Z * right.Y,
|
|
||||||
direction.Z * right.X - direction.X * right.Z,
|
|
||||||
direction.X * right.Y - direction.Y * right.X
|
|
||||||
);
|
|
||||||
|
|
||||||
// 归一化up向量
|
|
||||||
var upLength = Math.Sqrt(up.X * up.X + up.Y * up.Y + up.Z * up.Z);
|
|
||||||
if (upLength > 0.001)
|
|
||||||
{
|
|
||||||
up = new Vector3D(up.X / upLength, up.Y / upLength, up.Z / upLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算长方体的边界框和向量
|
// 计算长方体的边界框和向量
|
||||||
var halfWidth = width / 2.0;
|
var halfWidth = width / 2.0;
|
||||||
@ -2894,7 +2809,7 @@ namespace NavisworksTransport
|
|||||||
/// <param name="height">高度</param>
|
/// <param name="height">高度</param>
|
||||||
/// <param name="length">指定长度(覆盖默认计算值)</param>
|
/// <param name="length">指定长度(覆盖默认计算值)</param>
|
||||||
/// <param name="horizontalDirection">水平段方向向量(用于垂直路径渲染时确定通行空间方向)</param>
|
/// <param name="horizontalDirection">水平段方向向量(用于垂直路径渲染时确定通行空间方向)</param>
|
||||||
private void RenderCuboidMarkerWithLength(Graphics graphics, Point3D startPoint, Point3D endPoint, double width, double height, double length, Vector3D horizontalDirection = null)
|
private void RenderCuboidMarkerWithLength(Graphics graphics, Point3D startPoint, Point3D endPoint, double width, double height, double length, Vector3D horizontalDirection = null, Vector3D upReference = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -2912,47 +2827,11 @@ namespace NavisworksTransport
|
|||||||
|
|
||||||
direction = new Vector3D(direction.X / directionLength, direction.Y / directionLength, direction.Z / directionLength);
|
direction = new Vector3D(direction.X / directionLength, direction.Y / directionLength, direction.Z / directionLength);
|
||||||
|
|
||||||
var hostUp = GetHostUpVector();
|
var (right, up) = ObjectSpaceOrientationHelper.CalculateAxes(
|
||||||
var right = Cross(direction, hostUp);
|
startPoint,
|
||||||
|
endPoint,
|
||||||
double parallelToUp = Math.Abs(
|
upReference ?? GetHostUpVector(),
|
||||||
direction.X * hostUp.X +
|
horizontalDirection);
|
||||||
direction.Y * hostUp.Y +
|
|
||||||
direction.Z * hostUp.Z);
|
|
||||||
if (parallelToUp > 0.9)
|
|
||||||
{
|
|
||||||
if (horizontalDirection != null)
|
|
||||||
{
|
|
||||||
right = Cross(horizontalDirection, hostUp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
right = Math.Abs(hostUp.X) < 0.9
|
|
||||||
? Normalize(Cross(hostUp, new Vector3D(1, 0, 0)))
|
|
||||||
: Normalize(Cross(hostUp, new Vector3D(0, 1, 0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 归一化right向量
|
|
||||||
var rightLength = Math.Sqrt(right.X * right.X + right.Y * right.Y + right.Z * right.Z);
|
|
||||||
if (rightLength > 0.001)
|
|
||||||
{
|
|
||||||
right = new Vector3D(right.X / rightLength, right.Y / rightLength, right.Z / rightLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算高度向量(垂直于方向向量和宽度向量)
|
|
||||||
var up = new Vector3D(
|
|
||||||
direction.Y * right.Z - direction.Z * right.Y,
|
|
||||||
direction.Z * right.X - direction.X * right.Z,
|
|
||||||
direction.X * right.Y - direction.Y * right.X
|
|
||||||
);
|
|
||||||
|
|
||||||
// 归一化up向量
|
|
||||||
var upLength = Math.Sqrt(up.X * up.X + up.Y * up.Y + up.Z * up.Z);
|
|
||||||
if (upLength > 0.001)
|
|
||||||
{
|
|
||||||
up = new Vector3D(up.X / upLength, up.Y / upLength, up.Z / upLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算长方体的边界框和向量
|
// 计算长方体的边界框和向量
|
||||||
var halfWidth = width / 2.0;
|
var halfWidth = width / 2.0;
|
||||||
@ -3009,7 +2888,8 @@ namespace NavisworksTransport
|
|||||||
lineMarker.EndPoint,
|
lineMarker.EndPoint,
|
||||||
width,
|
width,
|
||||||
lineMarker.Height,
|
lineMarker.Height,
|
||||||
lineMarker.HorizontalDirection
|
lineMarker.HorizontalDirection,
|
||||||
|
lineMarker.UpDirection
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3052,11 +2932,25 @@ namespace NavisworksTransport
|
|||||||
width,
|
width,
|
||||||
lineMarker.Height,
|
lineMarker.Height,
|
||||||
_passageAlongPath,
|
_passageAlongPath,
|
||||||
lineMarker.HorizontalDirection
|
lineMarker.HorizontalDirection,
|
||||||
|
lineMarker.UpDirection
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector3D ResolveObjectSpaceUpDirection(PathRoute route)
|
||||||
|
{
|
||||||
|
if (route?.PathType == NavisworksTransport.PathType.Rail && route.RailPreferredNormal != null)
|
||||||
|
{
|
||||||
|
return Normalize(new Vector3D(
|
||||||
|
route.RailPreferredNormal.X,
|
||||||
|
route.RailPreferredNormal.Y,
|
||||||
|
route.RailPreferredNormal.Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetHostUpVector();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 计算采样点处的切线方向
|
/// 计算采样点处的切线方向
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -154,6 +154,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
private Vector3 _assemblyInstallationPlaneNormal;
|
private Vector3 _assemblyInstallationPlaneNormal;
|
||||||
private Vector3 _assemblyInstallationPlaneSpanDirection;
|
private Vector3 _assemblyInstallationPlaneSpanDirection;
|
||||||
private double _assemblyInstallationOffsetDistanceInMeters;
|
private double _assemblyInstallationOffsetDistanceInMeters;
|
||||||
|
private readonly List<Point3D> _assemblyInstallationSeedPoints = new List<Point3D>();
|
||||||
private readonly List<Point3D> _assemblyEndFaceSeedPoints = new List<Point3D>();
|
private readonly List<Point3D> _assemblyEndFaceSeedPoints = new List<Point3D>();
|
||||||
private const string AssemblyAnchorMarkerPathId = "assembly_anchor_marker";
|
private const string AssemblyAnchorMarkerPathId = "assembly_anchor_marker";
|
||||||
private const string AssemblyCenterGuideLinePathId = "assembly_center_guide_line";
|
private const string AssemblyCenterGuideLinePathId = "assembly_center_guide_line";
|
||||||
@ -1347,6 +1348,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
{
|
{
|
||||||
await SafeExecuteAsync(() =>
|
await SafeExecuteAsync(() =>
|
||||||
{
|
{
|
||||||
|
ClearNonGridPathVisualizations("[直线装配] 捕获箱体");
|
||||||
|
|
||||||
var document = NavisApplication.ActiveDocument;
|
var document = NavisApplication.ActiveDocument;
|
||||||
var selectedItem = document?.CurrentSelection?.SelectedItems?.FirstOrDefault();
|
var selectedItem = document?.CurrentSelection?.SelectedItems?.FirstOrDefault();
|
||||||
if (selectedItem == null)
|
if (selectedItem == null)
|
||||||
@ -1379,6 +1382,30 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
}, "捕获终点箱体");
|
}, "捕获终点箱体");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ClearNonGridPathVisualizations(string context)
|
||||||
|
{
|
||||||
|
if (PathPointRenderPlugin.Instance == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PathPointRenderPlugin.Instance.ClearPathsExcept(
|
||||||
|
"grid_visualization_all",
|
||||||
|
"grid_visualization_channel",
|
||||||
|
"grid_visualization_unknown",
|
||||||
|
"grid_visualization_obstacle",
|
||||||
|
"grid_visualization_door");
|
||||||
|
LogManager.Info($"{context}:已清除现有路径可视化显示(保留网格可视化)");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"{context}:清除现有路径可视化失败: {ex.Message}", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ExecuteGenerateAssemblyReferenceRodAsync()
|
private async Task ExecuteGenerateAssemblyReferenceRodAsync()
|
||||||
{
|
{
|
||||||
await SafeExecuteAsync(() =>
|
await SafeExecuteAsync(() =>
|
||||||
@ -1546,7 +1573,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
throw new InvalidOperationException("ToolPlugin 初始化失败,请重试。");
|
throw new InvalidOperationException("ToolPlugin 初始化失败,请重试。");
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateMainStatus("请在终点箱体表面点击安装点,系统将按该点计算安装参考面和终点锚点。");
|
_assemblyInstallationSeedPoints.Clear();
|
||||||
|
UpdateMainStatus("请在终点箱体表面连续点击两个安装面点,系统将按两点和光轴计算安装参考面与安装点。");
|
||||||
LogManager.Info("[直线装配] 已进入安装点拾取模式");
|
LogManager.Info("[直线装配] 已进入安装点拾取模式");
|
||||||
}, "选择安装点");
|
}, "选择安装点");
|
||||||
}
|
}
|
||||||
@ -1640,7 +1668,21 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildAndRenderAssemblyInstallationReference(pickResult.Point);
|
_assemblyInstallationSeedPoints.Add(pickResult.Point);
|
||||||
|
RenderAssemblyInstallationPickPoints(_assemblyInstallationSeedPoints);
|
||||||
|
|
||||||
|
int pickedCount = _assemblyInstallationSeedPoints.Count;
|
||||||
|
LogManager.Info($"[直线装配] 已记录安装面点 {pickedCount}: ({pickResult.Point.X:F3}, {pickResult.Point.Y:F3}, {pickResult.Point.Z:F3})");
|
||||||
|
|
||||||
|
if (pickedCount < 2)
|
||||||
|
{
|
||||||
|
UpdateMainStatus("已记录安装面点 1/2,请继续在同一安装面上点击第二个点。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildAndRenderAssemblyInstallationReference(
|
||||||
|
_assemblyInstallationSeedPoints[0],
|
||||||
|
_assemblyInstallationSeedPoints[1]);
|
||||||
CleanupAssemblyInstallationSelection();
|
CleanupAssemblyInstallationSelection();
|
||||||
}, "处理安装点拾取");
|
}, "处理安装点拾取");
|
||||||
}
|
}
|
||||||
@ -1665,6 +1707,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
RailPathDefinitionMode = RailPathDefinitionMode.RailCenterLine
|
RailPathDefinitionMode = RailPathDefinitionMode.RailCenterLine
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (_hasAssemblyInstallationReference)
|
||||||
|
{
|
||||||
|
route.RailPreferredNormal = new Point3D(
|
||||||
|
_assemblyInstallationPlaneNormal.X,
|
||||||
|
_assemblyInstallationPlaneNormal.Y,
|
||||||
|
_assemblyInstallationPlaneNormal.Z);
|
||||||
|
}
|
||||||
|
|
||||||
route.AddPoint(new PathPoint(startPoint, "装配起点", PathPointType.StartPoint));
|
route.AddPoint(new PathPoint(startPoint, "装配起点", PathPointType.StartPoint));
|
||||||
route.AddPoint(new PathPoint(endPoint, "装配终点", PathPointType.EndPoint));
|
route.AddPoint(new PathPoint(endPoint, "装配终点", PathPointType.EndPoint));
|
||||||
|
|
||||||
@ -1706,7 +1756,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
GetAssemblyAnchorText());
|
GetAssemblyAnchorText());
|
||||||
|
|
||||||
OnPropertyChanged(nameof(PathRoutes));
|
OnPropertyChanged(nameof(PathRoutes));
|
||||||
LogManager.Info($"[直线装配] 已生成并完成路径: {route.Name},起点=({startPoint.X:F2}, {startPoint.Y:F2}, {startPoint.Z:F2}),终点=({endPoint.X:F2}, {endPoint.Y:F2}, {endPoint.Z:F2})");
|
LogManager.Info(
|
||||||
|
$"[直线装配] 已生成并完成路径: {route.Name},起点=({startPoint.X:F2}, {startPoint.Y:F2}, {startPoint.Z:F2}),终点=({endPoint.X:F2}, {endPoint.Y:F2}, {endPoint.Z:F2})" +
|
||||||
|
$"{(route.RailPreferredNormal != null ? $",安装法向=({route.RailPreferredNormal.X:F3}, {route.RailPreferredNormal.Y:F3}, {route.RailPreferredNormal.Z:F3})" : string.Empty)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HideAssemblyReferenceVisuals(bool resetStartPointText, string statusMessage, string logMessage)
|
private void HideAssemblyReferenceVisuals(bool resetStartPointText, string statusMessage, string logMessage)
|
||||||
@ -1882,7 +1934,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
: string.Format("{0}点=未选择", anchorText);
|
: string.Format("{0}点=未选择", anchorText);
|
||||||
string installationText = _hasAssemblyInstallationReference
|
string installationText = _hasAssemblyInstallationReference
|
||||||
? string.Format(
|
? string.Format(
|
||||||
"选定安装点=({0:F2}, {1:F2}, {2:F2}),安装点=({3:F2}, {4:F2}, {5:F2}),偏距={6:F3}m",
|
"安装面点中点=({0:F2}, {1:F2}, {2:F2}),安装点=({3:F2}, {4:F2}, {5:F2}),偏距={6:F3}m",
|
||||||
_assemblyInstallationPickPoint.X,
|
_assemblyInstallationPickPoint.X,
|
||||||
_assemblyInstallationPickPoint.Y,
|
_assemblyInstallationPickPoint.Y,
|
||||||
_assemblyInstallationPickPoint.Z,
|
_assemblyInstallationPickPoint.Z,
|
||||||
@ -2214,7 +2266,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
RenderStyleName.AssemblyGuideLine);
|
RenderStyleName.AssemblyGuideLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildAndRenderAssemblyInstallationReference(Point3D pickPoint)
|
private void BuildAndRenderAssemblyInstallationReference(Point3D firstPickPoint, Point3D secondPickPoint)
|
||||||
{
|
{
|
||||||
Point3D opticalAxisReferencePoint = GetAssemblyOpticalAxisReferencePoint();
|
Point3D opticalAxisReferencePoint = GetAssemblyOpticalAxisReferencePoint();
|
||||||
Point3D sphereCenterPoint = new Point3D(
|
Point3D sphereCenterPoint = new Point3D(
|
||||||
@ -2230,10 +2282,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
AssemblyInstallationReferenceResult result = AssemblyInstallationReferenceBuilder.Build(
|
AssemblyInstallationReferenceResult result = AssemblyInstallationReferenceBuilder.Build(
|
||||||
new Vector3((float)opticalAxisReferencePoint.X, (float)opticalAxisReferencePoint.Y, (float)opticalAxisReferencePoint.Z),
|
new Vector3((float)opticalAxisReferencePoint.X, (float)opticalAxisReferencePoint.Y, (float)opticalAxisReferencePoint.Z),
|
||||||
opticalAxisDirection,
|
opticalAxisDirection,
|
||||||
new Vector3((float)pickPoint.X, (float)pickPoint.Y, (float)pickPoint.Z));
|
new Vector3((float)firstPickPoint.X, (float)firstPickPoint.Y, (float)firstPickPoint.Z),
|
||||||
|
new Vector3((float)secondPickPoint.X, (float)secondPickPoint.Y, (float)secondPickPoint.Z));
|
||||||
|
|
||||||
_hasAssemblyInstallationReference = true;
|
_hasAssemblyInstallationReference = true;
|
||||||
_assemblyInstallationPickPoint = pickPoint;
|
_assemblyInstallationPickPoint = AssemblyEndFaceAnalyzer.ToPoint3D((result.PickPoint + result.SecondaryPickPoint) * 0.5f);
|
||||||
_assemblyInstallationBaseAnchorPoint = AssemblyEndFaceAnalyzer.ToPoint3D(result.AnchorPoint);
|
_assemblyInstallationBaseAnchorPoint = AssemblyEndFaceAnalyzer.ToPoint3D(result.AnchorPoint);
|
||||||
_assemblyInstallationPlaneNormal = result.PlaneNormal;
|
_assemblyInstallationPlaneNormal = result.PlaneNormal;
|
||||||
_assemblyInstallationPlaneSpanDirection = result.PlaneSpanDirection;
|
_assemblyInstallationPlaneSpanDirection = result.PlaneSpanDirection;
|
||||||
@ -2242,7 +2295,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters));
|
OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters));
|
||||||
UpdateAssemblyInstallationAnchorFromVerticalOffset();
|
UpdateAssemblyInstallationAnchorFromVerticalOffset();
|
||||||
|
|
||||||
RenderAssemblyInstallationPickPoint(_assemblyInstallationPickPoint);
|
RenderAssemblyInstallationPickPoints(_assemblyInstallationSeedPoints);
|
||||||
RenderAssemblyInstallationCenterLine(AssemblyEndFaceAnalyzer.ToPoint3D(result.InstallLineBasePoint), result.OpticalAxisDirection);
|
RenderAssemblyInstallationCenterLine(AssemblyEndFaceAnalyzer.ToPoint3D(result.InstallLineBasePoint), result.OpticalAxisDirection);
|
||||||
|
|
||||||
RefreshAssemblyTerminalObjectInfo();
|
RefreshAssemblyTerminalObjectInfo();
|
||||||
@ -2250,14 +2303,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
UpdateMainStatus(
|
UpdateMainStatus(
|
||||||
$"安装参考已计算:安装点=({_assemblyInstallationAnchorPoint.X:F2}, {_assemblyInstallationAnchorPoint.Y:F2}, {_assemblyInstallationAnchorPoint.Z:F2}),偏距={_assemblyInstallationOffsetDistanceInMeters:F3}m");
|
$"安装参考已计算:安装点=({_assemblyInstallationAnchorPoint.X:F2}, {_assemblyInstallationAnchorPoint.Y:F2}, {_assemblyInstallationAnchorPoint.Z:F2}),偏距={_assemblyInstallationOffsetDistanceInMeters:F3}m");
|
||||||
LogManager.Info(
|
LogManager.Info(
|
||||||
$"[直线装配] 安装参考已计算: 选定安装点=({pickPoint.X:F3}, {pickPoint.Y:F3}, {pickPoint.Z:F3}), " +
|
$"[直线装配] 安装参考已计算: 安装面点1=({firstPickPoint.X:F3}, {firstPickPoint.Y:F3}, {firstPickPoint.Z:F3}), " +
|
||||||
|
$"安装面点2=({secondPickPoint.X:F3}, {secondPickPoint.Y:F3}, {secondPickPoint.Z:F3}), " +
|
||||||
$"安装点=({_assemblyInstallationAnchorPoint.X:F3}, {_assemblyInstallationAnchorPoint.Y:F3}, {_assemblyInstallationAnchorPoint.Z:F3}), " +
|
$"安装点=({_assemblyInstallationAnchorPoint.X:F3}, {_assemblyInstallationAnchorPoint.Y:F3}, {_assemblyInstallationAnchorPoint.Z:F3}), " +
|
||||||
$"偏距={_assemblyInstallationOffsetDistanceInMeters:F3}m, 平面法向=({result.PlaneNormal.X:F4}, {result.PlaneNormal.Y:F4}, {result.PlaneNormal.Z:F4})");
|
$"偏距={_assemblyInstallationOffsetDistanceInMeters:F3}m, 平面法向=({result.PlaneNormal.X:F4}, {result.PlaneNormal.Y:F4}, {result.PlaneNormal.Z:F4})");
|
||||||
OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod));
|
OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod));
|
||||||
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
|
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderAssemblyInstallationPickPoint(Point3D pickPoint)
|
private void RenderAssemblyInstallationPickPoints(IReadOnlyList<Point3D> pickPoints)
|
||||||
{
|
{
|
||||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||||
if (renderPlugin == null)
|
if (renderPlugin == null)
|
||||||
@ -2271,7 +2325,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
Id = AssemblyInstallationPickPointPathId,
|
Id = AssemblyInstallationPickPointPathId,
|
||||||
Description = "终端安装点"
|
Description = "终端安装点"
|
||||||
};
|
};
|
||||||
AddVisualizationPoint(markerRoute, pickPoint, "安装点", PathPointType.WayPoint);
|
for (int i = 0; i < pickPoints.Count; i++)
|
||||||
|
{
|
||||||
|
AddVisualizationPoint(markerRoute, pickPoints[i], $"安装面点{i + 1}", PathPointType.WayPoint);
|
||||||
|
}
|
||||||
renderPlugin.RenderPointOnly(markerRoute);
|
renderPlugin.RenderPointOnly(markerRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2462,6 +2519,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
_assemblyInstallationPlaneNormal = default(Vector3);
|
_assemblyInstallationPlaneNormal = default(Vector3);
|
||||||
_assemblyInstallationPlaneSpanDirection = default(Vector3);
|
_assemblyInstallationPlaneSpanDirection = default(Vector3);
|
||||||
_assemblyInstallationOffsetDistanceInMeters = 0.0;
|
_assemblyInstallationOffsetDistanceInMeters = 0.0;
|
||||||
|
_assemblyInstallationSeedPoints.Clear();
|
||||||
_assemblyAnchorVerticalOffsetInMeters = DefaultAssemblyAnchorVerticalOffsetInMeters;
|
_assemblyAnchorVerticalOffsetInMeters = DefaultAssemblyAnchorVerticalOffsetInMeters;
|
||||||
OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters));
|
OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters));
|
||||||
OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod));
|
OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod));
|
||||||
|
|||||||
@ -8,6 +8,7 @@ namespace NavisworksTransport.Utils.GeometryAnalysis
|
|||||||
public Vector3 OpticalAxisBasePoint { get; set; }
|
public Vector3 OpticalAxisBasePoint { get; set; }
|
||||||
public Vector3 OpticalAxisDirection { get; set; }
|
public Vector3 OpticalAxisDirection { get; set; }
|
||||||
public Vector3 PickPoint { get; set; }
|
public Vector3 PickPoint { get; set; }
|
||||||
|
public Vector3 SecondaryPickPoint { get; set; }
|
||||||
public Vector3 PlaneNormal { get; set; }
|
public Vector3 PlaneNormal { get; set; }
|
||||||
public Vector3 PlaneSpanDirection { get; set; }
|
public Vector3 PlaneSpanDirection { get; set; }
|
||||||
public float OffsetDistance { get; set; }
|
public float OffsetDistance { get; set; }
|
||||||
@ -57,6 +58,72 @@ namespace NavisworksTransport.Utils.GeometryAnalysis
|
|||||||
OpticalAxisBasePoint = opticalAxisBasePoint,
|
OpticalAxisBasePoint = opticalAxisBasePoint,
|
||||||
OpticalAxisDirection = axisDir,
|
OpticalAxisDirection = axisDir,
|
||||||
PickPoint = pickPoint,
|
PickPoint = pickPoint,
|
||||||
|
SecondaryPickPoint = pickPoint,
|
||||||
|
PlaneNormal = planeNormal,
|
||||||
|
PlaneSpanDirection = planeSpanDirection,
|
||||||
|
OffsetDistance = offsetDistance,
|
||||||
|
InstallLineBasePoint = installLineBasePoint,
|
||||||
|
AnchorPoint = anchorPoint
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssemblyInstallationReferenceResult Build(
|
||||||
|
Vector3 opticalAxisBasePoint,
|
||||||
|
Vector3 opticalAxisDirection,
|
||||||
|
Vector3 firstPickPoint,
|
||||||
|
Vector3 secondPickPoint)
|
||||||
|
{
|
||||||
|
float axisLength = opticalAxisDirection.Length();
|
||||||
|
if (axisLength < 1e-6f)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("光轴方向长度过小,无法计算安装参考。");
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 axisDir = opticalAxisDirection / axisLength;
|
||||||
|
Vector3 pickSegment = secondPickPoint - firstPickPoint;
|
||||||
|
Vector3 axisAlignedComponent = axisDir * Vector3.Dot(pickSegment, axisDir);
|
||||||
|
Vector3 planeSpanDirection = pickSegment - axisAlignedComponent;
|
||||||
|
float spanLength = planeSpanDirection.Length();
|
||||||
|
if (spanLength < MinimumOffsetDistance)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("两次安装点拾取几乎与光轴平行,无法确定安装参考面,请重新选择。");
|
||||||
|
}
|
||||||
|
|
||||||
|
planeSpanDirection /= spanLength;
|
||||||
|
|
||||||
|
Vector3 midpoint = (firstPickPoint + secondPickPoint) * 0.5f;
|
||||||
|
Vector3 planeNormal = Vector3.Cross(axisDir, planeSpanDirection);
|
||||||
|
float normalLength = planeNormal.Length();
|
||||||
|
if (normalLength < 1e-6f)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("安装参考面法向计算失败,请重新选择。");
|
||||||
|
}
|
||||||
|
|
||||||
|
planeNormal /= normalLength;
|
||||||
|
|
||||||
|
Vector3 midpointOffset = midpoint - opticalAxisBasePoint;
|
||||||
|
float signedOffset = Vector3.Dot(midpointOffset, planeNormal);
|
||||||
|
if (Math.Abs(signedOffset) < MinimumOffsetDistance)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("安装面中点距离光轴过小,无法确定安装参考面,请重新选择。");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signedOffset < 0f)
|
||||||
|
{
|
||||||
|
planeNormal = -planeNormal;
|
||||||
|
signedOffset = -signedOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
float offsetDistance = signedOffset;
|
||||||
|
Vector3 installLineBasePoint = opticalAxisBasePoint + planeNormal * offsetDistance;
|
||||||
|
Vector3 anchorPoint = ProjectPointToLine(midpoint, installLineBasePoint, axisDir);
|
||||||
|
|
||||||
|
return new AssemblyInstallationReferenceResult
|
||||||
|
{
|
||||||
|
OpticalAxisBasePoint = opticalAxisBasePoint,
|
||||||
|
OpticalAxisDirection = axisDir,
|
||||||
|
PickPoint = firstPickPoint,
|
||||||
|
SecondaryPickPoint = secondPickPoint,
|
||||||
PlaneNormal = planeNormal,
|
PlaneNormal = planeNormal,
|
||||||
PlaneSpanDirection = planeSpanDirection,
|
PlaneSpanDirection = planeSpanDirection,
|
||||||
OffsetDistance = offsetDistance,
|
OffsetDistance = offsetDistance,
|
||||||
|
|||||||
@ -17,6 +17,23 @@ namespace NavisworksTransport.Utils.CoordinateSystem
|
|||||||
Vector3 nextPoint,
|
Vector3 nextPoint,
|
||||||
Vector3 canonicalUp,
|
Vector3 canonicalUp,
|
||||||
out RailLocalFrame frame)
|
out RailLocalFrame frame)
|
||||||
|
{
|
||||||
|
return TryCreateLocalFrame(
|
||||||
|
previousPoint,
|
||||||
|
currentPoint,
|
||||||
|
nextPoint,
|
||||||
|
canonicalUp,
|
||||||
|
null,
|
||||||
|
out frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreateLocalFrame(
|
||||||
|
Vector3 previousPoint,
|
||||||
|
Vector3 currentPoint,
|
||||||
|
Vector3 nextPoint,
|
||||||
|
Vector3 canonicalUp,
|
||||||
|
Vector3? preferredNormal,
|
||||||
|
out RailLocalFrame frame)
|
||||||
{
|
{
|
||||||
frame = null;
|
frame = null;
|
||||||
|
|
||||||
@ -25,6 +42,7 @@ namespace NavisworksTransport.Utils.CoordinateSystem
|
|||||||
currentPoint,
|
currentPoint,
|
||||||
nextPoint,
|
nextPoint,
|
||||||
canonicalUp,
|
canonicalUp,
|
||||||
|
preferredNormal,
|
||||||
out var forward,
|
out var forward,
|
||||||
out var lateral,
|
out var lateral,
|
||||||
out var up))
|
out var up))
|
||||||
@ -44,6 +62,27 @@ namespace NavisworksTransport.Utils.CoordinateSystem
|
|||||||
out Vector3 forward,
|
out Vector3 forward,
|
||||||
out Vector3 lateral,
|
out Vector3 lateral,
|
||||||
out Vector3 up)
|
out Vector3 up)
|
||||||
|
{
|
||||||
|
return TryCreateBasis(
|
||||||
|
previousPoint,
|
||||||
|
currentPoint,
|
||||||
|
nextPoint,
|
||||||
|
canonicalUp,
|
||||||
|
null,
|
||||||
|
out forward,
|
||||||
|
out lateral,
|
||||||
|
out up);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreateBasis(
|
||||||
|
Vector3 previousPoint,
|
||||||
|
Vector3 currentPoint,
|
||||||
|
Vector3 nextPoint,
|
||||||
|
Vector3 canonicalUp,
|
||||||
|
Vector3? preferredNormal,
|
||||||
|
out Vector3 forward,
|
||||||
|
out Vector3 lateral,
|
||||||
|
out Vector3 up)
|
||||||
{
|
{
|
||||||
forward = default;
|
forward = default;
|
||||||
lateral = default;
|
lateral = default;
|
||||||
@ -61,7 +100,13 @@ namespace NavisworksTransport.Utils.CoordinateSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
forward = Vector3.Normalize(tangent);
|
forward = Vector3.Normalize(tangent);
|
||||||
Vector3 projectedUp = canonicalUp - Vector3.Dot(canonicalUp, forward) * forward;
|
Vector3 referenceUp = canonicalUp;
|
||||||
|
if (preferredNormal.HasValue && preferredNormal.Value.LengthSquared() >= TangentEpsilon)
|
||||||
|
{
|
||||||
|
referenceUp = Vector3.Normalize(preferredNormal.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 projectedUp = referenceUp - Vector3.Dot(referenceUp, forward) * forward;
|
||||||
if (projectedUp.LengthSquared() < TangentEpsilon)
|
if (projectedUp.LengthSquared() < TangentEpsilon)
|
||||||
{
|
{
|
||||||
projectedUp = Math.Abs(forward.Z) < 0.9f
|
projectedUp = Math.Abs(forward.Z) < 0.9f
|
||||||
@ -95,6 +140,7 @@ namespace NavisworksTransport.Utils.CoordinateSystem
|
|||||||
nextPoint,
|
nextPoint,
|
||||||
canonicalUp,
|
canonicalUp,
|
||||||
convention,
|
convention,
|
||||||
|
null,
|
||||||
0.0,
|
0.0,
|
||||||
out rotation);
|
out rotation);
|
||||||
}
|
}
|
||||||
@ -107,6 +153,27 @@ namespace NavisworksTransport.Utils.CoordinateSystem
|
|||||||
ModelAxisConvention convention,
|
ModelAxisConvention convention,
|
||||||
double localUpRotationDegrees,
|
double localUpRotationDegrees,
|
||||||
out Quaternion rotation)
|
out Quaternion rotation)
|
||||||
|
{
|
||||||
|
return TryCreateQuaternion(
|
||||||
|
previousPoint,
|
||||||
|
currentPoint,
|
||||||
|
nextPoint,
|
||||||
|
canonicalUp,
|
||||||
|
convention,
|
||||||
|
null,
|
||||||
|
localUpRotationDegrees,
|
||||||
|
out rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreateQuaternion(
|
||||||
|
Vector3 previousPoint,
|
||||||
|
Vector3 currentPoint,
|
||||||
|
Vector3 nextPoint,
|
||||||
|
Vector3 canonicalUp,
|
||||||
|
ModelAxisConvention convention,
|
||||||
|
Vector3? preferredNormal,
|
||||||
|
double localUpRotationDegrees,
|
||||||
|
out Quaternion rotation)
|
||||||
{
|
{
|
||||||
rotation = Quaternion.Identity;
|
rotation = Quaternion.Identity;
|
||||||
|
|
||||||
@ -115,7 +182,15 @@ namespace NavisworksTransport.Utils.CoordinateSystem
|
|||||||
throw new ArgumentNullException(nameof(convention));
|
throw new ArgumentNullException(nameof(convention));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryCreateBasis(previousPoint, currentPoint, nextPoint, canonicalUp, out var forward, out _, out var up))
|
if (!TryCreateBasis(
|
||||||
|
previousPoint,
|
||||||
|
currentPoint,
|
||||||
|
nextPoint,
|
||||||
|
canonicalUp,
|
||||||
|
preferredNormal,
|
||||||
|
out var forward,
|
||||||
|
out _,
|
||||||
|
out var up))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
92
src/Utils/CoordinateSystem/ObjectSpaceOrientationHelper.cs
Normal file
92
src/Utils/CoordinateSystem/ObjectSpaceOrientationHelper.cs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
using Autodesk.Navisworks.Api;
|
||||||
|
|
||||||
|
namespace NavisworksTransport.Utils.CoordinateSystem
|
||||||
|
{
|
||||||
|
public static class ObjectSpaceOrientationHelper
|
||||||
|
{
|
||||||
|
public static (Vector3D right, Vector3D up) CalculateAxes(
|
||||||
|
Point3D startPoint,
|
||||||
|
Point3D endPoint,
|
||||||
|
Vector3D upReference,
|
||||||
|
Vector3D horizontalDirection = null)
|
||||||
|
{
|
||||||
|
var segmentDirection = new Vector3(
|
||||||
|
(float)(endPoint.X - startPoint.X),
|
||||||
|
(float)(endPoint.Y - startPoint.Y),
|
||||||
|
(float)(endPoint.Z - startPoint.Z));
|
||||||
|
|
||||||
|
var (right, up) = CalculateAxes(
|
||||||
|
segmentDirection,
|
||||||
|
ToNumerics(upReference),
|
||||||
|
horizontalDirection == null ? (Vector3?)null : ToNumerics(horizontalDirection));
|
||||||
|
|
||||||
|
return (ToNavisworks(right), ToNavisworks(up));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (Vector3 right, Vector3 up) CalculateAxes(
|
||||||
|
Vector3 segmentDirection,
|
||||||
|
Vector3 upReference,
|
||||||
|
Vector3? horizontalDirection = null)
|
||||||
|
{
|
||||||
|
double segmentLength = Math.Sqrt(
|
||||||
|
segmentDirection.X * segmentDirection.X +
|
||||||
|
segmentDirection.Y * segmentDirection.Y +
|
||||||
|
segmentDirection.Z * segmentDirection.Z);
|
||||||
|
|
||||||
|
if (segmentLength < 1e-9)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("路径段长度过小,无法计算通行空间方向。");
|
||||||
|
}
|
||||||
|
|
||||||
|
var normalizedDirection = Vector3.Normalize(segmentDirection);
|
||||||
|
var normalizedUpReference = Normalize(upReference);
|
||||||
|
var right = Cross(normalizedDirection, normalizedUpReference);
|
||||||
|
|
||||||
|
double parallelToUp = Math.Abs(Vector3.Dot(normalizedDirection, normalizedUpReference));
|
||||||
|
if (parallelToUp > 0.9)
|
||||||
|
{
|
||||||
|
if (horizontalDirection.HasValue)
|
||||||
|
{
|
||||||
|
right = Cross(horizontalDirection.Value, normalizedUpReference);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
right = Math.Abs(normalizedUpReference.X) < 0.9f
|
||||||
|
? Normalize(Cross(normalizedUpReference, new Vector3(1f, 0f, 0f)))
|
||||||
|
: Normalize(Cross(normalizedUpReference, new Vector3(0f, 1f, 0f)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
right = Normalize(right);
|
||||||
|
var up = Normalize(Cross(normalizedDirection, right));
|
||||||
|
return (right, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector3 Cross(Vector3 a, Vector3 b)
|
||||||
|
{
|
||||||
|
return Vector3.Cross(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector3 Normalize(Vector3 vector)
|
||||||
|
{
|
||||||
|
if (vector.LengthSquared() < 1e-9f)
|
||||||
|
{
|
||||||
|
return Vector3.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vector3.Normalize(vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector3 ToNumerics(Vector3D vector)
|
||||||
|
{
|
||||||
|
return new Vector3((float)vector.X, (float)vector.Y, (float)vector.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector3D ToNavisworks(Vector3 vector)
|
||||||
|
{
|
||||||
|
return new Vector3D(vector.X, vector.Y, vector.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -135,7 +135,7 @@ namespace NavisworksTransport.Utils
|
|||||||
|
|
||||||
var adapterForRail = CoordinateSystemManager.Instance.CreateHostAdapter();
|
var adapterForRail = CoordinateSystemManager.Instance.CreateHostAdapter();
|
||||||
var canonicalReferencePointForRail = adapterForRail.ToCanonicalPoint(referencePoint);
|
var canonicalReferencePointForRail = adapterForRail.ToCanonicalPoint(referencePoint);
|
||||||
if (!TryCreateCanonicalLocalFrame(previousPoint, referencePoint, nextPoint, out RailLocalFrame frame))
|
if (!TryCreateCanonicalLocalFrame(route, previousPoint, referencePoint, nextPoint, out RailLocalFrame frame))
|
||||||
{
|
{
|
||||||
var canonicalCenterPointForRailFallback = new Point3D(
|
var canonicalCenterPointForRailFallback = new Point3D(
|
||||||
canonicalReferencePointForRail.X,
|
canonicalReferencePointForRail.X,
|
||||||
@ -165,6 +165,22 @@ namespace NavisworksTransport.Utils
|
|||||||
out Matrix3 linearTransform)
|
out Matrix3 linearTransform)
|
||||||
{
|
{
|
||||||
return TryCreateRailLinearTransform(
|
return TryCreateRailLinearTransform(
|
||||||
|
null,
|
||||||
|
previousPoint,
|
||||||
|
currentPoint,
|
||||||
|
nextPoint,
|
||||||
|
out linearTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreateRailLinearTransform(
|
||||||
|
PathRoute route,
|
||||||
|
Point3D previousPoint,
|
||||||
|
Point3D currentPoint,
|
||||||
|
Point3D nextPoint,
|
||||||
|
out Matrix3 linearTransform)
|
||||||
|
{
|
||||||
|
return TryCreateRailLinearTransform(
|
||||||
|
route,
|
||||||
previousPoint,
|
previousPoint,
|
||||||
currentPoint,
|
currentPoint,
|
||||||
nextPoint,
|
nextPoint,
|
||||||
@ -177,6 +193,7 @@ namespace NavisworksTransport.Utils
|
|||||||
/// 通过模型局部轴约定显式指定本地哪个轴代表 forward/up。
|
/// 通过模型局部轴约定显式指定本地哪个轴代表 forward/up。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool TryCreateRailLinearTransform(
|
public static bool TryCreateRailLinearTransform(
|
||||||
|
PathRoute route,
|
||||||
Point3D previousPoint,
|
Point3D previousPoint,
|
||||||
Point3D currentPoint,
|
Point3D currentPoint,
|
||||||
Point3D nextPoint,
|
Point3D nextPoint,
|
||||||
@ -184,6 +201,7 @@ namespace NavisworksTransport.Utils
|
|||||||
out Matrix3 linearTransform)
|
out Matrix3 linearTransform)
|
||||||
{
|
{
|
||||||
return TryCreateRailLinearTransform(
|
return TryCreateRailLinearTransform(
|
||||||
|
route,
|
||||||
previousPoint,
|
previousPoint,
|
||||||
currentPoint,
|
currentPoint,
|
||||||
nextPoint,
|
nextPoint,
|
||||||
@ -193,6 +211,7 @@ namespace NavisworksTransport.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryCreateRailLinearTransform(
|
public static bool TryCreateRailLinearTransform(
|
||||||
|
PathRoute route,
|
||||||
Point3D previousPoint,
|
Point3D previousPoint,
|
||||||
Point3D currentPoint,
|
Point3D currentPoint,
|
||||||
Point3D nextPoint,
|
Point3D nextPoint,
|
||||||
@ -217,6 +236,7 @@ namespace NavisworksTransport.Utils
|
|||||||
canonicalCurrentPoint,
|
canonicalCurrentPoint,
|
||||||
canonicalNextPoint,
|
canonicalNextPoint,
|
||||||
HostCoordinateAdapter.CanonicalUpVector3,
|
HostCoordinateAdapter.CanonicalUpVector3,
|
||||||
|
ResolvePreferredNormal(route),
|
||||||
out RailLocalFrame frame))
|
out RailLocalFrame frame))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -231,6 +251,7 @@ namespace NavisworksTransport.Utils
|
|||||||
canonicalNextPoint,
|
canonicalNextPoint,
|
||||||
HostCoordinateAdapter.CanonicalUpVector3,
|
HostCoordinateAdapter.CanonicalUpVector3,
|
||||||
axisConvention,
|
axisConvention,
|
||||||
|
ResolvePreferredNormal(route),
|
||||||
localUpRotationDegrees,
|
localUpRotationDegrees,
|
||||||
out var correctedRotation)
|
out var correctedRotation)
|
||||||
? correctedRotation
|
? correctedRotation
|
||||||
@ -270,6 +291,22 @@ namespace NavisworksTransport.Utils
|
|||||||
out Rotation3D rotation)
|
out Rotation3D rotation)
|
||||||
{
|
{
|
||||||
return TryCreateRailRotation(
|
return TryCreateRailRotation(
|
||||||
|
null,
|
||||||
|
previousPoint,
|
||||||
|
currentPoint,
|
||||||
|
nextPoint,
|
||||||
|
out rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreateRailRotation(
|
||||||
|
PathRoute route,
|
||||||
|
Point3D previousPoint,
|
||||||
|
Point3D currentPoint,
|
||||||
|
Point3D nextPoint,
|
||||||
|
out Rotation3D rotation)
|
||||||
|
{
|
||||||
|
return TryCreateRailRotation(
|
||||||
|
route,
|
||||||
previousPoint,
|
previousPoint,
|
||||||
currentPoint,
|
currentPoint,
|
||||||
nextPoint,
|
nextPoint,
|
||||||
@ -285,6 +322,24 @@ namespace NavisworksTransport.Utils
|
|||||||
out Rotation3D rotation)
|
out Rotation3D rotation)
|
||||||
{
|
{
|
||||||
return TryCreateRailRotation(
|
return TryCreateRailRotation(
|
||||||
|
null,
|
||||||
|
previousPoint,
|
||||||
|
currentPoint,
|
||||||
|
nextPoint,
|
||||||
|
axisConvention,
|
||||||
|
out rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreateRailRotation(
|
||||||
|
PathRoute route,
|
||||||
|
Point3D previousPoint,
|
||||||
|
Point3D currentPoint,
|
||||||
|
Point3D nextPoint,
|
||||||
|
ModelAxisConvention axisConvention,
|
||||||
|
out Rotation3D rotation)
|
||||||
|
{
|
||||||
|
return TryCreateRailRotation(
|
||||||
|
route,
|
||||||
previousPoint,
|
previousPoint,
|
||||||
currentPoint,
|
currentPoint,
|
||||||
nextPoint,
|
nextPoint,
|
||||||
@ -294,6 +349,7 @@ namespace NavisworksTransport.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryCreateRailRotation(
|
public static bool TryCreateRailRotation(
|
||||||
|
PathRoute route,
|
||||||
Point3D previousPoint,
|
Point3D previousPoint,
|
||||||
Point3D currentPoint,
|
Point3D currentPoint,
|
||||||
Point3D nextPoint,
|
Point3D nextPoint,
|
||||||
@ -305,6 +361,7 @@ namespace NavisworksTransport.Utils
|
|||||||
LogRotationConstructorConventionOnce();
|
LogRotationConstructorConventionOnce();
|
||||||
|
|
||||||
if (!TryCreateRailLinearTransform(
|
if (!TryCreateRailLinearTransform(
|
||||||
|
route,
|
||||||
previousPoint,
|
previousPoint,
|
||||||
currentPoint,
|
currentPoint,
|
||||||
nextPoint,
|
nextPoint,
|
||||||
@ -446,7 +503,7 @@ namespace NavisworksTransport.Utils
|
|||||||
|
|
||||||
private static Vector3D ResolveRailNormal(Point3D previousPoint, Point3D currentPoint, Point3D nextPoint)
|
private static Vector3D ResolveRailNormal(Point3D previousPoint, Point3D currentPoint, Point3D nextPoint)
|
||||||
{
|
{
|
||||||
if (TryCreateCanonicalLocalFrame(previousPoint, currentPoint, nextPoint, out RailLocalFrame frame))
|
if (TryCreateCanonicalLocalFrame(null, previousPoint, currentPoint, nextPoint, out RailLocalFrame frame))
|
||||||
{
|
{
|
||||||
return ToNavVector(frame.Normal);
|
return ToNavVector(frame.Normal);
|
||||||
}
|
}
|
||||||
@ -479,6 +536,7 @@ namespace NavisworksTransport.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryCreateCanonicalLocalFrame(
|
private static bool TryCreateCanonicalLocalFrame(
|
||||||
|
PathRoute route,
|
||||||
Point3D previousPoint,
|
Point3D previousPoint,
|
||||||
Point3D currentPoint,
|
Point3D currentPoint,
|
||||||
Point3D nextPoint,
|
Point3D nextPoint,
|
||||||
@ -490,9 +548,37 @@ namespace NavisworksTransport.Utils
|
|||||||
ToNumerics(adapter.ToCanonicalPoint(currentPoint)),
|
ToNumerics(adapter.ToCanonicalPoint(currentPoint)),
|
||||||
ToNumerics(adapter.ToCanonicalPoint(nextPoint)),
|
ToNumerics(adapter.ToCanonicalPoint(nextPoint)),
|
||||||
HostCoordinateAdapter.CanonicalUpVector3,
|
HostCoordinateAdapter.CanonicalUpVector3,
|
||||||
|
ResolvePreferredNormal(route),
|
||||||
out frame);
|
out frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Vector3? ResolvePreferredNormal(PathRoute route)
|
||||||
|
{
|
||||||
|
if (route?.RailPreferredNormal == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var preferredNormal = new Vector3(
|
||||||
|
(float)route.RailPreferredNormal.X,
|
||||||
|
(float)route.RailPreferredNormal.Y,
|
||||||
|
(float)route.RailPreferredNormal.Z);
|
||||||
|
|
||||||
|
if (preferredNormal.LengthSquared() < 1e-9f)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
|
||||||
|
Vector3 canonicalPreferredNormal = adapter.ToCanonicalVector3(preferredNormal);
|
||||||
|
if (canonicalPreferredNormal.LengthSquared() < 1e-9f)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Vector3.Normalize(canonicalPreferredNormal);
|
||||||
|
}
|
||||||
|
|
||||||
private static Vector3D Normalize(Vector3D vector)
|
private static Vector3D Normalize(Vector3D vector)
|
||||||
{
|
{
|
||||||
double lengthSquared = vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z;
|
double lengthSquared = vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user