NavisworksTransport/doc/design/2017/navisworks_api_analysis.md

20 KiB
Raw Blame History

Navisworks API 技术分析与开发指南

概述

基于对 Navisworks 2017 官方 API 文档和示例代码的深入分析,本文档提供了完整的 API 使用指南,重点关注物流路径规划插件开发的技术要点。

1. API 架构概览

1.1 双 API 架构模式

Navisworks 提供两套 API

API 类型 主要用途 命名空间 适用场景
.NET API 主要功能开发 Autodesk.Navisworks.Api UI集成、插件框架、3D交互
COM API 属性持久化 Autodesk.Navisworks.Api.Interop.ComApi 用户属性、TimeLiner、数据持久化

我们项目的使用策略:

  • Native API 用于主要插件功能路径规划、UI界面、3D交互
  • COM API 用于物流属性管理和动画功能

1.2 核心插件类型

// 1. AddInPlugin - 主功能插件
[Plugin("NavisworksTransport.MainPlugin", "YourDeveloperID")]
[AddInPlugin(AddInLocation.AddIn)]
public class MainPlugin : AddInPlugin

// 2. ToolPlugin - 3D交互工具
[Plugin("NavisworksTransport.PathClickTool", "YourDeveloperID")]
public class PathClickToolPlugin : ToolPlugin

// 3. RenderPlugin - 3D渲染和可视化
[Plugin("NavisworksTransport.PathPointRender", "YourDeveloperID")]
public class PathPointRenderPlugin : RenderPlugin

// 4. DockPanePlugin - UI面板可选
[Plugin("NavisworksTransport.PropertyPanel", "YourDeveloperID")]
[DockPanePlugin(300, 400)]
public class PropertyPanelPlugin : DockPanePlugin

2. 核心功能实现模式

2.1 3D 点拾取和路径规划

// 鼠标点击处理 - 用于路径点选择
public override bool MouseDown(View view, KeyModifiers modifiers, 
    ushort button, int x, int y, double timeOffset)
{
    if (button == 1) // 左键
    {
        // 进行射线拾取
        PickItemResult pickResult = view.PickItemFromPoint(x, y);
        if (pickResult != null)
        {
            // 获取3D坐标
            Point3D worldPoint = pickResult.Position;
            
            // 转换到表面
            ModelItem item = pickResult.ModelItem;
            Point3D surfacePoint = GetSurfacePoint(item, worldPoint);
            
            // 添加到路径点集合
            AddPathPoint(surfacePoint);
        }
    }
    return false;
}

// 坐标转换和表面贴合
private Point3D GetSurfacePoint(ModelItem item, Point3D worldPoint)
{
    // 获取模型几何信息
    BoundingBox3D boundingBox = item.BoundingBox();
    
    // 进行表面投影计算
    // 这里需要根据具体的几何算法实现
    return projectedPoint;
}

2.2 3D 路径可视化

public override void OverlayRender(View view, Graphics graphics)
{
    if (pathPoints != null && pathPoints.Count > 1)
    {
        // 设置线条样式
        graphics.Color(Color.Blue, 1.0);
        graphics.LineWidth(3);
        
        // 绘制路径线段
        for (int i = 0; i < pathPoints.Count - 1; i++)
        {
            graphics.Line(pathPoints[i], pathPoints[i + 1]);
        }
        
        // 绘制路径点标记
        graphics.Color(Color.Red, 1.0);
        foreach (Point3D point in pathPoints)
        {
            graphics.DrawMarker(point, MarkerType.Circle);
        }
    }
}

2.3 物流属性管理COM API

using ComApi = Autodesk.Navisworks.Api.Interop.ComApi;
using ComApiBridge = Autodesk.Navisworks.Api.ComApi;

public class LogisticsAttributeManager
{
    private ComApi.InwOpState10 state;
    
    public LogisticsAttributeManager()
    {
        state = ComApiBridge.ComApiBridge.State;
    }
    
