From 8b4afcfe0445c6f68051fa2f30f42f9a9f1e2e52 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Wed, 11 Mar 2026 23:17:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=89=96=E9=9D=A2=E7=9B=92?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModels/LayerManagementViewModel.cs | 259 +++++++++++++++--- .../ViewModels/SystemManagementViewModel.cs | 66 +---- src/UI/WPF/Views/LayerManagementView.xaml | 22 ++ src/UI/WPF/Views/SystemManagementView.xaml | 5 - src/Utils/VisibilityHelper.cs | 71 +++-- 5 files changed, 295 insertions(+), 128 deletions(-) diff --git a/src/UI/WPF/ViewModels/LayerManagementViewModel.cs b/src/UI/WPF/ViewModels/LayerManagementViewModel.cs index 58ca869..4396f4f 100644 --- a/src/UI/WPF/ViewModels/LayerManagementViewModel.cs +++ b/src/UI/WPF/ViewModels/LayerManagementViewModel.cs @@ -737,6 +737,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels public ICommand SaveSelectedItemsCommand { get; private set; } public ICommand CancelOperationCommand { get; private set; } public ICommand TestExportToNwdCommand { get; private set; } + public ICommand ExportSectionBoxCommand { get; private set; } // 楼层属性相关命令 public ICommand RefreshSelectionCommand { get; private set; } @@ -894,6 +895,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels async () => await SaveSelectedItemsAsync(), () => HasSelectedItems); + ExportSectionBoxCommand = new RelayCommand( + async () => await ExportSectionBoxAsync(), + () => IsNotProcessing); + CancelOperationCommand = new RelayCommand(CancelOperation, () => IsProcessing); TestExportToNwdCommand = new RelayCommand( @@ -1792,27 +1797,42 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// private async Task SaveSelectedItemsAsync() { + var document = Autodesk.Navisworks.Api.Application.ActiveDocument; + if (document?.CurrentSelection?.SelectedItems == null || document.CurrentSelection.SelectedItems.Count == 0) + { + MessageBox.Show("请先选择要保存的项目", "保存提示", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + + var items = document.CurrentSelection.SelectedItems.ToList(); + string defaultFileName = GenerateDefaultFileNameForMultipleItems(document, items); + + await ExportItemsToNwdAsync(items, "保存当前选择项", defaultFileName, true); + } + + /// + /// 通用导出方法 - 导出指定对象列表到NWD + /// + /// 要导出的对象列表 + /// 对话框标题 + /// 默认文件名 + /// 是否恢复原始选择 + private async Task ExportItemsToNwdAsync(List items, string dialogTitle, string defaultFileName, bool restoreSelection = false) + { + if (items == null || items.Count == 0) + { + MessageBox.Show("没有要导出的对象", "导出提示", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + try { - LogManager.Info("[LayerManagementViewModel] 开始保存当前选择项"); - + LogManager.Info($"[LayerManagementViewModel] 开始导出 {items.Count} 个对象"); IsProcessing = true; + CurrentOperationText = "准备导出..."; var document = Autodesk.Navisworks.Api.Application.ActiveDocument; - if (document?.Models?.Count == 0 || document.CurrentSelection.SelectedItems.Count == 0) - { - LogManager.Warning("[LayerManagementViewModel] 没有活动文档或未选择节点"); - MessageBox.Show("请先选择要保存的项目", "保存提示", MessageBoxButton.OK, MessageBoxImage.Warning); - return; - } - - // 保存当前选择状态 - var originalSelection = new List(document.CurrentSelection.SelectedItems); - - LogManager.Info($"[LayerManagementViewModel] 用户选中了 {originalSelection.Count} 个节点"); - - // 生成默认文件名 - string defaultFileName = GenerateDefaultFileNameForMultipleItems(document, originalSelection); + var originalSelection = restoreSelection ? document.CurrentSelection.SelectedItems.ToList() : null; // 获取保存路径 string saveFilePath = null; @@ -1820,7 +1840,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels { var saveDialog = new Microsoft.Win32.SaveFileDialog { - Title = "保存当前选择项", + Title = dialogTitle, Filter = "Navisworks文件 (*.nwd)|*.nwd", DefaultExt = "nwd", FileName = defaultFileName @@ -1840,22 +1860,36 @@ namespace NavisworksTransport.UI.WPF.ViewModels bool exportResult = false; string errorMessage = ""; - // 在主线程执行导出 + // 在主线程执行导出,显示Navisworks系统进度条 await Task.Run(() => { System.Windows.Application.Current.Dispatcher.Invoke(() => { + // 设置等待光标 + System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait; + + // 开始Navisworks系统进度条 + var progress = Autodesk.Navisworks.Api.Application.BeginProgress( + dialogTitle, + $"正在导出 {items.Count} 个对象到 NWD 文件..."); + try { - // 收集要导出的项目 (仅根节点) + CurrentOperationText = $"正在导出 {items.Count} 个对象..."; + progress.Update(0.2); + + // 收集要导出的项目 var itemsToExport = new ModelItemCollection(); - itemsToExport.AddRange(originalSelection); + itemsToExport.AddRange(items); LogManager.Info($"[LayerManagementViewModel] 准备导出 {itemsToExport.Count} 个节点"); + progress.Update(0.4); // 在隔离模式下执行导出,自动恢复可见性 VisibilityHelper.ExecuteInIsolation(itemsToExport, () => { + progress.Update(0.6); + // 导出选项 var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions { @@ -1864,10 +1898,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels PreventObjectPropertyExport = PreventObjectPropertyExport }; + progress.Update(0.8); document.ExportToNwd(saveFilePath, exportOptions); exportResult = true; LogManager.Info("[LayerManagementViewModel] ExportToNwd API调用完成"); }); + + progress.Update(1.0); } catch (Exception ex) { @@ -1875,22 +1912,32 @@ namespace NavisworksTransport.UI.WPF.ViewModels errorMessage = ex.Message; exportResult = false; } + finally + { + // 确保进度条被关闭 + Autodesk.Navisworks.Api.Application.EndProgress(); + // 恢复光标 + System.Windows.Input.Mouse.OverrideCursor = null; + } }); }); - // 恢复原始选择 (需要在主线程) - System.Windows.Application.Current.Dispatcher.Invoke(() => + // 恢复原始选择(如果需要) + if (restoreSelection && originalSelection != null) { - try + System.Windows.Application.Current.Dispatcher.Invoke(() => { - document.CurrentSelection.Clear(); - document.CurrentSelection.AddRange(originalSelection); - } - catch (Exception ex) - { - LogManager.Warning($"[LayerManagementViewModel] 恢复选择失败: {ex.Message}"); - } - }); + try + { + document.CurrentSelection.Clear(); + document.CurrentSelection.AddRange(originalSelection); + } + catch (Exception ex) + { + LogManager.Warning($"[LayerManagementViewModel] 恢复选择失败: {ex.Message}"); + } + }); + } // 显示结果 if (exportResult) @@ -1899,23 +1946,163 @@ namespace NavisworksTransport.UI.WPF.ViewModels { var fileInfo = new FileInfo(saveFilePath); MessageBox.Show( - $"保存成功!\n\n文件: {saveFilePath}\n大小: {fileInfo.Length / 1024} KB", - "保存结果", MessageBoxButton.OK, MessageBoxImage.Information); + $"导出成功!\n\n文件: {saveFilePath}\n大小: {fileInfo.Length / 1024} KB", + "导出结果", MessageBoxButton.OK, MessageBoxImage.Information); } } else { - MessageBox.Show($"保存失败: {errorMessage}", "保存错误", MessageBoxButton.OK, MessageBoxImage.Error); + MessageBox.Show($"导出失败: {errorMessage}", "导出错误", MessageBoxButton.OK, MessageBoxImage.Error); } } catch (Exception ex) { - LogManager.Error($"[LayerManagementViewModel] 保存选中项目过程异常: {ex.Message}", ex); - MessageBox.Show($"保存过程异常: {ex.Message}", "保存错误", MessageBoxButton.OK, MessageBoxImage.Error); + LogManager.Error($"[LayerManagementViewModel] 导出过程异常: {ex.Message}", ex); + MessageBox.Show($"导出过程异常: {ex.Message}", "导出错误", MessageBoxButton.OK, MessageBoxImage.Error); } finally { IsProcessing = false; + CurrentOperationText = ""; + } + } + + /// + /// 导出剖面盒内的对象 + /// + private async Task ExportSectionBoxAsync() + { + try + { + IsProcessing = true; + CurrentOperationText = "检查剖面盒..."; + + var document = NavisApplication.ActiveDocument; + if (document == null) + { + MessageBox.Show("没有活动的文档!请先打开一个模型。", "错误", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + // 检查剖面盒 + var viewpoint = document.CurrentViewpoint.Value; + var clipPlanes = viewpoint.ClipPlanes; + + if (clipPlanes == null || !clipPlanes.Enabled) + { + MessageBox.Show( + "当前没有活动的剖面盒!\n请先使用 Navisworks 的剖面工具创建剖面盒。", + "提示", MessageBoxButton.OK, MessageBoxImage.Information); + return; + } + + if (clipPlanes.Mode != ClipPlaneSetMode.Box) + { + MessageBox.Show( + "当前是平面裁剪模式,请切换为剖面盒模式!\n在 Navisworks 剖面工具中选择'Box'模式。", + "提示", MessageBoxButton.OK, MessageBoxImage.Information); + return; + } + + // 获取剖面盒边界 + var box = clipPlanes.Box; + if (box == null) + { + MessageBox.Show("无法获取剖面盒边界!", "错误", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + var sectionBoxBounds = new BoundingBox3D( + new Point3D(box.Min.X, box.Min.Y, box.Min.Z), + new Point3D(box.Max.X, box.Max.Y, box.Max.Z) + ); + + // 异步获取剖面盒内的对象 + CurrentOperationText = "正在查找剖面盒内的对象..."; + List objectsInSectionBox = null; + + await Task.Run(() => + { + objectsInSectionBox = GetObjectsInSectionBox(document, sectionBoxBounds); + }); + + if (objectsInSectionBox.Count == 0) + { + MessageBox.Show("剖面盒内没有找到对象!", "提示", MessageBoxButton.OK, MessageBoxImage.Information); + return; + } + + LogManager.Info($"[LayerManagementViewModel] 剖面盒内找到 {objectsInSectionBox.Count} 个对象"); + + // 生成默认文件名 + string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); + string defaultFileName = $"SectionBox_Export_{timestamp}"; + + // 调用通用导出方法 + await ExportItemsToNwdAsync(objectsInSectionBox, "导出剖面盒", defaultFileName, false); + } + catch (Exception ex) + { + LogManager.Error($"[LayerManagementViewModel] 导出剖面盒异常: {ex.Message}", ex); + MessageBox.Show($"导出剖面盒异常: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); + } + finally + { + IsProcessing = false; + CurrentOperationText = ""; + } + } + + /// + /// 获取剖面盒内的所有对象 + /// + private List GetObjectsInSectionBox(Document document, BoundingBox3D sectionBox) + { + var result = new List(); + + foreach (var model in document.Models) + { + var rootItem = model.RootItem; + if (rootItem != null) + { + TraverseModelItem(rootItem, sectionBox, result); + } + } + + return result; + } + + /// + /// 递归遍历模型项 - 剪枝策略 + /// + private void TraverseModelItem(ModelItem item, BoundingBox3D sectionBox, List result) + { + if (item == null) return; + if (item.IsHidden) return; + + // 如果有几何体信息,检查并添加 + if (item.HasGeometry) + { + var bbox = item.BoundingBox(); + + // 检查是否有体积 + double sizeX = bbox.Max.X - bbox.Min.X; + double sizeY = bbox.Max.Y - bbox.Min.Y; + double sizeZ = bbox.Max.Z - bbox.Min.Z; + bool hasVolume = sizeX > 0.0001 && sizeY > 0.0001 && sizeZ > 0.0001; + + // 有体积且与剖面盒相交才添加 + if (hasVolume && BoundingBoxGeometryUtils.BoundingBoxesIntersect(bbox, sectionBox)) + { + result.Add(item); + } + return; + } + + // 没有几何体,继续遍历子节点 + foreach (var child in item.Children) + { + TraverseModelItem(child, sectionBox, result); } } diff --git a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs index 43c3a49..f24006e 100644 --- a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs +++ b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs @@ -174,7 +174,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels public ICommand TestVoxelPathFindingCommand { get; private set; } public ICommand ReadTransformTestCommand { get; private set; } public ICommand CoordinateSystemExplorerCommand { get; private set; } - public ICommand ExportSectionBoxCommand { get; private set; } + // 坐标系设置 public ObservableCollection CoordinateSystemOptions { get; private set; } @@ -311,7 +311,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels TestVoxelPathFindingCommand = new RelayCommand(() => ExecuteTestVoxelPathFinding()); ReadTransformTestCommand = new RelayCommand(() => ExecuteReadTransformTest()); CoordinateSystemExplorerCommand = new RelayCommand(() => ExecuteCoordinateSystemExplorer()); - ExportSectionBoxCommand = new RelayCommand(() => ExecuteExportSectionBox()); + // 初始化坐标系选项 CoordinateSystemOptions = new ObservableCollection { "AutoDetect", "ZUp", "YUp" }; @@ -1658,68 +1658,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels }, "坐标系检测"); } - /// - /// 执行导出剖面盒功能 - /// - private void ExecuteExportSectionBox() - { - SafeExecute(() => - { - try - { - UpdateMainStatus("正在导出剖面盒信息..."); - LogManager.Info("开始导出剖面盒信息"); - - var doc = Autodesk.Navisworks.Api.Application.ActiveDocument; - if (doc == null || doc.IsClear) - { - System.Windows.MessageBox.Show( - "没有活动的文档!请先打开一个模型。", - "错误", - System.Windows.MessageBoxButton.OK, - System.Windows.MessageBoxImage.Error); - UpdateMainStatus("导出剖面盒失败:无活动文档"); - return; - } - - // 使用导出功能类 - var exporter = new NavisworksTransport.Core.SectionBoxExporter(); - string filePath = exporter.ExportToJson(doc); - - if (!string.IsNullOrEmpty(filePath)) - { - var result = System.Windows.MessageBox.Show( - $"剖面盒信息已导出到:\n{filePath}\n\n是否打开文件所在目录?", - "导出成功", - System.Windows.MessageBoxButton.YesNo, - System.Windows.MessageBoxImage.Information); - - if (result == System.Windows.MessageBoxResult.Yes) - { - System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{filePath}\""); - } - - UpdateMainStatus($"剖面盒信息已导出: {filePath}"); - LogManager.Info($"剖面盒信息导出成功: {filePath}"); - } - else - { - UpdateMainStatus("导出剖面盒被取消或失败"); - } - } - catch (Exception ex) - { - LogManager.Error($"导出剖面盒异常: {ex.Message}", ex); - System.Windows.MessageBox.Show( - $"导出剖面盒出现异常:\n{ex.Message}", - "错误", - System.Windows.MessageBoxButton.OK, - System.Windows.MessageBoxImage.Error); - UpdateMainStatus($"导出剖面盒异常: {ex.Message}"); - } - }, "导出剖面盒"); - } - #endregion #region 辅助方法 diff --git a/src/UI/WPF/Views/LayerManagementView.xaml b/src/UI/WPF/Views/LayerManagementView.xaml index d0d0b80..7796f3f 100644 --- a/src/UI/WPF/Views/LayerManagementView.xaml +++ b/src/UI/WPF/Views/LayerManagementView.xaml @@ -325,6 +325,28 @@ NavisworksTransport 分层管理页签视图 - 重构优化版本 + + + + +