给“导出剖面盒”增加导出nwd文件;重构了可见性的保存和恢复
This commit is contained in:
parent
0f669fd995
commit
3b801c6bd4
@ -2,6 +2,10 @@
|
||||
|
||||
## 功能点
|
||||
|
||||
### [2026/3/11]
|
||||
|
||||
1. [x] (功能)给“导出剖面盒”增加导出nwd文件的选项
|
||||
|
||||
### [2026/3/9]
|
||||
|
||||
1. [x] (功能)支持记录并查看路径文件操作的历史记录
|
||||
|
||||
@ -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)
|
||||
{
|
||||
// 如果用户选择了JSON(FilterIndex为2或文件扩展名为json)
|
||||
exportAsNwd = !(dialog.FilterIndex == 2 ||
|
||||
dialog.FileName.EndsWith(".json", StringComparison.OrdinalIgnoreCase));
|
||||
return dialog.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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("操作失败");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user