    // 为模型元素设置物流属性
    public bool SetLogisticsAttribute(ModelItem item, LogisticsType type, 
        Dictionary<string, object> properties)
    {
        try
        {
            ComApi.InwOaPath oPath = ComApiBridge.ComApiBridge.ToInwOaPath(item);
            ComApi.InwGUIPropertyNode2 propNode = (ComApi.InwGUIPropertyNode2)oPath.PropertyNode();
            
            // 创建或获取物流属性类别
            ComApi.InwOaPropertyVec logisticsCategory = GetOrCreateLogisticsCategory(propNode);
            
            // 设置基础属性
            SetProperty(logisticsCategory, "类型", type.ToString());
            SetProperty(logisticsCategory, "创建时间", DateTime.Now.ToString());
            
            // 设置特定属性
            foreach (var kvp in properties)
            {
                SetProperty(logisticsCategory, kvp.Key, kvp.Value.ToString());
            }
            
            // 提交更改
            propNode.SetUserDefined(0, "物流属性", "LogisticsAttributes", logisticsCategory);
            
            return true;
        }
        catch (Exception ex)
        {
            LogManager.Error($"设置物流属性失败: {ex.Message}");
            return false;
        }
    }
    
    private ComApi.InwOaPropertyVec GetOrCreateLogisticsCategory(ComApi.InwGUIPropertyNode2 propNode)
    {
        // 尝试获取现有类别
        ComApi.InwGUIPropertyTab2 tabs = (ComApi.InwGUIPropertyTab2)propNode.GetGUIPropertyTabs();
        for (int i = 1; i <= tabs.count; i++)
        {
            ComApi.InwGUIPropertyTab tab = tabs.GetAt(i);
            if (tab.UserName == "物流属性")
            {
                return (ComApi.InwOaPropertyVec)tab.GetUserDefined();
            }
        }
        
        // 创建新类别
        return (ComApi.InwOaPropertyVec)state.ObjectFactory(ComApi.nwEObjectType.eObjectType_nwOaPropertyVec);
    }
    
    private void SetProperty(ComApi.InwOaPropertyVec category, string name, string value)
    {
        ComApi.InwOaProperty property = (ComApi.InwOaProperty)state.ObjectFactory(ComApi.nwEObjectType.eObjectType_nwOaProperty);
        property.name = name;
        property.UserName = name;
        property.value = value;
        category.Properties().Add(property);
    }
}

2.4 搜索和筛选功能

// 根据物流属性搜索模型元素
public ModelItemCollection FindLogisticsElements(LogisticsType type)
{
    Search search = new Search();
    
    // 创建属性搜索条件
    SearchCondition condition = SearchCondition.HasPropertyByDisplayName(
        "物流属性", "类型").EqualValue(VariantData.FromString(type.ToString()));
    
    search.SearchConditions.Add(condition);
    
    // 执行搜索
    ModelItemCollection results = search.FindAll(Application.ActiveDocument, false);
    return results;
}

// 按类别筛选并高亮显示
public void HighlightLogisticsElements(LogisticsType type)
{
    ModelItemCollection elements = FindLogisticsElements(type);
    
    // 清除现有选择
    Application.ActiveDocument.CurrentSelection.Clear();
    
    // 选择找到的元素
    Application.ActiveDocument.CurrentSelection.CopyFrom(elements);
    
    // 设置显示颜色
    OverridePermanentColor(elements, GetLogisticsTypeColor(type));
}

2.5 碰撞检测集成

