给“导出剖面盒”增加导出nwd文件;重构了可见性的保存和恢复

This commit is contained in:
tian 2026-03-11 19:03:43 +08:00
parent 0f669fd995
commit 3b801c6bd4
5 changed files with 314 additions and 163 deletions

View File

@ -2,6 +2,10 @@
## 功能点
### [2026/3/11]
1. [x] 功能给“导出剖面盒”增加导出nwd文件的选项
### [2026/3/9]
1. [x] (功能)支持记录并查看路径文件操作的历史记录

View File

@ -6,6 +6,7 @@ using System.Windows.Forms;
using Autodesk.Navisworks.Api;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NavisApplication = Autodesk.Navisworks.Api.Application;
namespace NavisworksTransport.Core
{
@ -15,7 +16,7 @@ namespace NavisworksTransport.Core
public class SectionBoxExporter
{
/// <summary>
/// 导出剖面盒信息到JSON文件
/// 导出剖面盒信息
/// </summary>
/// <param name="document">Navisworks文档</param>
/// <returns>导出的文件路径失败返回null</returns>
@ -72,8 +73,8 @@ namespace NavisworksTransport.Core
return null;
}
// 3. 选择保存路径
string filePath = ShowSaveFileDialog();
// 3. 选择保存路径和格式
string filePath = ShowSaveFileDialog(out bool exportAsNwd);
if (string.IsNullOrEmpty(filePath))
return null;
@ -82,15 +83,20 @@ namespace NavisworksTransport.Core
// 4. 获取剖面盒内的对象
var objectsInSectionBox = GetObjectsInSectionBox(document, sectionBoxBounds);
// 5. 构建导出数据
var exportData = BuildExportData(sectionBoxBounds, objectsInSectionBox, document);
// 6. 序列化为JSON并保存
string json = JsonConvert.SerializeObject(exportData, Formatting.Indented);
File.WriteAllText(filePath, json);
LogManager.Info($"剖面盒导出完成: {objectsInSectionBox.Count} 个对象 -> {filePath}");
return filePath;
if (exportAsNwd)
{
// 导出为NWD格式
return ExportToNwd(document, objectsInSectionBox, filePath);
}
else
{
// 导出为JSON格式原有逻辑
var exportData = BuildExportData(sectionBoxBounds, objectsInSectionBox, document);
string json = JsonConvert.SerializeObject(exportData, Formatting.Indented);
File.WriteAllText(filePath, json);
LogManager.Info($"剖面盒导出完成: {objectsInSectionBox.Count} 个对象 -> {filePath}");
return filePath;
}
}
catch (Exception ex)
{
@ -331,20 +337,58 @@ namespace NavisworksTransport.Core
return string.Join("/", pathParts);
}
/// <summary>
/// 导出为NWD文件
/// </summary>
private string ExportToNwd(Document document, List<ModelItem> objects, string filePath)
{
// 必须在主线程执行Navisworks API操作
string result = null;
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
// 准备要显示的项目
var itemsToShow = new ModelItemCollection();
foreach (var item in objects)
itemsToShow.Add(item);
// 在隔离模式下执行导出,自动保存和恢复可见性
result = VisibilityHelper.ExecuteInIsolation(itemsToShow, () =>
{
// 创建导出选项
var exportOptions = new NwdExportOptions
{
ExcludeHiddenItems = true
};
// 执行导出
document.ExportToNwd(filePath, exportOptions);
LogManager.Info($"[SectionBoxExporter] NWD导出完成: {objects.Count} 个对象 -> {filePath}");
return filePath;
});
});
return result;
}
/// <summary>
/// 显示保存文件对话框
/// </summary>
private string ShowSaveFileDialog()
private string ShowSaveFileDialog(out bool exportAsNwd)
{
exportAsNwd = true; // 默认导出为NWD
using (var dialog = new SaveFileDialog())
{
dialog.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*";
dialog.DefaultExt = "json";
dialog.FileName = $"SectionBox_Export_{DateTime.Now:yyyyMMdd_HHmmss}.json";
// NWD 作为默认格式JSON 作为备选
dialog.Filter = "Navisworks files (*.nwd)|*.nwd|JSON files (*.json)|*.json";
dialog.DefaultExt = "nwd";
dialog.FileName = $"SectionBox_Export_{DateTime.Now:yyyyMMdd_HHmmss}";
dialog.Title = "导出剖面盒信息";
if (dialog.ShowDialog() == DialogResult.OK)
{
// 如果用户选择了JSONFilterIndex为2或文件扩展名为json
exportAsNwd = !(dialog.FilterIndex == 2 ||
dialog.FileName.EndsWith(".json", StringComparison.OrdinalIgnoreCase));
return dialog.FileName;
}
}

View File

@ -1853,15 +1853,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogManager.Info($"[LayerManagementViewModel] 准备导出 {itemsToExport.Count} 个节点");
// 保存当前可见性状态
var originalVisibilityState = SaveCurrentVisibilityState(document);
try
// 在隔离模式下执行导出,自动恢复可见性
VisibilityHelper.ExecuteInIsolation(itemsToExport, () =>
{
// 隔离显示
bool isolateSuccess = VisibilityHelper.IsolateSpecificItems(itemsToExport);
if (!isolateSuccess) throw new InvalidOperationException("隔离显示失败");
// 导出选项
var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions
{
@ -1873,12 +1867,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
document.ExportToNwd(saveFilePath, exportOptions);
exportResult = true;
LogManager.Info("[LayerManagementViewModel] ExportToNwd API调用完成");
}
finally
{
// 恢复可见性
RestoreVisibilityState(document, originalVisibilityState);
}
});
}
catch (Exception ex)
{
@ -1930,112 +1919,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
/// <summary>
/// 保存当前可见性状态
/// </summary>
private Dictionary<ModelItem, bool> SaveCurrentVisibilityState(Document document)
{
var visibilityState = new Dictionary<ModelItem, bool>();
try
{
// 获取所有顶级项目并记录它们的可见性状态
foreach (Model model in document.Models)
{
foreach (ModelItem topLevelItem in model.RootItem.Children)
{
try
{
// 记录是否隐藏IsHidden为true表示隐藏我们存储可见性所以取反
visibilityState[topLevelItem] = !topLevelItem.IsHidden;
}
catch
{
// 如果无法获取状态,默认为可见
visibilityState[topLevelItem] = true;
}
}
}
LogManager.Info($"[LayerManagementViewModel] 保存可见性状态完成,记录了 {visibilityState.Count} 个顶级项目");
}
catch (Exception ex)
{
LogManager.Error($"[LayerManagementViewModel] 保存可见性状态失败: {ex.Message}");
}
return visibilityState;
}
/// <summary>
/// 恢复可见性状态
/// </summary>
private void RestoreVisibilityState(Document document, Dictionary<ModelItem, bool> visibilityState)
{
try
{
LogManager.Info("[LayerManagementViewModel] 恢复可见性状态");
if (visibilityState == null || visibilityState.Count == 0)
{
LogManager.Warning("[LayerManagementViewModel] 没有可见性状态需要恢复,重置为全部可见");
document.Models.ResetAllHidden();
return;
}
// 使用成熟的可见性控制模式 - 分别收集要显示和隐藏的项目
var itemsToShow = new ModelItemCollection();
var itemsToHide = new ModelItemCollection();
foreach (var kvp in visibilityState)
{
try
{
if (kvp.Value) // 原来是可见的
{
itemsToShow.Add(kvp.Key);
}
else // 原来是隐藏的
{
itemsToHide.Add(kvp.Key);
}
}
catch (Exception ex)
{
LogManager.Warning($"[LayerManagementViewModel] 处理项目可见性状态时出错: {ex.Message}");
}
}
// 首先重置所有项目为可见状态
document.Models.ResetAllHidden();
// 然后隐藏原来应该隐藏的项目
if (itemsToHide.Count > 0)
{
document.Models.SetHidden(itemsToHide, true);
LogManager.Info($"[LayerManagementViewModel] 恢复隐藏 {itemsToHide.Count} 个项目");
}
LogManager.Info("[LayerManagementViewModel] 可见性状态恢复完成");
}
catch (Exception ex)
{
LogManager.Error($"[LayerManagementViewModel] 恢复可见性状态失败: {ex.Message}");
// 失败时至少确保模型处于可见状态
try
{
document.Models.ResetAllHidden();
LogManager.Info("[LayerManagementViewModel] 已重置为全部可见状态");
}
catch (Exception resetEx)
{
LogManager.Error($"[LayerManagementViewModel] 重置可见性也失败: {resetEx.Message}");
}
}
}
/// <summary>
/// 测试ExportToNwd API - 专门的导出API
/// </summary>

View File

@ -1435,35 +1435,29 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
else
{
ShowAllInternal();
// 取消"仅显示物流元素",退出隔离模式
if (VisibilityHelper.ExitIsolation())
{
// 更新物流模型列表中的可见性状态
foreach (var model in LogisticsModels)
{
model.IsVisible = true;
}
UpdateMainStatus("已恢复可见性状态");
LogManager.Info("[UI-ModelSettings] 退出隔离模式,恢复可见性状态");
}
else
{
// 没有隔离状态,显示全部
VisibilityHelper.ShowAllItems();
UpdateMainStatus("已显示全部元素");
LogManager.Info("[UI-ModelSettings] 没有隔离状态,显示全部");
}
}
}, "应用可见性模式", runOnUIThread: true);
}
/// <summary>
/// 内部方法:显示所有元素
/// </summary>
private void ShowAllInternal()
{
bool success = VisibilityHelper.ShowAllItems();
if (success)
{
foreach (var model in LogisticsModels)
{
model.IsVisible = true;
}
UpdateMainStatus("显示所有元素");
LogManager.Info("切换到显示全部模式");
}
else
{
UpdateMainStatus("显示全部失败");
LogManager.Error("显示全部失败");
}
}
/// <summary>
/// 内部方法:仅显示物流元素
/// </summary>
@ -1492,7 +1486,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogManager.Info($"[UI-ModelSettings] 找到 {logisticsItems.Count} 个物流元素");
bool success = VisibilityHelper.IsolateSpecificItems(logisticsItems);
// 进入隔离模式(自动保存当前状态)
bool success = VisibilityHelper.EnterIsolation(logisticsItems);
if (success)
{
@ -1507,7 +1502,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
else
{
LogManager.Error("[UI-ModelSettings] 隔离显示失败");
LogManager.Error("[UI-ModelSettings] 进入隔离模式失败");
UpdateMainStatus("操作失败");
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisApplication = Autodesk.Navisworks.Api.Application;
@ -141,5 +142,229 @@ namespace NavisworksTransport
}
}
// 可见性状态栈(支持嵌套隔离)
private static readonly Stack<Dictionary<ModelItem, bool>> _visibilityStateStack = new Stack<Dictionary<ModelItem, bool>>();
/// <summary>
/// 进入隔离模式:保存当前可见性状态,并隔离显示指定项目
/// </summary>
/// <param name="itemsToShow">要显示的项目集合</param>
/// <returns>操作是否成功</returns>
public static bool EnterIsolation(ModelItemCollection itemsToShow)
{
try
{
var document = NavisApplication.ActiveDocument;
if (document == null)
{
LogManager.Warning("[VisibilityHelper] 进入隔离模式失败:没有活动文档");
return false;
}
// 保存当前状态到栈
var state = SaveVisibilityStateInternal(document);
_visibilityStateStack.Push(state);
// 执行隔离显示
bool success = IsolateSpecificItems(itemsToShow);
if (!success)
{
// 隔离失败,弹出状态
_visibilityStateStack.Pop();
return false;
}
LogManager.Info($"[VisibilityHelper] 进入隔离模式,当前栈深度: {_visibilityStateStack.Count}");
return true;
}
catch (Exception ex)
{
LogManager.Error($"[VisibilityHelper] 进入隔离模式失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 退出隔离模式:恢复之前保存的可见性状态
/// </summary>
/// <returns>操作是否成功</returns>
public static bool ExitIsolation()
{
try
{
if (_visibilityStateStack.Count == 0)
{
LogManager.Warning("[VisibilityHelper] 退出隔离模式失败:没有保存的状态");
return false;
}
var document = NavisApplication.ActiveDocument;
if (document == null)
{
LogManager.Warning("[VisibilityHelper] 退出隔离模式失败:没有活动文档");
return false;
}
// 弹出并恢复状态
var state = _visibilityStateStack.Pop();
RestoreVisibilityStateInternal(document, state);
LogManager.Info($"[VisibilityHelper] 退出隔离模式,当前栈深度: {_visibilityStateStack.Count}");
return true;
}
catch (Exception ex)
{
LogManager.Error($"[VisibilityHelper] 退出隔离模式失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 在隔离模式下执行操作,自动恢复可见性
/// </summary>
/// <param name="itemsToShow">要显示的项目集合</param>
/// <param name="action">要执行的操作</param>
public static void ExecuteInIsolation(ModelItemCollection itemsToShow, Action action)
{
bool entered = EnterIsolation(itemsToShow);
try
{
action?.Invoke();
}
finally
{
if (entered)
{
ExitIsolation();
}
}
}
/// <summary>
/// 在隔离模式下执行操作(带返回值),自动恢复可见性
/// </summary>
/// <typeparam name="T">返回值类型</typeparam>
/// <param name="itemsToShow">要显示的项目集合</param>
/// <param name="func">要执行的函数</param>
/// <returns>函数执行结果</returns>
public static T ExecuteInIsolation<T>(ModelItemCollection itemsToShow, Func<T> func)
{
bool entered = EnterIsolation(itemsToShow);
try
{
return func.Invoke();
}
finally
{
if (entered)
{
ExitIsolation();
}
}
}
/// <summary>
/// 获取当前隔离栈深度(用于调试)
/// </summary>
public static int IsolationDepth => _visibilityStateStack.Count;
/// <summary>
/// 清空所有保存的可见性状态(谨慎使用)
/// </summary>
public static void ClearIsolationStack()
{
_visibilityStateStack.Clear();
LogManager.Warning("[VisibilityHelper] 已清空所有隔离状态");
}
#region
/// <summary>
/// 保存当前可见性状态(内部实现)
/// </summary>
private static Dictionary<ModelItem, bool> SaveVisibilityStateInternal(Document document)
{
var visibilityState = new Dictionary<ModelItem, bool>();
try
{
if (document?.Models == null)
return visibilityState;
foreach (Model model in document.Models)
{
if (model.RootItem?.Children == null)
continue;
foreach (ModelItem topLevelItem in model.RootItem.Children)
{
try
{
visibilityState[topLevelItem] = !topLevelItem.IsHidden;
}
catch
{
visibilityState[topLevelItem] = true;
}
}
}
}
catch (Exception ex)
{
LogManager.Error($"[VisibilityHelper] 保存可见性状态失败: {ex.Message}");
}
return visibilityState;
}
/// <summary>
/// 恢复可见性状态(内部实现)
/// </summary>
private static void RestoreVisibilityStateInternal(Document document, Dictionary<ModelItem, bool> visibilityState)
{
try
{
if (document?.Models == null)
return;
if (visibilityState == null || visibilityState.Count == 0)
{
document.Models.ResetAllHidden();
return;
}
var itemsToHide = new ModelItemCollection();
foreach (var kvp in visibilityState)
{
try
{
if (!kvp.Value) // 原来是隐藏的
{
itemsToHide.Add(kvp.Key);
}
}
catch { }
}
document.Models.ResetAllHidden();
if (itemsToHide.Count > 0)
{
document.Models.SetHidden(itemsToHide, true);
}
}
catch (Exception ex)
{
LogManager.Error($"[VisibilityHelper] 恢复可见性状态失败: {ex.Message}");
try
{
document.Models.ResetAllHidden();
}
catch { }
}
}
#endregion
}
}