Refine assembly installation workflow UI
This commit is contained in:
parent
70aaff10bf
commit
93ad55c725
@ -62,6 +62,7 @@
|
||||
<Compile Include="UnitTests\CoordinateSystem\ModelAxisConventionTests.cs" />
|
||||
<Compile Include="UnitTests\CoordinateSystem\ProjectReferenceFrameTests.cs" />
|
||||
<Compile Include="UnitTests\CoordinateSystem\AssemblyEndFaceAnalyzerTests.cs" />
|
||||
<Compile Include="UnitTests\CoordinateSystem\AssemblyInstallationReferenceBuilderTests.cs" />
|
||||
<Compile Include="UnitTests\Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@ -140,6 +140,7 @@
|
||||
<!-- Core - Section Box Export -->
|
||||
<Compile Include="src\Core\SectionBoxExporter.cs" />
|
||||
<Compile Include="src\Utils\Assembly\AssemblyEndFaceAnalyzer.cs" />
|
||||
<Compile Include="src\Utils\Assembly\AssemblyInstallationReferenceBuilder.cs" />
|
||||
<!-- Core - Configuration Management -->
|
||||
<Compile Include="src\Core\Config\SystemConfig.cs" />
|
||||
<Compile Include="src\Core\Config\ConfigManager.cs" />
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using NavisworksTransport.Utils.GeometryAnalysis;
|
||||
|
||||
namespace NavisworksTransport.UnitTests.CoordinateSystem
|
||||
{
|
||||
[TestClass]
|
||||
public class AssemblyInstallationReferenceBuilderTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Build_ShouldCreatePlaneParallelToOpticalAxisAndProjectedAnchor()
|
||||
{
|
||||
Vector3 axisBase = new Vector3(0f, 0f, 0f);
|
||||
Vector3 axisDirection = Vector3.UnitX;
|
||||
Vector3 pickPoint = new Vector3(2f, 3f, 4f);
|
||||
|
||||
AssemblyInstallationReferenceResult result =
|
||||
AssemblyInstallationReferenceBuilder.Build(axisBase, axisDirection, pickPoint);
|
||||
|
||||
Assert.AreEqual(5f, result.OffsetDistance, 1e-4f);
|
||||
Assert.AreEqual(2f, result.AnchorPoint.X, 1e-4f);
|
||||
Assert.AreEqual(3f, result.AnchorPoint.Y, 1e-4f);
|
||||
Assert.AreEqual(4f, 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);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Build_WhenPickPointTooCloseToOpticalAxis_ShouldThrow()
|
||||
{
|
||||
Vector3 axisBase = new Vector3(0f, 0f, 0f);
|
||||
Vector3 axisDirection = Vector3.UnitX;
|
||||
Vector3 pickPoint = new Vector3(2f, 0f, 0f);
|
||||
|
||||
InvalidOperationException ex = Assert.ThrowsException<InvalidOperationException>(
|
||||
() => AssemblyInstallationReferenceBuilder.Build(axisBase, axisDirection, pickPoint));
|
||||
|
||||
StringAssert.Contains(ex.Message, "距离光轴过小");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -133,6 +133,11 @@ namespace NavisworksTransport
|
||||
/// </summary>
|
||||
AssemblyGuideLine,
|
||||
|
||||
/// <summary>
|
||||
/// 直线装配安装参考面样式(绿色半透明)
|
||||
/// </summary>
|
||||
AssemblyInstallationPlane,
|
||||
|
||||
/// <summary>
|
||||
/// 吊装路径样式(紫色)
|
||||
/// </summary>
|
||||
@ -338,6 +343,11 @@ namespace NavisworksTransport
|
||||
/// </summary>
|
||||
public List<ObjectSpaceMarker> ObjectSpaceMarkers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平面标记集合
|
||||
/// </summary>
|
||||
public List<PlaneMarker> PlaneMarkers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示控制点可视化(用户意图)
|
||||
/// </summary>
|
||||
@ -358,6 +368,7 @@ namespace NavisworksTransport
|
||||
PathLineMarkers = new List<LineMarker>();
|
||||
TangentMarkers = new List<SquareMarker>();
|
||||
ObjectSpaceMarkers = new List<ObjectSpaceMarker>();
|
||||
PlaneMarkers = new List<PlaneMarker>();
|
||||
LastUpdated = DateTime.Now;
|
||||
}
|
||||
|
||||
@ -633,6 +644,11 @@ namespace NavisworksTransport
|
||||
RenderPointMarker(graphics, pointMarker);
|
||||
}
|
||||
|
||||
foreach (var planeMarker in visualization.PlaneMarkers)
|
||||
{
|
||||
RenderPlaneMarker(graphics, planeMarker);
|
||||
}
|
||||
|
||||
// 渲染控制点连线(半透明)
|
||||
foreach (var controlLineMarker in visualization.ControlLineMarkers)
|
||||
{
|
||||
@ -802,6 +818,55 @@ namespace NavisworksTransport
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderRectanglePlane(
|
||||
string pathId,
|
||||
Point3D origin,
|
||||
Vector3D xVector,
|
||||
Vector3D yVector,
|
||||
RenderStyleName renderStyleName,
|
||||
bool filled = true)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pathId))
|
||||
{
|
||||
throw new ArgumentException("pathId 不能为空。", nameof(pathId));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var visualization = new PathVisualization
|
||||
{
|
||||
PathId = pathId,
|
||||
PathRoute = new PathRoute(pathId)
|
||||
{
|
||||
Id = pathId,
|
||||
Description = $"矩形平面可视化:{pathId}"
|
||||
}
|
||||
};
|
||||
|
||||
var renderStyle = GetRenderStyle(renderStyleName);
|
||||
visualization.PlaneMarkers.Add(new PlaneMarker
|
||||
{
|
||||
Origin = origin,
|
||||
XVector = xVector,
|
||||
YVector = yVector,
|
||||
Color = renderStyle.Color,
|
||||
Alpha = renderStyle.Alpha,
|
||||
Filled = filled
|
||||
});
|
||||
|
||||
lock (_lockObject)
|
||||
{
|
||||
_pathVisualizations[pathId] = visualization;
|
||||
}
|
||||
|
||||
RequestViewRefresh();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[平面渲染] 渲染矩形平面失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除网格可视化
|
||||
/// </summary>
|
||||
@ -960,6 +1025,7 @@ namespace NavisworksTransport
|
||||
visualization.PointMarkers.Clear();
|
||||
visualization.ControlLineMarkers.Clear(); // 确保没有控制点连线
|
||||
visualization.PathLineMarkers.Clear(); // 确保没有路径连线
|
||||
visualization.PlaneMarkers.Clear();
|
||||
|
||||
var points = visualization.PathRoute.Points;
|
||||
if (points.Count == 0) return;
|
||||
@ -2347,6 +2413,9 @@ namespace NavisworksTransport
|
||||
case RenderStyleName.AssemblyGuideLine:
|
||||
return new RenderStyle(Color.FromByteRGB(76, 175, 80), 0.85); // Material Green装配基准向量
|
||||
|
||||
case RenderStyleName.AssemblyInstallationPlane:
|
||||
return new RenderStyle(Color.FromByteRGB(76, 175, 80), 0.5); // Material Green安装参考面,50%透明
|
||||
|
||||
case RenderStyleName.HoistingLine:
|
||||
return new RenderStyle(Color.FromByteRGB(156, 39, 176), 0.8); // Material Purple吊装路径,20%透明
|
||||
|
||||
@ -3151,6 +3220,12 @@ namespace NavisworksTransport
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderPlaneMarker(Graphics graphics, PlaneMarker marker)
|
||||
{
|
||||
graphics.Color(marker.Color, marker.Alpha);
|
||||
graphics.Rectangle(marker.Origin, marker.XVector, marker.YVector, marker.Filled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 渲染连线标记(支持直线段和圆弧段)
|
||||
/// </summary>
|
||||
@ -3512,4 +3587,14 @@ namespace NavisworksTransport
|
||||
return $"CircleMarker[序号={SequenceNumber}, 类型={PointType}, 中心=({Center.X:F2},{Center.Y:F2},{Center.Z:F2}), 半径={Radius:F2}]";
|
||||
}
|
||||
}
|
||||
|
||||
public class PlaneMarker
|
||||
{
|
||||
public Point3D Origin { get; set; }
|
||||
public Vector3D XVector { get; set; }
|
||||
public Vector3D YVector { get; set; }
|
||||
public Color Color { get; set; }
|
||||
public double Alpha { get; set; }
|
||||
public bool Filled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,11 +141,19 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private bool _hasAssemblyTerminalObject;
|
||||
private bool _isSelectingAssemblyStartPoint;
|
||||
private bool _isSelectingAssemblyEndFacePoints;
|
||||
private bool _isSelectingAssemblyInstallationPoint;
|
||||
private bool _hasAssemblyEndFaceAnalysis;
|
||||
private bool _hasAssemblyInstallationReference;
|
||||
private ModelItem _assemblyTerminalObject;
|
||||
private Point3D _assemblyStartPoint;
|
||||
private Point3D _assemblyEndFaceCenterPoint;
|
||||
private Vector3 _assemblyEndFaceNormal;
|
||||
private Point3D _assemblyInstallationPickPoint;
|
||||
private Point3D _assemblyInstallationBaseAnchorPoint;
|
||||
private Point3D _assemblyInstallationAnchorPoint;
|
||||
private Vector3 _assemblyInstallationPlaneNormal;
|
||||
private Vector3 _assemblyInstallationPlaneSpanDirection;
|
||||
private double _assemblyInstallationOffsetDistanceInMeters;
|
||||
private readonly List<Point3D> _assemblyEndFaceSeedPoints = new List<Point3D>();
|
||||
private const string AssemblyAnchorMarkerPathId = "assembly_anchor_marker";
|
||||
private const string AssemblyCenterGuideLinePathId = "assembly_center_guide_line";
|
||||
@ -153,6 +161,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private const string AssemblyEndFaceSeedPathId = "assembly_end_face_seed_points";
|
||||
private const string AssemblyEndFaceCenterPathId = "assembly_end_face_center";
|
||||
private const string AssemblyEndFaceNormalPathId = "assembly_end_face_normal";
|
||||
private const string AssemblyInstallationPickPointPathId = "assembly_install_pick_point";
|
||||
private const string AssemblyInstallationAnchorPointPathId = "assembly_install_anchor_point";
|
||||
private const string AssemblyInstallationCenterLinePathId = "assembly_install_center_line";
|
||||
private const string AssemblyInstallationOffsetLinePathId = "assembly_install_offset_line";
|
||||
private const string AssemblyInstallationPlanePathId = "assembly_install_plane";
|
||||
private const double AssemblyInstallationPlanePaddingInMeters = 0.5;
|
||||
private const double AssemblyInstallationLineLengthScale = 1.2;
|
||||
|
||||
// 自动路径起点和终点的路径对象引用(用于正确的ID管理)
|
||||
private PathRoute _autoPathStartPointRoute = null;
|
||||
@ -375,6 +390,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
if (SetProperty(ref _assemblyAnchorVerticalOffsetInMeters, value) && HasAssemblyTerminalObject)
|
||||
{
|
||||
if (_hasAssemblyInstallationReference)
|
||||
{
|
||||
UpdateAssemblyInstallationAnchorFromVerticalOffset();
|
||||
}
|
||||
RefreshAssemblyTerminalObjectInfo();
|
||||
RenderAssemblyAnchorMarker();
|
||||
RefreshAssemblyReferenceRodIfNeeded();
|
||||
@ -969,6 +988,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
public ICommand CaptureAssemblyTerminalObjectCommand { get; private set; }
|
||||
public ICommand GenerateAssemblyReferenceRodCommand { get; private set; }
|
||||
public ICommand SelectAssemblyStartPointCommand { get; private set; }
|
||||
public ICommand SelectAssemblyInstallationPointCommand { get; private set; }
|
||||
public ICommand ClearAssemblyReferenceRodCommand { get; private set; }
|
||||
public ICommand AnalyzeAssemblyTerminalFaceCommand { get; private set; }
|
||||
|
||||
@ -1007,16 +1027,27 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
public bool CanExecuteSaveAsPath => SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0;
|
||||
public bool CanGenerateAssemblyReferenceRod => HasAssemblyTerminalObject &&
|
||||
_hasAssemblyInstallationReference &&
|
||||
AssemblyReferenceRodLengthInMeters > 0 &&
|
||||
AssemblyReferenceRodDiameterInMeters > 0;
|
||||
public bool CanSelectAssemblyStartPoint => HasAssemblyTerminalObject &&
|
||||
_pathPlanningManager != null &&
|
||||
AssemblyReferencePathManager.Instance.HasReferenceLine &&
|
||||
!IsSelectingAssemblyStartPoint;
|
||||
public bool CanSelectAssemblyInstallationPoint => HasAssemblyTerminalObject &&
|
||||
_pathPlanningManager != null &&
|
||||
!_isSelectingAssemblyStartPoint &&
|
||||
!_isSelectingAssemblyEndFacePoints &&
|
||||
!_isSelectingAssemblyInstallationPoint;
|
||||
public bool CanAnalyzeAssemblyTerminalFace => HasAssemblyTerminalObject &&
|
||||
_pathPlanningManager != null &&
|
||||
!IsSelectingAssemblyStartPoint &&
|
||||
!IsSelectingAssemblyEndFacePoints;
|
||||
!IsSelectingAssemblyEndFacePoints &&
|
||||
!_isSelectingAssemblyInstallationPoint;
|
||||
|
||||
public string AssemblyInstallationPointButtonText => _hasAssemblyInstallationReference
|
||||
? "重选安装点"
|
||||
: "选安装点";
|
||||
|
||||
public bool IsSelectingAssemblyEndFacePoints => _isSelectingAssemblyEndFacePoints;
|
||||
|
||||
@ -1301,6 +1332,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
CaptureAssemblyTerminalObjectCommand = new RelayCommand(async () => await ExecuteCaptureAssemblyTerminalObjectAsync());
|
||||
GenerateAssemblyReferenceRodCommand = new RelayCommand(async () => await ExecuteGenerateAssemblyReferenceRodAsync(), () => CanGenerateAssemblyReferenceRod);
|
||||
SelectAssemblyStartPointCommand = new RelayCommand(async () => await ExecuteSelectAssemblyStartPointAsync(), () => CanSelectAssemblyStartPoint);
|
||||
SelectAssemblyInstallationPointCommand = new RelayCommand(async () => await ExecuteSelectAssemblyInstallationPointAsync(), () => CanSelectAssemblyInstallationPoint);
|
||||
ClearAssemblyReferenceRodCommand = new RelayCommand(() => ExecuteClearAssemblyReferenceRod());
|
||||
AnalyzeAssemblyTerminalFaceCommand = new RelayCommand(async () => await ExecuteAnalyzeAssemblyTerminalFaceAsync(), () => CanAnalyzeAssemblyTerminalFace);
|
||||
}
|
||||
@ -1332,12 +1364,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
HasAssemblyTerminalObject = true;
|
||||
AssemblyStartPointText = "未选择";
|
||||
AssemblyTerminalObjectName = ModelItemAnalysisHelper.GetSafeDisplayName(selectedItem);
|
||||
InitializeAssemblyAnchorVerticalOffsetFromTerminalObject();
|
||||
ResetAssemblyEndFaceAnalysisState();
|
||||
ResetAssemblyInstallationReferenceState();
|
||||
RefreshAssemblyTerminalObjectInfo();
|
||||
RenderAssemblyAnchorMarker();
|
||||
ClearAssemblyAnchorMarker();
|
||||
ClearAssemblyEndFaceAnalysisVisuals();
|
||||
ClearAssemblyInstallationReferenceVisuals();
|
||||
OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyStartPoint));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyInstallationPoint));
|
||||
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFace));
|
||||
UpdateMainStatus($"已捕获终点箱体: {AssemblyTerminalObjectName}");
|
||||
LogManager.Info($"[直线装配] 已捕获终点箱体: {AssemblyTerminalObjectName}");
|
||||
@ -1450,13 +1485,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
|
||||
CleanupAssemblyReferenceSelection();
|
||||
CleanupAssemblyEndFaceSelection(clearVisuals: false);
|
||||
CleanupAssemblyInstallationSelection();
|
||||
ClearAssemblyEndFaceAnalysisVisuals();
|
||||
ResetAssemblyEndFaceAnalysisState();
|
||||
ClearAssemblyInstallationReferenceVisuals();
|
||||
ResetAssemblyInstallationReferenceState();
|
||||
_assemblyEndFaceSeedPoints.Clear();
|
||||
|
||||
_pathPlanningManager.DisableMouseHandling();
|
||||
_isSelectingAssemblyEndFacePoints = true;
|
||||
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFace));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyStartPoint));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyInstallationPoint));
|
||||
|
||||
PathClickToolPlugin.MouseClicked -= OnAssemblyEndFaceMouseClicked;
|
||||
PathClickToolPlugin.MouseClicked += OnAssemblyEndFaceMouseClicked;
|
||||
@ -1472,6 +1512,45 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}, "分析终端端面");
|
||||
}
|
||||
|
||||
private async Task ExecuteSelectAssemblyInstallationPointAsync()
|
||||
{
|
||||
await SafeExecuteAsync(() =>
|
||||
{
|
||||
if (_pathPlanningManager == null)
|
||||
{
|
||||
throw new InvalidOperationException("路径规划管理器未初始化,无法选择安装点。");
|
||||
}
|
||||
|
||||
if (_assemblyTerminalObject == null || !ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject))
|
||||
{
|
||||
throw new InvalidOperationException("终点箱体未设置或已失效,请先捕获终点箱体。");
|
||||
}
|
||||
|
||||
CleanupAssemblyReferenceSelection();
|
||||
CleanupAssemblyEndFaceSelection(clearVisuals: false);
|
||||
CleanupAssemblyInstallationSelection();
|
||||
ClearAssemblyInstallationReferenceVisuals();
|
||||
|
||||
_pathPlanningManager.DisableMouseHandling();
|
||||
_isSelectingAssemblyInstallationPoint = true;
|
||||
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFace));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyStartPoint));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyInstallationPoint));
|
||||
|
||||
PathClickToolPlugin.MouseClicked -= OnAssemblyInstallationMouseClicked;
|
||||
PathClickToolPlugin.MouseClicked += OnAssemblyInstallationMouseClicked;
|
||||
|
||||
if (!ForceReinitializeToolPlugin(subscribeToEvents: false))
|
||||
{
|
||||
CleanupAssemblyInstallationSelection();
|
||||
throw new InvalidOperationException("ToolPlugin 初始化失败,请重试。");
|
||||
}
|
||||
|
||||
UpdateMainStatus("请在终点箱体表面点击安装点,系统将按该点计算安装参考面和终点锚点。");
|
||||
LogManager.Info("[直线装配] 已进入安装点拾取模式");
|
||||
}, "选择安装点");
|
||||
}
|
||||
|
||||
private async void OnAssemblyReferenceMouseClicked(object sender, PickItemResult pickResult)
|
||||
{
|
||||
try
|
||||
@ -1544,6 +1623,35 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnAssemblyInstallationMouseClicked(object sender, PickItemResult pickResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_isSelectingAssemblyInstallationPoint || pickResult == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await SafeExecuteAsync(() =>
|
||||
{
|
||||
if (!IsPickOnAssemblyTerminalObject(pickResult))
|
||||
{
|
||||
UpdateMainStatus("请点击当前终点箱体表面,不要点到其他对象。");
|
||||
return;
|
||||
}
|
||||
|
||||
BuildAndRenderAssemblyInstallationReference(pickResult.Point);
|
||||
CleanupAssemblyInstallationSelection();
|
||||
}, "处理安装点拾取");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[直线装配] 安装点计算失败: {ex.Message}", ex);
|
||||
UpdateMainStatus($"安装点计算失败: {ex.Message}");
|
||||
CleanupAssemblyInstallationSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateAssemblyLinearRoute(Point3D startPoint)
|
||||
{
|
||||
Point3D endPoint = AssemblyReferencePathManager.Instance.ReferenceLineEnd;
|
||||
@ -1610,11 +1718,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
ClearAssemblyCenterGuideLine();
|
||||
ClearAssemblyReferenceLine();
|
||||
ClearAssemblyEndFaceAnalysisVisuals();
|
||||
ClearAssemblyInstallationReferenceVisuals();
|
||||
if (resetStartPointText)
|
||||
{
|
||||
AssemblyStartPointText = "未选择";
|
||||
}
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyStartPoint));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyInstallationPoint));
|
||||
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFace));
|
||||
if (!string.IsNullOrWhiteSpace(statusMessage))
|
||||
{
|
||||
@ -1634,6 +1744,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
throw new InvalidOperationException("终点箱体未设置或已失效,无法计算对接点");
|
||||
}
|
||||
|
||||
if (_hasAssemblyInstallationReference && _assemblyInstallationAnchorPoint != null)
|
||||
{
|
||||
return _assemblyInstallationAnchorPoint;
|
||||
}
|
||||
|
||||
HostCoordinateAdapter adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
|
||||
ProjectReferenceFrame projectFrame = CreateAssemblyProjectReferenceFrame(adapter);
|
||||
|
||||
@ -1654,6 +1769,39 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
return adapter.FromCanonicalPoint(canonicalAnchorPoint);
|
||||
}
|
||||
|
||||
private void UpdateAssemblyInstallationAnchorFromVerticalOffset()
|
||||
{
|
||||
if (!_hasAssemblyInstallationReference ||
|
||||
_assemblyInstallationBaseAnchorPoint == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double offset = UnitsConverter.ConvertFromMeters(_assemblyAnchorVerticalOffsetInMeters);
|
||||
_assemblyInstallationAnchorPoint = new Point3D(
|
||||
_assemblyInstallationBaseAnchorPoint.X + _assemblyInstallationPlaneNormal.X * (float)offset,
|
||||
_assemblyInstallationBaseAnchorPoint.Y + _assemblyInstallationPlaneNormal.Y * (float)offset,
|
||||
_assemblyInstallationBaseAnchorPoint.Z + _assemblyInstallationPlaneNormal.Z * (float)offset);
|
||||
|
||||
RenderAssemblyInstallationAnchorPoint(_assemblyInstallationAnchorPoint);
|
||||
RenderAssemblyInstallationPlane(_assemblyInstallationAnchorPoint, GetCurrentAssemblyOpticalAxisDirection(), _assemblyInstallationPlaneSpanDirection);
|
||||
}
|
||||
|
||||
private Vector3 GetCurrentAssemblyOpticalAxisDirection()
|
||||
{
|
||||
Point3D opticalAxisReferencePoint = GetAssemblyOpticalAxisReferencePoint();
|
||||
Point3D sphereCenterPoint = new Point3D(
|
||||
AssemblySphereCenterX,
|
||||
AssemblySphereCenterY,
|
||||
AssemblySphereCenterZ);
|
||||
|
||||
Vector3 opticalAxisDirection = new Vector3(
|
||||
(float)(opticalAxisReferencePoint.X - sphereCenterPoint.X),
|
||||
(float)(opticalAxisReferencePoint.Y - sphereCenterPoint.Y),
|
||||
(float)(opticalAxisReferencePoint.Z - sphereCenterPoint.Z));
|
||||
return Vector3.Normalize(opticalAxisDirection);
|
||||
}
|
||||
|
||||
private Point3D GetAssemblyOpticalAxisReferencePoint()
|
||||
{
|
||||
if (_hasAssemblyEndFaceAnalysis && _assemblyEndFaceCenterPoint != null)
|
||||
@ -1719,18 +1867,35 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
var bounds = _assemblyTerminalObject.BoundingBox();
|
||||
Point3D anchorPoint = GetAssemblyTerminalAnchorPoint();
|
||||
string anchorText = GetAssemblyAnchorText();
|
||||
string mountText = AssemblyMountMode == RailMountMode.OverRail ? "轨上安装" : "轨下安装";
|
||||
Point3D opticalAxisReferencePoint = GetAssemblyOpticalAxisReferencePoint();
|
||||
string opticalAxisText = _hasAssemblyEndFaceAnalysis
|
||||
? string.Format("端面中心=({0:F2}, {1:F2}, {2:F2})", opticalAxisReferencePoint.X, opticalAxisReferencePoint.Y, opticalAxisReferencePoint.Z)
|
||||
: string.Format("箱体中心=({0:F2}, {1:F2}, {2:F2})", opticalAxisReferencePoint.X, opticalAxisReferencePoint.Y, opticalAxisReferencePoint.Z);
|
||||
string anchorPointText = _hasAssemblyInstallationReference
|
||||
? string.Format("{0}点=({1:F2}, {2:F2}, {3:F2})",
|
||||
anchorText,
|
||||
_assemblyInstallationAnchorPoint.X,
|
||||
_assemblyInstallationAnchorPoint.Y,
|
||||
_assemblyInstallationAnchorPoint.Z)
|
||||
: string.Format("{0}点=未选择", anchorText);
|
||||
string installationText = _hasAssemblyInstallationReference
|
||||
? string.Format(
|
||||
"选定安装点=({0:F2}, {1:F2}, {2:F2}),安装点=({3:F2}, {4:F2}, {5:F2}),偏距={6:F3}m",
|
||||
_assemblyInstallationPickPoint.X,
|
||||
_assemblyInstallationPickPoint.Y,
|
||||
_assemblyInstallationPickPoint.Z,
|
||||
_assemblyInstallationAnchorPoint.X,
|
||||
_assemblyInstallationAnchorPoint.Y,
|
||||
_assemblyInstallationAnchorPoint.Z,
|
||||
_assemblyInstallationOffsetDistanceInMeters)
|
||||
: "安装点=未选择";
|
||||
|
||||
if (referenceStartPoint != null && referenceEndPoint != null)
|
||||
{
|
||||
AssemblyTerminalObjectInfo = string.Format(
|
||||
"中心=({0:F2}, {1:F2}, {2:F2}),尺寸=({3:F2}, {4:F2}, {5:F2}),{6},{7}点=({8:F2}, {9:F2}, {10:F2}),{11},垂直偏移={12:F3}m,辅助线外端=({13:F2}, {14:F2}, {15:F2})",
|
||||
"中心=({0:F2}, {1:F2}, {2:F2}),尺寸=({3:F2}, {4:F2}, {5:F2}),{6},{7},{8},{9},垂直偏移={10:F3}m,辅助线外端=({11:F2}, {12:F2}, {13:F2})",
|
||||
bounds.Center.X,
|
||||
bounds.Center.Y,
|
||||
bounds.Center.Z,
|
||||
@ -1738,11 +1903,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
bounds.Max.Y - bounds.Min.Y,
|
||||
bounds.Max.Z - bounds.Min.Z,
|
||||
mountText,
|
||||
anchorText,
|
||||
referenceEndPoint.X,
|
||||
referenceEndPoint.Y,
|
||||
referenceEndPoint.Z,
|
||||
anchorPointText,
|
||||
opticalAxisText,
|
||||
installationText,
|
||||
AssemblyAnchorVerticalOffsetInMeters,
|
||||
referenceStartPoint.X,
|
||||
referenceStartPoint.Y,
|
||||
@ -1751,7 +1914,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
AssemblyTerminalObjectInfo = string.Format(
|
||||
"中心=({0:F2}, {1:F2}, {2:F2}),尺寸=({3:F2}, {4:F2}, {5:F2}),{6},{7}点=({8:F2}, {9:F2}, {10:F2}),{11},垂直偏移={12:F3}m",
|
||||
"中心=({0:F2}, {1:F2}, {2:F2}),尺寸=({3:F2}, {4:F2}, {5:F2}),{6},{7},{8},{9},垂直偏移={10:F3}m",
|
||||
bounds.Center.X,
|
||||
bounds.Center.Y,
|
||||
bounds.Center.Z,
|
||||
@ -1759,11 +1922,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
bounds.Max.Y - bounds.Min.Y,
|
||||
bounds.Max.Z - bounds.Min.Z,
|
||||
mountText,
|
||||
anchorText,
|
||||
anchorPoint.X,
|
||||
anchorPoint.Y,
|
||||
anchorPoint.Z,
|
||||
anchorPointText,
|
||||
opticalAxisText,
|
||||
installationText,
|
||||
AssemblyAnchorVerticalOffsetInMeters);
|
||||
}
|
||||
|
||||
@ -2015,7 +2176,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
Id = AssemblyEndFaceCenterPathId,
|
||||
Description = "终端安装端面中心"
|
||||
};
|
||||
AddVisualizationPoint(markerRoute, centerPoint, "端面中心", PathPointType.EndPoint);
|
||||
AddVisualizationPoint(markerRoute, centerPoint, "端面中心", PathPointType.WayPoint);
|
||||
renderPlugin.RenderPointOnly(markerRoute);
|
||||
}
|
||||
|
||||
@ -2053,6 +2214,158 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
RenderStyleName.AssemblyGuideLine);
|
||||
}
|
||||
|
||||
private void BuildAndRenderAssemblyInstallationReference(Point3D pickPoint)
|
||||
{
|
||||
Point3D opticalAxisReferencePoint = GetAssemblyOpticalAxisReferencePoint();
|
||||
Point3D sphereCenterPoint = new Point3D(
|
||||
AssemblySphereCenterX,
|
||||
AssemblySphereCenterY,
|
||||
AssemblySphereCenterZ);
|
||||
|
||||
Vector3 opticalAxisDirection = new Vector3(
|
||||
(float)(opticalAxisReferencePoint.X - sphereCenterPoint.X),
|
||||
(float)(opticalAxisReferencePoint.Y - sphereCenterPoint.Y),
|
||||
(float)(opticalAxisReferencePoint.Z - sphereCenterPoint.Z));
|
||||
|
||||
AssemblyInstallationReferenceResult result = AssemblyInstallationReferenceBuilder.Build(
|
||||
new Vector3((float)opticalAxisReferencePoint.X, (float)opticalAxisReferencePoint.Y, (float)opticalAxisReferencePoint.Z),
|
||||
opticalAxisDirection,
|
||||
new Vector3((float)pickPoint.X, (float)pickPoint.Y, (float)pickPoint.Z));
|
||||
|
||||
_hasAssemblyInstallationReference = true;
|
||||
_assemblyInstallationPickPoint = pickPoint;
|
||||
_assemblyInstallationBaseAnchorPoint = AssemblyEndFaceAnalyzer.ToPoint3D(result.AnchorPoint);
|
||||
_assemblyInstallationPlaneNormal = result.PlaneNormal;
|
||||
_assemblyInstallationPlaneSpanDirection = result.PlaneSpanDirection;
|
||||
_assemblyInstallationOffsetDistanceInMeters = UnitsConverter.ConvertToMeters(result.OffsetDistance);
|
||||
_assemblyAnchorVerticalOffsetInMeters = DefaultAssemblyAnchorVerticalOffsetInMeters;
|
||||
OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters));
|
||||
UpdateAssemblyInstallationAnchorFromVerticalOffset();
|
||||
|
||||
RenderAssemblyInstallationPickPoint(_assemblyInstallationPickPoint);
|
||||
RenderAssemblyInstallationCenterLine(AssemblyEndFaceAnalyzer.ToPoint3D(result.InstallLineBasePoint), result.OpticalAxisDirection);
|
||||
|
||||
RefreshAssemblyTerminalObjectInfo();
|
||||
RefreshAssemblyReferenceRodIfNeeded();
|
||||
UpdateMainStatus(
|
||||
$"安装参考已计算:安装点=({_assemblyInstallationAnchorPoint.X:F2}, {_assemblyInstallationAnchorPoint.Y:F2}, {_assemblyInstallationAnchorPoint.Z:F2}),偏距={_assemblyInstallationOffsetDistanceInMeters:F3}m");
|
||||
LogManager.Info(
|
||||
$"[直线装配] 安装参考已计算: 选定安装点=({pickPoint.X:F3}, {pickPoint.Y:F3}, {pickPoint.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})");
|
||||
OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod));
|
||||
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
|
||||
}
|
||||
|
||||
private void RenderAssemblyInstallationPickPoint(Point3D pickPoint)
|
||||
{
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
if (renderPlugin == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
renderPlugin.RemovePath(AssemblyInstallationPickPointPathId);
|
||||
var markerRoute = new PathRoute("安装点")
|
||||
{
|
||||
Id = AssemblyInstallationPickPointPathId,
|
||||
Description = "终端安装点"
|
||||
};
|
||||
AddVisualizationPoint(markerRoute, pickPoint, "安装点", PathPointType.WayPoint);
|
||||
renderPlugin.RenderPointOnly(markerRoute);
|
||||
}
|
||||
|
||||
private void RenderAssemblyInstallationAnchorPoint(Point3D anchorPoint)
|
||||
{
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
if (renderPlugin == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
renderPlugin.RemovePath(AssemblyInstallationAnchorPointPathId);
|
||||
var markerRoute = new PathRoute("安装点")
|
||||
{
|
||||
Id = AssemblyInstallationAnchorPointPathId,
|
||||
Description = "终端安装点"
|
||||
};
|
||||
AddVisualizationPoint(markerRoute, anchorPoint, "安装点", PathPointType.WayPoint);
|
||||
renderPlugin.RenderPointOnly(markerRoute);
|
||||
}
|
||||
|
||||
private void RenderAssemblyInstallationCenterLine(Point3D lineBasePoint, Vector3 axisDirection)
|
||||
{
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
if (renderPlugin == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
renderPlugin.ClearRailBaseline(AssemblyInstallationCenterLinePathId);
|
||||
double halfLength = GetAssemblyInstallationPlaneSideLength() * AssemblyInstallationLineLengthScale / 2.0;
|
||||
Point3D startPoint = new Point3D(
|
||||
lineBasePoint.X - axisDirection.X * (float)halfLength,
|
||||
lineBasePoint.Y - axisDirection.Y * (float)halfLength,
|
||||
lineBasePoint.Z - axisDirection.Z * (float)halfLength);
|
||||
Point3D endPoint = new Point3D(
|
||||
lineBasePoint.X + axisDirection.X * (float)halfLength,
|
||||
lineBasePoint.Y + axisDirection.Y * (float)halfLength,
|
||||
lineBasePoint.Z + axisDirection.Z * (float)halfLength);
|
||||
renderPlugin.RenderRailBaseline(
|
||||
AssemblyInstallationCenterLinePathId,
|
||||
new List<Point3D> { startPoint, endPoint },
|
||||
RenderStyleName.AssemblyGuideLine);
|
||||
}
|
||||
|
||||
private void RenderAssemblyInstallationPlane(Point3D planeCenter, Vector3 axisDirection, Vector3 planeSpanDirection)
|
||||
{
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
if (renderPlugin == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double sideLength = GetAssemblyInstallationPlaneSideLength();
|
||||
double halfLength = sideLength / 2.0;
|
||||
double thickness = UnitsConverter.ConvertFromMeters(0.01);
|
||||
|
||||
Vector3D xVector = new Vector3D(
|
||||
axisDirection.X * (float)sideLength,
|
||||
axisDirection.Y * (float)sideLength,
|
||||
axisDirection.Z * (float)sideLength);
|
||||
Vector3D yVector = new Vector3D(
|
||||
planeSpanDirection.X * (float)sideLength,
|
||||
planeSpanDirection.Y * (float)sideLength,
|
||||
planeSpanDirection.Z * (float)sideLength);
|
||||
Point3D origin = new Point3D(
|
||||
planeCenter.X - axisDirection.X * (float)halfLength - planeSpanDirection.X * (float)halfLength + _assemblyInstallationPlaneNormal.X * thickness,
|
||||
planeCenter.Y - axisDirection.Y * (float)halfLength - planeSpanDirection.Y * (float)halfLength + _assemblyInstallationPlaneNormal.Y * thickness,
|
||||
planeCenter.Z - axisDirection.Z * (float)halfLength - planeSpanDirection.Z * (float)halfLength + _assemblyInstallationPlaneNormal.Z * thickness);
|
||||
|
||||
renderPlugin.RemovePath(AssemblyInstallationPlanePathId);
|
||||
renderPlugin.RenderRectanglePlane(
|
||||
AssemblyInstallationPlanePathId,
|
||||
origin,
|
||||
xVector,
|
||||
yVector,
|
||||
RenderStyleName.AssemblyInstallationPlane,
|
||||
filled: true);
|
||||
}
|
||||
|
||||
private double GetAssemblyInstallationPlaneSideLength()
|
||||
{
|
||||
if (_assemblyTerminalObject == null || !ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject))
|
||||
{
|
||||
return UnitsConverter.ConvertFromMeters(1.0);
|
||||
}
|
||||
|
||||
BoundingBox3D bounds = _assemblyTerminalObject.BoundingBox();
|
||||
double maxSize = Math.Max(
|
||||
bounds.Max.X - bounds.Min.X,
|
||||
Math.Max(bounds.Max.Y - bounds.Min.Y, bounds.Max.Z - bounds.Min.Z));
|
||||
return maxSize + UnitsConverter.ConvertFromMeters(AssemblyInstallationPlanePaddingInMeters) * 2.0;
|
||||
}
|
||||
|
||||
private ProjectReferenceFrame CreateAssemblyProjectReferenceFrame(HostCoordinateAdapter adapter)
|
||||
{
|
||||
if (adapter == null)
|
||||
@ -2116,11 +2429,45 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
renderPlugin.RemovePath(AssemblyEndFaceSeedPathId);
|
||||
renderPlugin.RemovePath(AssemblyEndFaceCenterPathId);
|
||||
renderPlugin.ClearRailBaseline(AssemblyEndFaceNormalPathId);
|
||||
}
|
||||
|
||||
private void ResetAssemblyEndFaceAnalysisState()
|
||||
{
|
||||
_hasAssemblyEndFaceAnalysis = false;
|
||||
_assemblyEndFaceCenterPoint = null;
|
||||
_assemblyEndFaceNormal = default(Vector3);
|
||||
}
|
||||
|
||||
private void ClearAssemblyInstallationReferenceVisuals()
|
||||
{
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
if (renderPlugin == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
renderPlugin.RemovePath(AssemblyInstallationPickPointPathId);
|
||||
renderPlugin.RemovePath(AssemblyInstallationAnchorPointPathId);
|
||||
renderPlugin.ClearRailBaseline(AssemblyInstallationCenterLinePathId);
|
||||
renderPlugin.ClearRailBaseline(AssemblyInstallationOffsetLinePathId);
|
||||
renderPlugin.RemovePath(AssemblyInstallationPlanePathId);
|
||||
}
|
||||
|
||||
private void ResetAssemblyInstallationReferenceState()
|
||||
{
|
||||
_hasAssemblyInstallationReference = false;
|
||||
_assemblyInstallationPickPoint = null;
|
||||
_assemblyInstallationBaseAnchorPoint = null;
|
||||
_assemblyInstallationAnchorPoint = null;
|
||||
_assemblyInstallationPlaneNormal = default(Vector3);
|
||||
_assemblyInstallationPlaneSpanDirection = default(Vector3);
|
||||
_assemblyInstallationOffsetDistanceInMeters = 0.0;
|
||||
_assemblyAnchorVerticalOffsetInMeters = DefaultAssemblyAnchorVerticalOffsetInMeters;
|
||||
OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters));
|
||||
OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod));
|
||||
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
|
||||
}
|
||||
|
||||
private void CleanupAssemblyReferenceSelection()
|
||||
{
|
||||
try
|
||||
@ -2137,6 +2484,25 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupAssemblyInstallationSelection()
|
||||
{
|
||||
try
|
||||
{
|
||||
PathClickToolPlugin.MouseClicked -= OnAssemblyInstallationMouseClicked;
|
||||
_isSelectingAssemblyInstallationPoint = false;
|
||||
_pathPlanningManager?.EnableMouseHandling();
|
||||
_pathPlanningManager?.StopClickTool();
|
||||
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFace));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyStartPoint));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyInstallationPoint));
|
||||
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[直线装配] 清理参考安装点拾取状态失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupAssemblyEndFaceSelection(bool clearVisuals)
|
||||
{
|
||||
try
|
||||
@ -2149,9 +2515,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
_assemblyEndFaceSeedPoints.Clear();
|
||||
ClearAssemblyEndFaceAnalysisVisuals();
|
||||
ResetAssemblyEndFaceAnalysisState();
|
||||
}
|
||||
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFace));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyStartPoint));
|
||||
OnPropertyChanged(nameof(CanSelectAssemblyInstallationPoint));
|
||||
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -2208,9 +2577,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
RenderAssemblyEndFaceNormal(centerPoint, result.Normal);
|
||||
RefreshAssemblyTerminalObjectInfo();
|
||||
RefreshAssemblyReferenceRodIfNeeded();
|
||||
|
||||
AssemblyTerminalObjectInfo =
|
||||
$"{AssemblyTerminalObjectInfo} | 端面中心=({centerPoint.X:F2}, {centerPoint.Y:F2}, {centerPoint.Z:F2}),候选三角形={result.CandidateTriangleCount},偏差={result.MaxPlaneDeviation:F6}";
|
||||
UpdateMainStatus($"端面分析完成:中心=({centerPoint.X:F2}, {centerPoint.Y:F2}, {centerPoint.Z:F2}),候选三角形={result.CandidateTriangleCount}");
|
||||
LogManager.Info(
|
||||
$"[直线装配] 端面分析完成: 中心=({centerPoint.X:F3}, {centerPoint.Y:F3}, {centerPoint.Z:F3}), " +
|
||||
|
||||
@ -263,6 +263,117 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="0" Margin="0,10,0,0" Padding="10">
|
||||
<StackPanel>
|
||||
<Label Content="终端安装仿真" Style="{StaticResource SectionHeaderStyle}"/>
|
||||
<Grid Margin="0,5,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="安装方式:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
Margin="6,0,8,0"
|
||||
ItemsSource="{Binding RailMountModeOptions}"
|
||||
SelectedValue="{Binding AssemblyMountMode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ToolTip="选择直线装配路径使用轨上安装还是轨下安装"/>
|
||||
<Label Grid.Column="2"
|
||||
Content="垂直偏移:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel Grid.Column="3"
|
||||
Orientation="Horizontal"
|
||||
VerticalAlignment="Center"
|
||||
Margin="6,0,0,0">
|
||||
<TextBox Text="{Binding AssemblyAnchorVerticalOffsetInMeters, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Content="米"
|
||||
Style="{StaticResource UnitLabelStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="球心:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<StackPanel Grid.Column="1"
|
||||
Orientation="Horizontal"
|
||||
VerticalAlignment="Center"
|
||||
Margin="6,0,8,0">
|
||||
<TextBox Text="{Binding AssemblySphereCenterX, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Content="X" Style="{StaticResource UnitLabelStyle}"/>
|
||||
<TextBox Text="{Binding AssemblySphereCenterY, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Content="Y" Style="{StaticResource UnitLabelStyle}"/>
|
||||
<TextBox Text="{Binding AssemblySphereCenterZ, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Content="Z" Style="{StaticResource UnitLabelStyle}"/>
|
||||
</StackPanel>
|
||||
<Label Grid.Column="2"
|
||||
Content="终点箱体:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Column="3"
|
||||
Margin="6,0,0,0"
|
||||
Text="{Binding AssemblyTerminalObjectName}"
|
||||
Style="{StaticResource ReadOnlyTextBoxStyle}"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="装配起点:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Column="1"
|
||||
Margin="6,0,0,0"
|
||||
Text="{Binding AssemblyStartPointText}"
|
||||
Style="{StaticResource ReadOnlyTextBoxStyle}"/>
|
||||
</Grid>
|
||||
<WrapPanel Margin="0,8,0,0">
|
||||
<Button Content="捕获箱体"
|
||||
Command="{Binding CaptureAssemblyTerminalObjectCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"/>
|
||||
<Button Content="找端面"
|
||||
Command="{Binding AnalyzeAssemblyTerminalFaceCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
IsEnabled="{Binding CanAnalyzeAssemblyTerminalFace}"/>
|
||||
<Button Content="{Binding AssemblyInstallationPointButtonText}"
|
||||
Command="{Binding SelectAssemblyInstallationPointCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
IsEnabled="{Binding CanSelectAssemblyInstallationPoint}"/>
|
||||
<Button Content="生成辅助线"
|
||||
Command="{Binding GenerateAssemblyReferenceRodCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
IsEnabled="{Binding CanGenerateAssemblyReferenceRod}"/>
|
||||
<Button Content="取起点"
|
||||
Command="{Binding SelectAssemblyStartPointCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
IsEnabled="{Binding CanSelectAssemblyStartPoint}"/>
|
||||
<Button Content="隐藏辅助线"
|
||||
Command="{Binding ClearAssemblyReferenceRodCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"/>
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
@ -300,211 +411,6 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
|
||||
Foreground="#FF2B579A"
|
||||
Margin="0,5,0,0"/>
|
||||
|
||||
<Border Margin="0,8,0,0"
|
||||
Padding="8"
|
||||
BorderBrush="#FFD4E7FF"
|
||||
BorderThickness="1">
|
||||
<StackPanel>
|
||||
<TextBlock Text="终端安装仿真"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#FF2B579A"/>
|
||||
<TextBlock Text="推荐流程:先选择终点处已安装箱体,再生成一条可点击的辅助线。"
|
||||
Style="{StaticResource StatusTextStyle}"
|
||||
Margin="0,4,0,0"/>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="安装方式:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
Margin="6,0,0,0"
|
||||
ItemsSource="{Binding RailMountModeOptions}"
|
||||
SelectedValue="{Binding AssemblyMountMode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ToolTip="选择直线装配路径使用轨上安装还是轨下安装"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="垂直偏移:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Column="1"
|
||||
Text="{Binding AssemblyAnchorVerticalOffsetInMeters, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Column="2"
|
||||
Content="米"
|
||||
Style="{StaticResource UnitLabelStyle}"/>
|
||||
<TextBlock Grid.Column="3"
|
||||
Margin="8,0,0,0"
|
||||
Text="表示箱体中心到真实安装点沿局部上下方向的距离"
|
||||
Style="{StaticResource StatusTextStyle}"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="球心坐标:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Column="1"
|
||||
Text="{Binding AssemblySphereCenterX, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Column="2"
|
||||
Content="X"
|
||||
Style="{StaticResource UnitLabelStyle}"/>
|
||||
<TextBox Grid.Column="3"
|
||||
Text="{Binding AssemblySphereCenterY, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Column="4"
|
||||
Content="Y"
|
||||
Style="{StaticResource UnitLabelStyle}"/>
|
||||
<TextBox Grid.Column="5"
|
||||
Text="{Binding AssemblySphereCenterZ, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Column="6"
|
||||
Content="Z"
|
||||
Style="{StaticResource UnitLabelStyle}"/>
|
||||
<TextBlock Grid.Column="7"
|
||||
Margin="8,0,0,0"
|
||||
Text="使用 Navisworks 当前模型坐标,默认 0,0,0"
|
||||
Style="{StaticResource StatusTextStyle}"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="终点箱体:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Column="1"
|
||||
Margin="6,0,0,0"
|
||||
Text="{Binding AssemblyTerminalObjectName}"
|
||||
Style="{StaticResource ReadOnlyTextBoxStyle}"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="装配起点:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Column="1"
|
||||
Margin="6,0,0,0"
|
||||
Text="{Binding AssemblyStartPointText}"
|
||||
Style="{StaticResource ReadOnlyTextBoxStyle}"/>
|
||||
</Grid>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="辅助线长度:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Column="1"
|
||||
Text="{Binding AssemblyReferenceRodLengthInMeters, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Column="2"
|
||||
Content="米"
|
||||
Style="{StaticResource UnitLabelStyle}"/>
|
||||
<Label Grid.Column="3"
|
||||
Content="直径:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<TextBox Grid.Column="4"
|
||||
Text="{Binding AssemblyReferenceRodDiameterInMeters, StringFormat=0.0###}"
|
||||
Style="{StaticResource ParameterInputStyle}"/>
|
||||
<Label Grid.Column="5"
|
||||
Content="米"
|
||||
Style="{StaticResource UnitLabelStyle}"/>
|
||||
</Grid>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<Button Content="捕获终点箱体"
|
||||
Command="{Binding CaptureAssemblyTerminalObjectCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"/>
|
||||
<Button Content="生成辅助线"
|
||||
Command="{Binding GenerateAssemblyReferenceRodCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
IsEnabled="{Binding CanGenerateAssemblyReferenceRod}"/>
|
||||
<Button Content="取起点并生成路径"
|
||||
Command="{Binding SelectAssemblyStartPointCommand}"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
IsEnabled="{Binding CanSelectAssemblyStartPoint}"/>
|
||||
<Button Content="分析端面(3点)"
|
||||
Command="{Binding AnalyzeAssemblyTerminalFaceCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
IsEnabled="{Binding CanAnalyzeAssemblyTerminalFace}"/>
|
||||
<Button Content="隐藏辅助线"
|
||||
Command="{Binding ClearAssemblyReferenceRodCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Margin="0,8,0,0"
|
||||
Padding="8"
|
||||
BorderBrush="#FFD4E7FF"
|
||||
BorderThickness="1"
|
||||
Visibility="{Binding IsRailRouteSelected, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Rail 路径构型"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#FF2B579A"/>
|
||||
<TextBlock Text="用于传统空轨路径或已生成的 Rail 直线装配路径。"
|
||||
Style="{StaticResource StatusTextStyle}"
|
||||
Margin="0,4,0,0"/>
|
||||
<Grid Margin="0,6,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Grid.Column="0"
|
||||
Content="安装方式:"
|
||||
Style="{StaticResource ParameterLabelStyle}"
|
||||
VerticalAlignment="Center"/>
|
||||
<ComboBox Grid.Column="1"
|
||||
Margin="6,0,0,0"
|
||||
ItemsSource="{Binding RailMountModeOptions}"
|
||||
SelectedValue="{Binding SelectedRailMountMode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="DisplayName"
|
||||
ToolTip="选择安装头位于双轨上方还是下方"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 路径点列表标题栏和工具按钮 -->
|
||||
<Grid Margin="0,5,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
|
||||
75
src/Utils/Assembly/AssemblyInstallationReferenceBuilder.cs
Normal file
75
src/Utils/Assembly/AssemblyInstallationReferenceBuilder.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace NavisworksTransport.Utils.GeometryAnalysis
|
||||
{
|
||||
public sealed class AssemblyInstallationReferenceResult
|
||||
{
|
||||
public Vector3 OpticalAxisBasePoint { get; set; }
|
||||
public Vector3 OpticalAxisDirection { get; set; }
|
||||
public Vector3 PickPoint { get; set; }
|
||||
public Vector3 PlaneNormal { get; set; }
|
||||
public Vector3 PlaneSpanDirection { get; set; }
|
||||
public float OffsetDistance { get; set; }
|
||||
public Vector3 InstallLineBasePoint { get; set; }
|
||||
public Vector3 AnchorPoint { get; set; }
|
||||
}
|
||||
|
||||
public static class AssemblyInstallationReferenceBuilder
|
||||
{
|
||||
private const float MinimumOffsetDistance = 1e-4f;
|
||||
|
||||
public static AssemblyInstallationReferenceResult Build(
|
||||
Vector3 opticalAxisBasePoint,
|
||||
Vector3 opticalAxisDirection,
|
||||
Vector3 pickPoint)
|
||||
{
|
||||
float axisLength = opticalAxisDirection.Length();
|
||||
if (axisLength < 1e-6f)
|
||||
{
|
||||
throw new InvalidOperationException("光轴方向长度过小,无法计算安装参考。");
|
||||
}
|
||||
|
||||
Vector3 axisDir = opticalAxisDirection / axisLength;
|
||||
Vector3 axisProjection = ProjectPointToLine(pickPoint, opticalAxisBasePoint, axisDir);
|
||||
Vector3 rawOffset = pickPoint - axisProjection;
|
||||
float offsetDistance = rawOffset.Length();
|
||||
if (offsetDistance < MinimumOffsetDistance)
|
||||
{
|
||||
throw new InvalidOperationException("参考安装点距离光轴过小,无法确定安装参考面,请重新选择。");
|
||||
}
|
||||
|
||||
Vector3 planeNormal = rawOffset / offsetDistance;
|
||||
Vector3 planeSpanDirection = Vector3.Cross(axisDir, planeNormal);
|
||||
float spanLength = planeSpanDirection.Length();
|
||||
if (spanLength < 1e-6f)
|
||||
{
|
||||
throw new InvalidOperationException("安装参考面横向方向计算失败,请重新选择参考安装点。");
|
||||
}
|
||||
|
||||
planeSpanDirection /= spanLength;
|
||||
|
||||
Vector3 installLineBasePoint = opticalAxisBasePoint + planeNormal * offsetDistance;
|
||||
Vector3 anchorPoint = ProjectPointToLine(pickPoint, installLineBasePoint, axisDir);
|
||||
|
||||
return new AssemblyInstallationReferenceResult
|
||||
{
|
||||
OpticalAxisBasePoint = opticalAxisBasePoint,
|
||||
OpticalAxisDirection = axisDir,
|
||||
PickPoint = pickPoint,
|
||||
PlaneNormal = planeNormal,
|
||||
PlaneSpanDirection = planeSpanDirection,
|
||||
OffsetDistance = offsetDistance,
|
||||
InstallLineBasePoint = installLineBasePoint,
|
||||
AnchorPoint = anchorPoint
|
||||
};
|
||||
}
|
||||
|
||||
private static Vector3 ProjectPointToLine(Vector3 point, Vector3 linePoint, Vector3 lineDirection)
|
||||
{
|
||||
Vector3 pointVector = point - linePoint;
|
||||
float projectionLength = Vector3.Dot(pointVector, lineDirection);
|
||||
return linePoint + lineDirection * projectionLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,5 +104,6 @@ namespace NavisworksTransport.Utils.CoordinateSystem
|
||||
rotation = convention.CreateQuaternion(forward, up);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user