public class TransportCollisionDetector
{
    // 创建运输路径碰撞检测
    public List<CollisionResult> DetectPathCollisions(List<Point3D> pathPoints, 
        TransportVehicle vehicle)
    {
        List<CollisionResult> collisions = new List<CollisionResult>();
        
        // 获取碰撞检测文档
        DocumentClash clashDoc = Application.ActiveDocument.GetClash();
        
        // 为每个路径段创建碰撞测试
        for (int i = 0; i < pathPoints.Count - 1; i++)
        {
            // 创建虚拟运输车辆几何体
            var vehicleGeometry = CreateVehicleGeometry(pathPoints[i], pathPoints[i + 1], vehicle);
            
            // 创建碰撞测试
            ClashTest test = new ClashTest();
            test.DisplayName = $"路径段_{i + 1}_碰撞检测";
            
            // 设置检测对象
            test.SelectionA.Selection.SelectAll(); // 选择所有模型
            test.SelectionB.Selection.SelectGeometry(vehicleGeometry); // 虚拟车辆
            
            // 运行检测
            test.Run();
            
            // 收集结果
            foreach (ClashResult result in test.Results)
            {
                collisions.Add(new CollisionResult
                {
                    PathSegment = i,
                    ClashPoint = result.GetImpactPoint(),
                    ClashItem = result.Item1,
                    Severity = result.Status
                });
            }
        }
        
        return collisions;
    }
}

2.6 动画播放集成

public class PathAnimationController
{
    private Timer animationTimer;
    private List<Point3D> pathPoints;
    private ModelItem transportVehicle;
    private int currentSegment;
    private float animationProgress;
    
    public void StartAnimation(ModelItem vehicle, List<Point3D> path, TimeSpan duration)
    {
        transportVehicle = vehicle;
        pathPoints = path;
        currentSegment = 0;
        animationProgress = 0f;
        
        // 计算动画参数
        int totalSegments = pathPoints.Count - 1;
        double segmentDuration = duration.TotalMilliseconds / totalSegments;
        
        // 启动定时器
        animationTimer = new Timer((int)segmentDuration / 20); // 50 FPS
        animationTimer.Tick += OnAnimationTick;
        animationTimer.Start();
    }
    
    private void OnAnimationTick(object sender, EventArgs e)
    {
        if (currentSegment >= pathPoints.Count - 1)
        {
            StopAnimation();
            return;
        }
        
        // 计算当前位置
        Point3D currentPos = InterpolatePosition(
            pathPoints[currentSegment], 
            pathPoints[currentSegment + 1], 
            animationProgress);
        
        // 更新车辆位置
        UpdateVehiclePosition(transportVehicle, currentPos);
        
        // 更新进度
        animationProgress += 0.05f; // 每帧5%进度
        if (animationProgress >= 1.0f)
        {
            currentSegment++;
            animationProgress = 0f;
        }
        
        // 刷新视图
        Application.ActiveDocument.CurrentViewpoint.Redraw();
    }
    
    private void UpdateVehiclePosition(ModelItem vehicle, Point3D position)
    {
        // 创建变换矩阵
        Transform3D transform = Transform3D.CreateTranslation(position.ToVector3D());
        
        // 应用变换需要COM API
        ComApi.InwOaPath vehiclePath = ComApiBridge.ComApiBridge.ToInwOaPath(vehicle);
        ComApi.InwOaNode vehicleNode = vehiclePath.Nodes().Last() as ComApi.InwOaNode;
        
        // 设置变换
        vehicleNode.SetAttribute("LcOaNodeBaseTransform", transform.ToComMatrix());
    }
}

3. UI 集成和事件处理

3.1 Ribbon 界面集成

// 自定义 Ribbon 标签页
[RibbonLayout("TransportRibbon.xaml")]
[RibbonTab("ID_TransportTab", DisplayName = "物流运输")]
public class TransportRibbonHandler : CommandHandlerPlugin
{
    [Command("ID_PathPlanning", DisplayName = "路径规划", Icon = "PathPlanning_32.ico")]
    public void OnPathPlanningCommand()
    {
        // 激活路径规划工具
        ActivatePathPlanningTool();
    }
    
    [Command("ID_CollisionDetection", DisplayName = "碰撞检测", Icon = "Collision_32.ico")]
    public void OnCollisionDetectionCommand()
    {
        // 启动碰撞检测
        StartCollisionDetection();
    }
}

3.2 事件驱动架构

public class TransportEventManager
{
    public static event EventHandler<PathPointAddedEventArgs> PathPointAdded;
    public static event EventHandler<CollisionDetectedEventArgs> CollisionDetected;
    public static event EventHandler<AnimationStateChangedEventArgs> AnimationStateChanged;
    
