diff --git a/resources/unit_cylinder.nwc b/resources/unit_cylinder.nwc index 540b4e6..8fbca10 100644 Binary files a/resources/unit_cylinder.nwc and b/resources/unit_cylinder.nwc differ diff --git a/resources/unit_cylinder.obj b/resources/unit_cylinder.obj index f920599..3b4e1ca 100644 --- a/resources/unit_cylinder.obj +++ b/resources/unit_cylinder.obj @@ -1,58 +1,104 @@ # unit cylinder for assembly reference rod -# dimensions: length 0.01m along +X, diameter 0.01m +# dimensions: length 1.0 along +X, diameter 1.0 # centered at origin +# when Navisworks imports OBJ as centimeters, generated NWC becomes 0.01m base size o unit_cylinder -v -0.005000 0.000000 0.000000 -v -0.005000 0.005000 0.000000 -v -0.005000 0.004330 0.002500 -v -0.005000 0.002500 0.004330 -v -0.005000 0.000000 0.005000 -v -0.005000 -0.002500 0.004330 -v -0.005000 -0.004330 0.002500 -v -0.005000 -0.005000 0.000000 -v -0.005000 -0.004330 -0.002500 -v -0.005000 -0.002500 -0.004330 -v -0.005000 0.000000 -0.005000 -v -0.005000 0.002500 -0.004330 -v -0.005000 0.004330 -0.002500 -v 0.005000 0.000000 0.000000 -v 0.005000 0.005000 0.000000 -v 0.005000 0.004330 0.002500 -v 0.005000 0.002500 0.004330 -v 0.005000 0.000000 0.005000 -v 0.005000 -0.002500 0.004330 -v 0.005000 -0.004330 0.002500 -v 0.005000 -0.005000 0.000000 -v 0.005000 -0.004330 -0.002500 -v 0.005000 -0.002500 -0.004330 -v 0.005000 0.000000 -0.005000 -v 0.005000 0.002500 -0.004330 -v 0.005000 0.004330 -0.002500 -f 2 15 16 -f 2 16 3 -f 3 16 17 -f 3 17 4 -f 4 17 18 -f 4 18 5 -f 5 18 19 -f 5 19 6 -f 6 19 20 -f 6 20 7 -f 7 20 21 -f 7 21 8 -f 8 21 22 -f 8 22 9 -f 9 22 23 -f 9 23 10 -f 10 23 24 -f 10 24 11 -f 11 24 25 -f 11 25 12 -f 12 25 26 -f 12 26 13 -f 13 26 15 -f 13 15 2 -f 1 3 2 +v -0.500000 0.000000 0.000000 +v 0.500000 0.000000 0.000000 +v -0.500000 0.500000 0.000000 +v -0.500000 0.482963 0.129410 +v -0.500000 0.433013 0.250000 +v -0.500000 0.353553 0.353553 +v -0.500000 0.250000 0.433013 +v -0.500000 0.129410 0.482963 +v -0.500000 0.000000 0.500000 +v -0.500000 -0.129410 0.482963 +v -0.500000 -0.250000 0.433013 +v -0.500000 -0.353553 0.353553 +v -0.500000 -0.433013 0.250000 +v -0.500000 -0.482963 0.129410 +v -0.500000 -0.500000 0.000000 +v -0.500000 -0.482963 -0.129410 +v -0.500000 -0.433013 -0.250000 +v -0.500000 -0.353553 -0.353553 +v -0.500000 -0.250000 -0.433013 +v -0.500000 -0.129410 -0.482963 +v -0.500000 0.000000 -0.500000 +v -0.500000 0.129410 -0.482963 +v -0.500000 0.250000 -0.433013 +v -0.500000 0.353553 -0.353553 +v -0.500000 0.433013 -0.250000 +v -0.500000 0.482963 -0.129410 +v 0.500000 0.500000 0.000000 +v 0.500000 0.482963 0.129410 +v 0.500000 0.433013 0.250000 +v 0.500000 0.353553 0.353553 +v 0.500000 0.250000 0.433013 +v 0.500000 0.129410 0.482963 +v 0.500000 0.000000 0.500000 +v 0.500000 -0.129410 0.482963 +v 0.500000 -0.250000 0.433013 +v 0.500000 -0.353553 0.353553 +v 0.500000 -0.433013 0.250000 +v 0.500000 -0.482963 0.129410 +v 0.500000 -0.500000 0.000000 +v 0.500000 -0.482963 -0.129410 +v 0.500000 -0.433013 -0.250000 +v 0.500000 -0.353553 -0.353553 +v 0.500000 -0.250000 -0.433013 +v 0.500000 -0.129410 -0.482963 +v 0.500000 0.000000 -0.500000 +v 0.500000 0.129410 -0.482963 +v 0.500000 0.250000 -0.433013 +v 0.500000 0.353553 -0.353553 +v 0.500000 0.433013 -0.250000 +v 0.500000 0.482963 -0.129410 +f 3 26 27 +f 3 27 4 +f 4 27 28 +f 4 28 5 +f 5 28 29 +f 5 29 6 +f 6 29 30 +f 6 30 7 +f 7 30 31 +f 7 31 8 +f 8 31 32 +f 8 32 9 +f 9 32 33 +f 9 33 10 +f 10 33 34 +f 10 34 11 +f 11 34 35 +f 11 35 12 +f 12 35 36 +f 12 36 13 +f 13 36 37 +f 13 37 14 +f 14 37 38 +f 14 38 15 +f 15 38 39 +f 15 39 16 +f 16 39 40 +f 16 40 17 +f 17 40 41 +f 17 41 18 +f 18 41 42 +f 18 42 19 +f 19 42 43 +f 19 43 20 +f 20 43 44 +f 20 44 21 +f 21 44 45 +f 21 45 22 +f 22 45 46 +f 22 46 23 +f 23 46 47 +f 23 47 24 +f 24 47 48 +f 24 48 25 +f 25 48 49 +f 25 49 26 f 1 4 3 f 1 5 4 f 1 6 5 @@ -63,16 +109,41 @@ f 1 10 9 f 1 11 10 f 1 12 11 f 1 13 12 -f 1 2 13 -f 14 15 16 -f 14 16 17 -f 14 17 18 -f 14 18 19 -f 14 19 20 -f 14 20 21 -f 14 21 22 -f 14 22 23 -f 14 23 24 -f 14 24 25 -f 14 25 26 -f 14 26 15 +f 1 14 13 +f 1 15 14 +f 1 16 15 +f 1 17 16 +f 1 18 17 +f 1 19 18 +f 1 20 19 +f 1 21 20 +f 1 22 21 +f 1 23 22 +f 1 24 23 +f 1 25 24 +f 1 26 25 +f 1 3 26 +f 2 27 28 +f 2 28 29 +f 2 29 30 +f 2 30 31 +f 2 31 32 +f 2 32 33 +f 2 33 34 +f 2 34 35 +f 2 35 36 +f 2 36 37 +f 2 37 38 +f 2 38 39 +f 2 39 40 +f 2 40 41 +f 2 41 42 +f 2 42 43 +f 2 43 44 +f 2 44 45 +f 2 45 46 +f 2 46 47 +f 2 47 48 +f 2 48 49 +f 2 49 26 +f 2 26 27 diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index 37eb74a..240c311 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -122,10 +122,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels private ObservableCollection> _railPayloadAnchorModeOptions; private const double DefaultAssemblyReferenceRodLengthInMeters = 20.0; private static readonly double DefaultAssemblyReferenceRodDiameterInMeters = CalculateDefaultAssemblyReferenceRodDiameterInMeters(); + private const double DefaultAssemblyAnchorVerticalOffsetInMeters = 0.0; private string _assemblyTerminalObjectName = "未选择"; private string _assemblyTerminalObjectInfo = "请选择终点处已安装箱体"; private double _assemblyReferenceRodLengthInMeters = DefaultAssemblyReferenceRodLengthInMeters; private double _assemblyReferenceRodDiameterInMeters = DefaultAssemblyReferenceRodDiameterInMeters; + private double _assemblyAnchorVerticalOffsetInMeters = DefaultAssemblyAnchorVerticalOffsetInMeters; private string _assemblyStartPointText = "未选择"; private RailMountMode _assemblyMountMode = RailMountMode.UnderRail; private RailPayloadAnchorMode _assemblyPayloadAnchorMode = RailPayloadAnchorMode.TopCenter; @@ -374,6 +376,20 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + public double AssemblyAnchorVerticalOffsetInMeters + { + get => _assemblyAnchorVerticalOffsetInMeters; + set + { + if (SetProperty(ref _assemblyAnchorVerticalOffsetInMeters, value) && HasAssemblyTerminalObject) + { + RefreshAssemblyTerminalObjectInfo(); + RenderAssemblyAnchorMarker(); + RefreshAssemblyReferenceRodIfNeeded(); + } + } + } + public bool HasAssemblyTerminalObject { get => _hasAssemblyTerminalObject; @@ -1304,6 +1320,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels HasAssemblyTerminalObject = true; AssemblyStartPointText = "未选择"; AssemblyTerminalObjectName = ModelItemAnalysisHelper.GetSafeDisplayName(selectedItem); + InitializeAssemblyAnchorVerticalOffsetFromTerminalObject(); RefreshAssemblyTerminalObjectInfo(); RenderAssemblyAnchorMarker(); OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod)); @@ -1420,6 +1437,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels Point3D projectedStartPoint = AssemblyReferencePathManager.Instance.ProjectPointToReferenceLine(pickResult.Point); _assemblyStartPoint = projectedStartPoint; AssemblyStartPointText = $"({projectedStartPoint.X:F2}, {projectedStartPoint.Y:F2}, {projectedStartPoint.Z:F2})"; + LogManager.Info( + $"[直线装配] 点击点=({pickResult.Point.X:F2}, {pickResult.Point.Y:F2}, {pickResult.Point.Z:F2})," + + $"投影起点=({projectedStartPoint.X:F2}, {projectedStartPoint.Y:F2}, {projectedStartPoint.Z:F2})"); await SafeExecuteAsync(() => { @@ -1450,7 +1470,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels RailPathDefinitionMode = RailPathDefinitionMode.RailCenterLine }; - route.AddPoint(new PathPoint(_assemblyStartPoint, "装配起点", PathPointType.StartPoint)); + route.AddPoint(new PathPoint(startPoint, "装配起点", PathPointType.StartPoint)); route.AddPoint(new PathPoint(endPoint, "装配终点", PathPointType.EndPoint)); if (!_pathPlanningManager.AddRoute(route)) @@ -1459,14 +1479,21 @@ namespace NavisworksTransport.UI.WPF.ViewModels } _pathPlanningManager.SetCurrentRoute(route); - _pathPlanningManager.DrawRouteVisualization(route, isAutoPath: false); - _pathPlanningManager.SavePathToDatabase(route); - if (!_pathPlanningManager.GeneratePath(route)) { throw new InvalidOperationException("装配路径生成失败"); } + _pathPlanningManager.DrawRouteVisualization(route, isAutoPath: false); + RefreshPathRoutes(); + + var generatedRouteViewModel = PathRoutes.FirstOrDefault(p => p.Name == route.Name); + if (generatedRouteViewModel != null) + { + SelectedPathRoute = generatedRouteViewModel; + UpdatePassageSpaceVisualizationForPathType(route.PathType); + } + AssemblyTerminalObjectInfo = string.Format( "对接终点=({0:F2}, {1:F2}, {2:F2}),装配起点={3},安装方式={4},对接基准={5}", endPoint.X, @@ -1477,7 +1504,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels AssemblyPayloadAnchorMode == RailPayloadAnchorMode.TopCenter ? "顶面对接" : "底面对接"); OnPropertyChanged(nameof(PathRoutes)); - LogManager.Info($"[直线装配] 已生成路径: {route.Name}"); + LogManager.Info($"[直线装配] 已生成路径: {route.Name},起点=({startPoint.X:F2}, {startPoint.Y:F2}, {startPoint.Z:F2}),终点=({endPoint.X:F2}, {endPoint.Y:F2}, {endPoint.Z:F2})"); } private Point3D GetAssemblyTerminalAnchorPoint() @@ -1490,14 +1517,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels var bounds = _assemblyTerminalObject.BoundingBox(); var center = bounds.Center; Vector3D up = ModelItemTransformHelper.GetUpDirectionFromTransform(_assemblyTerminalObject.Transform); - Vector3D localSize = ModelItemTransformHelper.EstimateLocalBoxSize(bounds, _assemblyTerminalObject.Transform); - double halfHeight = Math.Max(0.0, localSize.Z / 2.0); double direction = AssemblyPayloadAnchorMode == RailPayloadAnchorMode.TopCenter ? 1.0 : -1.0; + double verticalOffset = UnitsConverter.ConvertFromMeters(AssemblyAnchorVerticalOffsetInMeters); return new Point3D( - center.X + up.X * halfHeight * direction, - center.Y + up.Y * halfHeight * direction, - center.Z + up.Z * halfHeight * direction); + center.X + up.X * verticalOffset * direction, + center.Y + up.Y * verticalOffset * direction, + center.Z + up.Z * verticalOffset * direction); } private AssemblyReferenceLine BuildAssemblyReferenceLine() @@ -1548,7 +1574,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels 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:F2}, {12:F2}, {13:F2})", + "中心=({0:F2}, {1:F2}, {2:F2}),尺寸=({3:F2}, {4:F2}, {5:F2}),{6},{7}点=({8:F2}, {9:F2}, {10:F2}),垂直偏移={11:F3}m,参考杆起点=({12:F2}, {13:F2}, {14:F2})", bounds.Center.X, bounds.Center.Y, bounds.Center.Z, @@ -1560,6 +1586,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels referenceEndPoint.X, referenceEndPoint.Y, referenceEndPoint.Z, + AssemblyAnchorVerticalOffsetInMeters, referenceStartPoint.X, referenceStartPoint.Y, referenceStartPoint.Z); @@ -1567,7 +1594,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})", + "中心=({0:F2}, {1:F2}, {2:F2}),尺寸=({3:F2}, {4:F2}, {5:F2}),{6},{7}点=({8:F2}, {9:F2}, {10:F2}),垂直偏移={11:F3}m", bounds.Center.X, bounds.Center.Y, bounds.Center.Z, @@ -1578,7 +1605,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels anchorText, anchorPoint.X, anchorPoint.Y, - anchorPoint.Z); + anchorPoint.Z, + AssemblyAnchorVerticalOffsetInMeters); } private void RefreshAssemblyReferenceRodIfNeeded() @@ -1609,6 +1637,20 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + private void InitializeAssemblyAnchorVerticalOffsetFromTerminalObject() + { + if (_assemblyTerminalObject == null || !ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject)) + { + return; + } + + var bounds = _assemblyTerminalObject.BoundingBox(); + Vector3D localSize = ModelItemTransformHelper.EstimateLocalBoxSize(bounds, _assemblyTerminalObject.Transform); + double suggestedOffset = UnitsConverter.ConvertToMeters(Math.Max(0.0, localSize.Z / 2.0)); + _assemblyAnchorVerticalOffsetInMeters = suggestedOffset; + OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters)); + } + private sealed class AssemblyReferenceLine { public AssemblyReferenceLine(Point3D startPoint, Point3D endPoint, Vector3D direction) diff --git a/src/UI/WPF/Views/PathEditingView.xaml b/src/UI/WPF/Views/PathEditingView.xaml index e8f87cb..e493651 100644 --- a/src/UI/WPF/Views/PathEditingView.xaml +++ b/src/UI/WPF/Views/PathEditingView.xaml @@ -332,6 +332,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管 +