NavisworksTransport/.agents/skills/nw-api/references/api-usage-patterns.md

7.1 KiB
Raw Blame History

Navisworks API 常用模式

1. 模型遍历

遍历所有模型项

// 获取所有模型项
IEnumerable<ModelItem> allItems = 
    Application.ActiveDocument.Models.RootItemDescendantsAndSelf;

// 遍历特定模型
foreach (Model model in document.Models)
{
    foreach (ModelItem item in model.RootItem.DescendantsAndSelf)
    {
        // 处理每个模型项
    }
}

获取子节点

// 获取所有后代(不包括自己)
var childItems = selectedItem.DescendantsAndSelf.Where(x => x != selectedItem);

// 只获取直接子节点
foreach (ModelItem child in parentItem.Children) { }

// 向上遍历祖先
var current = selectedItem.Parent;
while (current != null)
{
    current = current.Parent;
}

2. 搜索和查询

使用 Search 类

Search search = new Search();

// 添加搜索条件
search.SearchConditions.Add(
    SearchCondition.HasCategoryByName(PropertyCategoryNames.Geometry));
search.SearchConditions.Add(
    SearchCondition.HasPropertyByName(PropertyCategoryNames.Item, DataPropertyNames.ItemHidden)
    .EqualValue(VariantData.FromBoolean(false)));

// 设置搜索范围
search.Selection.SelectAll();
search.Locations = SearchLocations.DescendantsAndSelf;

// 执行搜索
ModelItemCollection results = search.FindAll(document, false);

使用 LINQ 查询

var results = document.Models.RootItemDescendantsAndSelf
    .Where(x => x.HasGeometry && !x.IsHidden)
    .Where(x => x.ClassDisplayName.ToLower().Contains("wall"));

3. 选择操作

// 获取当前选择
var currentSelection = document.CurrentSelection.SelectedItems;

// 清空选择
document.CurrentSelection.Clear();

// 添加到选择
document.CurrentSelection.Add(modelItem);

// 复制集合到选择
document.CurrentSelection.CopyFrom(modelItems);

4. 可见性控制

// 隐藏项目
ModelItemCollection itemsToHide = new ModelItemCollection();
itemsToHide.Add(modelItem);
document.Models.SetHidden(itemsToHide, true);

// 显示项目
document.Models.SetHidden(itemsToHide, false);

// 检查是否隐藏
if (modelItem.IsHidden) { }

5. 文件导出

// 保存 NWD 文件
document.SaveFile(filePath);

// 使用导出选项
var exportOptions = new NwdExportOptions();
exportOptions.ExcludeHiddenItems = true;
exportOptions.EmbedXrefs = false;
exportOptions.PreventObjectPropertyExport = false;

document.ExportToNwd(saveFilePath, exportOptions);

6. Transform 变换操作

核心概念

  • ModelItem.Transform - 返回设计文件中的原始变换(只读)
  • OverridePermanentTransform() - 应用增量变换(累积)
  • ResetPermanentTransform() - 清除所有增量变换
  • ModelItem.BoundingBox() - 返回当前实际显示的包围盒

应用变换

// 获取原始 Transform
Transform3D originalTransform = modelItem.Transform;

// 应用增量变换
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { modelItem };
doc.Models.OverridePermanentTransform(modelItems, newTransform, false);

// 重置到原始位置
doc.Models.ResetPermanentTransform(modelItems);

绕物体中心旋转(需要补偿)

// 关键API 的旋转总是绕世界原点(0,0,0)
// 要实现绕物体中心旋转,需要计算补偿

double deltaYaw = newYaw - currentYaw;
double cos = Math.Cos(deltaYaw);
double sin = Math.Sin(deltaYaw);

// 计算绕原点旋转后的位置
double rotatedX = currentPosition.X * cos - currentPosition.Y * sin;
double rotatedY = currentPosition.X * sin + currentPosition.Y * cos;

// 计算补偿平移
var compensatedTranslation = new Vector3D(
    newPosition.X - rotatedX,
    newPosition.Y - rotatedY,
    newPosition.Z - currentPosition.Z
);

// 组合变换
var identity = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
var components = identity.Factor();
components.Rotation = new Rotation3D(new UnitVector3D(0, 0, 1), deltaYaw);
components.Translation = compensatedTranslation;

var incrementalTransform = components.Combine();
doc.Models.OverridePermanentTransform(modelItems, incrementalTransform, false);

7. 属性访问

NET API 方式

// 查找属性分类
var category = item.PropertyCategories.FindCategoryByDisplayName("Material");

// 基础属性
string displayName = item.DisplayName;
string className = item.ClassName;
bool hasGeometry = item.HasGeometry;
bool isHidden = item.IsHidden;

COM API 方式(当 NET API 不满足需求时使用)

参考: doc/navisworks_api/NET/examples/Basic Examples/CSharp/APICallsCOMPlugin/

using Autodesk.Navisworks.ComApi;
using Autodesk.Navisworks.Interop.ComApi;

// 获取 COM 状态
ComApi.InwOpState10 state = ComApiBridge.State;

// 获取属性节点
InwOpSelection2 selection = state.CurrentSelection as InwOpSelection2;
InwGUIPropertyNode2 propertyNode = 
    state.GetGUIPropertyNode(selection.Paths()[1], true) as InwGUIPropertyNode2;

// 遍历属性分类
foreach (InwGUIAttribute2 guiAttribute in propertyNode.GUIAttributes())
{
    foreach (InwOaProperty property in guiAttribute.Properties())
    {
        string name = property.name;
        string value = property.value;
    }
}

添加自定义属性COM API

InwOaPropertyVec propertyVector = 
    state.ObjectFactory(nwEObjectType.eObjectType_nwOaPropertyVec);

InwOaProperty property = 
    state.ObjectFactory(nwEObjectType.eObjectType_nwOaProperty);
property.name = "CustomProperty1";
property.UserName = "自定义属性1";
property.value = value;

propertyVector.Properties().Add(property);
propertyNode.SetUserDefined(0, categoryName, internalName, propertyVector);

8. 线程安全 - 关键

所有 Navisworks API 调用必须在主 UI 线程中执行

// ❌ 错误:在后台线程调用
await Task.Run(() =>
{
    var document = Application.ActiveDocument;  // 可能崩溃
});

// ✅ 正确:使用 Dispatcher.Invoke
await Task.Run(() =>
{
    System.Windows.Application.Current.Dispatcher.Invoke(() =>
    {
        var document = Application.ActiveDocument;
        document.ExportToNwd(path, options);  // 安全执行
    });
});

检查线程状态

var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState();
bool isMainThread = System.Windows.Application.Current.Dispatcher.CheckAccess();

9. 碰撞检测 (ClashDetective)

// 获取碰撞测试
document.ClashTestsData.Tests;

// 创建碰撞选择
var selectionA = new ClashSelection(modelItemsA, document);
var selectionB = new ClashSelection(modelItemsB, document);

// 创建碰撞测试
var clashTest = new ClashTest();
clashTest.Name = "Test Name";
clashTest.TestType = ClashTestType.Hard;
clashTest.SelectionA = selectionA;
clashTest.SelectionB = selectionB;

10. TimeLiner 集成

// 获取 TimeLiner 数据
var timeliner = document.Timeliner;

// 添加任务
var task = new TimelinerTask();
task.Name = "Task Name";
task.SimulationStatus = SimulationStatus.Active;
task.StartDate = DateTime.Now;
task.EndDate = DateTime.Now.AddDays(7);

timeliner.Tasks.Add(task);

// 关联模型项
task.Selection.CopyFrom(modelItems);