    // 初始化事件监听
    public static void Initialize()
    {
        // 文档加载事件
        Application.ActiveDocument.Database.Loaded += OnDatabaseLoaded;
        
        // 选择变化事件
        Application.ActiveDocument.CurrentSelection.Changed += OnSelectionChanged;
        
        // 视图变化事件
        Application.ActiveDocument.ViewpointData.Current.Changed += OnViewpointChanged;
    }
    
    private static void OnDatabaseLoaded(object sender, EventArgs e)
    {
        // 重新加载路径数据
        PathDataManager.LoadPathsFromDocument();
        
        // 重建物流属性索引
        LogisticsAttributeManager.RebuildIndex();
    }
}

4. 数据持久化和文件处理

4.1 路径数据序列化

public class PathDataManager
{
    private const string PATHS_PROPERTY_NAME = "TransportPaths";
    
    // 保存路径到文档
    public static void SavePathsToDocument(List<PathRoute> paths)
    {
        try
        {
            // 序列化为JSON
            string jsonData = JsonConvert.SerializeObject(paths, Formatting.Indented);
            
            // 保存到文档属性
            var docProperties = Application.ActiveDocument.DocumentInformation.Value;
            docProperties.SetUserString(PATHS_PROPERTY_NAME, jsonData);
            
            LogManager.Info($"已保存 {paths.Count} 条路径到文档");
        }
        catch (Exception ex)
        {
            LogManager.Error($"保存路径失败: {ex.Message}");
        }
    }
    
    // 从文档加载路径
    public static List<PathRoute> LoadPathsFromDocument()
    {
        try
        {
            var docProperties = Application.ActiveDocument.DocumentInformation.Value;
            string jsonData = docProperties.GetUserString(PATHS_PROPERTY_NAME);
            
            if (!string.IsNullOrEmpty(jsonData))
            {
                return JsonConvert.DeserializeObject<List<PathRoute>>(jsonData);
            }
        }
        catch (Exception ex)
        {
            LogManager.Error($"加载路径失败: {ex.Message}");
        }
        
        return new List<PathRoute>();
    }
}

4.2 外部文件导入导出

public class PathFileManager
{
    // 导出路径为不同格式
    public static bool ExportPaths(List<PathRoute> paths, string filePath, PathExportFormat format)
    {
        try
        {
            switch (format)
            {
                case PathExportFormat.JSON:
                    return ExportToJson(paths, filePath);
                
                case PathExportFormat.XML:
                    return ExportToXml(paths, filePath);
                    
                case PathExportFormat.CSV:
                    return ExportToCsv(paths, filePath);
                    
                case PathExportFormat.DELMIA:
                    return ExportToDelmia(paths, filePath);
            }
        }
        catch (Exception ex)
        {
            LogManager.Error($"导出路径失败: {ex.Message}");
        }
        
        return false;
    }
    
    // DELMIA 格式导出
    private static bool ExportToDelmia(List<PathRoute> paths, string filePath)
    {
        // 创建 DELMIA 兼容的路径数据结构
        var delmiaData = new
        {
            version = "1.0",
            paths = paths.Select(p => new
            {
                id = p.Id,
                name = p.Name,
                points = p.Points.Select(pt => new
                {
                    x = pt.X,
                    y = pt.Y,
                    z = pt.Z,
                    timestamp = pt.Timestamp
                })
            })
        };
        
        string jsonOutput = JsonConvert.SerializeObject(delmiaData, Formatting.Indented);
        File.WriteAllText(filePath, jsonOutput, Encoding.UTF8);
        
        return true;
    }
}

5. 性能优化和最佳实践

5.1 大模型处理优化

public class PerformanceOptimizer
{
    // 分批处理大量模型元素
    public static void ProcessLargeModelBatch<T>(IEnumerable<T> items, 
        Action<T> processor, int batchSize = 100)
    {
        var batch = new List<T>();
        foreach (var item in items)
        {
            batch.Add(item);
            
            if (batch.Count >= batchSize)
            {
                ProcessBatch(batch, processor);
                batch.Clear();
                
                // 让出CPU时间
                Application.DoEvents();
            }
        }
        
        // 处理最后一批
        if (batch.Count > 0)
        {
            ProcessBatch(batch, processor);
        }
    }
    
    // 视图级别的渲染优化
    public static void OptimizeRenderingPerformance()
    {
        var viewpoint = Application.ActiveDocument.CurrentViewpoint;
        
        // 临时禁用某些渲染特效
        viewpoint.RenderStyle = ViewpointRenderStyle.Wireframe;
        
        // 减少显示细节
        viewpoint.LODEnabled = true;
        viewpoint.LODThreshold = 0.1; // 降低细节阈值
    }
}

5.2 内存管理

public class ResourceManager : IDisposable
{
    private List<IDisposable> managedResources = new List<IDisposable>();
    
    public T RegisterResource<T>(T resource) where T : IDisposable
    {
        managedResources.Add(resource);
        return resource;
    }
    
    public void Dispose()
    {
        foreach (var resource in managedResources)
        {
            try
            {
                resource?.Dispose();
            }
            catch (Exception ex)
            {
                LogManager.Warning($"资源释放警告: {ex.Message}");
            }
        }
        managedResources.Clear();
    }
}

6. 调试和日志记录

6.1 统一日志系统

public static class LogManager
{
    private static readonly string LogFilePath = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
        "NavisworksTransport", "Logs", $"transport_{DateTime.Now:yyyyMMdd}.log");
        
    public static void Info(string message)
    {
        WriteLog("INFO", message);
    }
    
    public static void Warning(string message)
    {
        WriteLog("WARN", message);
    }
    
    public static void Error(string message)
    {
        WriteLog("ERROR", message);
        
        // 同时显示给用户
        MessageBox.Show(Application.Gui.MainWindow, message, "错误", 
            MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    
    private static void WriteLog(string level, string message)
    {
        try
        {
            string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}";
            
            Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath));
            File.AppendAllText(LogFilePath, logEntry + Environment.NewLine);
            
            // 同时输出到调试控制台
            System.Diagnostics.Debug.WriteLine(logEntry);
        }
        catch
        {
            // 忽略日志写入失败
        }
    }
}

7. 部署和安装

7.1 自动安装脚本

public class PluginInstaller
{
    private static readonly string NavisworksPath = 
        @"%PROGRAMFILES%\Autodesk\Navisworks Manage 2017";
    private static readonly string PluginTargetPath = 
        @"%PROGRAMFILES%\Autodesk\Navisworks Manage 2017\Plugins\NavisworksTransportPlugin";
    
    public static bool InstallPlugin()
    {
        try
        {
            // 检查 Navisworks 安装
            string navisworksDir = Environment.ExpandEnvironmentVariables(NavisworksPath);
            if (!Directory.Exists(navisworksDir))
            {
                throw new DirectoryNotFoundException("未找到 Navisworks Manage 2017 安装");
            }
            
            // 创建插件目录
            string pluginDir = Environment.ExpandEnvironmentVariables(PluginTargetPath);
            Directory.CreateDirectory(pluginDir);
            
            // 复制插件文件
            string sourceDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            CopyPluginFiles(sourceDir, pluginDir);
            
            // 注册插件
            RegisterPlugin(pluginDir);
            
            return true;
        }
        catch (Exception ex)
        {
            LogManager.Error($"插件安装失败: {ex.Message}");
            return false;
        }
    }
}

总结

本分析文档基于 Navisworks 官方 API 文档和示例代码,为 NavisworksTransport 插件开发提供了完整的技术指南。关键要点:

  1. 架构设计:采用 .NET API + COM API 的双重架构
  2. 功能实现涵盖3D交互、属性管理、碰撞检测、动画播放等核心功能
  3. 性能优化:提供大模型处理和内存管理的最佳实践
  4. 扩展性:设计了可扩展的事件驱动架构
  5. 维护性:建立了完整的日志和调试系统

当前项目实现已经达到企业级标准,建议重点关注性能优化和高级搜索功能的扩展。