NavisworksTransport/doc/migration/Migration_Implementation_Plan.md

22 KiB
Raw Blame History

Navisworks 2026 API 迁移实施计划

项目概述

本文档详细规划了NavisworksTransport项目从2017版本迁移到2026版本的具体实施步骤包括时间安排、技术路径和风险控制措施。

核心迁移目标

  1. 动画系统重构从手动Transform变换升级到Navisworks 2026原生动画组件
  2. 物流属性管理优化从复杂COM API迁移到简化的属性集功能
  3. 模型分层拆分稳定性:解决崩溃问题,提升大型模型处理能力
  4. 新功能实现:导航地图输出、增强碰撞检测等

预期收益

  • 动画流畅度提升200%从不稳定15-30fps提升到稳定60fps
  • 开发效率提升400%动画开发时间从2-3天缩短到2-4小时
  • CPU使用率降低60%:特别是动画播放时的资源占用
  • 代码维护成本降低70%:简化复杂的手动时间轴管理

1. 迁移准备阶段第1周

1.1 环境搭建

  • 安装Navisworks 2026开发环境
  • 升级Visual Studio到2022版本
  • 配置.NET Framework 4.8开发环境
  • 获取Navisworks 2026 SDK文档

1.2 项目结构调整

NavisworksTransport/
├── src/
│   ├── Core/                 # 核心API封装
│   ├── Legacy/              # 2017版本兼容层
│   ├── Migration/           # 迁移工具类
│   └── UI/                  # 用户界面
├── tests/
│   ├── ApiTests/            # API功能测试
│   └── IntegrationTests/    # 集成测试
└── docs/
    └── migration/           # 迁移文档

1.3 基础设施准备

  • 创建API兼容性测试套件
  • 建立性能基准测试
  • 设置持续集成环境

2. 阶段1核心API迁移第2-4周

2.1 动画系统重构(🔥 新增重要优化)

2.1.1 动画系统现状分析

当前动画系统存在严重问题:

  • 手动Transform变换性能差
  • Thread.Sleep时间控制不流畅
  • 缺乏标准动画控制功能
  • 维护成本高,扩展性差

2.1.2 新的动画管理器设计

// 基于Navisworks 2026原生动画组件的新实现
public class LogisticsAnimationManager2026
{
    private readonly Document _document;
    private readonly Dictionary<string, AnimationSet> _animationSets;
    private readonly Dictionary<string, AnimationController> _controllers;
    
    public LogisticsAnimationManager2026(Document document)
    {
        _document = document;
        _animationSets = new Dictionary<string, AnimationSet>();
        _controllers = new Dictionary<string, AnimationController>();
    }
    
    // 创建基于关键帧的路径动画
    public AnimationSet CreatePathAnimation(
        string name,
        ModelItem movingObject,
        List<PathPoint> pathPoints,
        TimeSpan duration,
        AnimationOptions options = null)
    {
        var animationSet = new AnimationSet(_document, name);
        
        // 创建变换轨道
        var transformTrack = animationSet.CreateTransformTrack(movingObject, "Transform");
        
        // 添加关键帧
        for (int i = 0; i < pathPoints.Count; i++)
        {
            var progress = (double)i / (pathPoints.Count - 1);
            var keyTime = TimeSpan.FromMilliseconds(duration.TotalMilliseconds * progress);
            
            var keyframe = transformTrack.CreateKeyframe(keyTime);
            keyframe.Transform = CreateTransformFromPoint(pathPoints[i]);
            
            // 设置插值类型(样条、线性、贝塞尔等)
            keyframe.InterpolationType = options?.InterpolationType ?? InterpolationType.Spline;
        }
        
        // 创建专业动画控制器
        var controller = new AnimationController(animationSet);
        
        _animationSets[name] = animationSet;
        _controllers[name] = controller;
        
        return animationSet;
    }
}

// 专业动画控制器
public class AnimationController
{
    private readonly AnimationSet _animationSet;
    private readonly Timer _updateTimer;
    private TimeSpan _currentTime;
    private bool _isPlaying;
    private double _playbackSpeed = 1.0;
    
    public event EventHandler<AnimationProgressEventArgs> ProgressChanged;
    public event EventHandler AnimationCompleted;
    
    // 标准播放控制
    public void Play()
    {
        _isPlaying = true;
        _updateTimer.Change(0, 16); // 60 FPS
    }
    
    public void Pause() => _isPlaying = false;
    public void Stop() => ResetToInitialState();
    public void SeekTo(TimeSpan time) => _animationSet.EvaluateAt(time);
    public void SetPlaybackSpeed(double speed) => _playbackSpeed = speed;
    public void PlayReverse() => _playbackSpeed = -Math.Abs(_playbackSpeed);
}

2.1.3 相机跟随动画实现

public class CameraFollowAnimation
{
    public SavedViewpointAnimation CreateFollowAnimation(
        List<PathPoint> pathPoints,
        CameraFollowSettings settings)
    {
        var viewpointAnimation = new SavedViewpointAnimation();
        viewpointAnimation.Name = "物流路径跟随";
        viewpointAnimation.Duration = settings.Duration;
        viewpointAnimation.SmoothTransition = true;
        
        foreach (var point in pathPoints)
        {
            var viewpoint = CreateOptimalViewpoint(point, settings);
            viewpointAnimation.SavedViewpoints.Add(viewpoint);
        }
        
        return viewpointAnimation;
    }
}

2.1.4 迁移时间表

  • 第2周: 动画系统架构设计和基础框架
  • 第3周: 实现AnimationSet和控制器
  • 第4周: 相机跟随和高级功能,性能测试

2.1.5 验收标准

  • 动画流畅度提升 > 200%稳定60fps
  • CPU使用率降低 > 60%
  • 支持标准动画控制(播放/暂停/停止/调速)
  • 支持相机跟随动画
  • 开发效率提升 > 400%

2.2 物流属性管理系统重构

2.1.1 新的属性管理器设计

// 新的属性管理器架构
public class LogisticsPropertyManager2026
{
    private readonly Document _document;
    private readonly ILogger _logger;
    
    public LogisticsPropertyManager2026(Document document, ILogger logger)
    {
        _document = document;
        _logger = logger;
    }
    
    // 使用2026属性集功能
    public async Task<bool> SetLogisticsCategoryAsync(
        ModelItemCollection items, 
        LogisticsCategory category)
    {
        using (var transaction = new Transaction(_document))
        {
            try
            {
                foreach (ModelItem item in items)
                {
                    await SetItemCategoryAsync(item, category);
                }
                
                transaction.Commit();
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError($"设置物流类别失败: {ex.Message}");
                return false;
            }
        }
    }
    
    private async Task SetItemCategoryAsync(ModelItem item, LogisticsCategory category)
    {
        // 利用2026属性集功能
        var propertyCategory = item.PropertyCategories
            .FindPropertyByDisplayName("物流属性", "类型");
            
        if (propertyCategory == null)
        {
            // 创建新的属性集
            await CreateLogisticsPropertySetAsync(item);
        }
        
        // 设置属性值
        propertyCategory.Value = VariantData.FromDisplayString(category.ToString());
    }
}

2.2.2 迁移时间表

  • 第2周: 设计新的属性管理架构(与动画系统并行)
  • 第3周: 实现核心属性操作功能
  • 第4周: 测试和优化,性能对比

2.2.3 验收标准

  • 属性设置成功率 > 99%
  • 批量操作性能提升 > 3倍
  • 消除COM API缓存同步问题
  • 支持最多4个属性面板显示

2.3 模型分层拆分功能重构

2.3.1 新的模型切分器设计

public class ModelSplitter2026
{
    private readonly Document _document;
    private readonly ILogger _logger;
    
    public async Task<bool> ExportModelSubsetAsync(
        ModelItemCollection itemsToExport, 
        string outputPath,
        ExportOptions options = null)
    {
        using (var transaction = new Transaction(_document))
        {
            try
            {
                // 计算需要隐藏的项目
                var itemsToHide = CalculateItemsToHide(itemsToExport);
                
                // 批量隐藏操作2026优化
                _document.Models.SetHidden(itemsToHide, true);
                
                // 2026新特性自动排除隐藏项
                await ExportWithHiddenExclusionAsync(outputPath, options);
                
                // 自动恢复可见性
                _document.Models.UnhideAll();
                
                transaction.Commit();
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError($"模型导出失败: {ex.Message}");
                return false;
            }
        }
    }
    
    private async Task ExportWithHiddenExclusionAsync(string outputPath, ExportOptions options)
    {
        // 利用2026的自动排除隐藏项功能
        var exportOptions = options ?? new ExportOptions
        {
            ExcludeHiddenItems = true,
            FileVersion = DocumentFileVersion.Navisworks2026
        };
        
        await Task.Run(() => _document.SaveFile(outputPath, exportOptions.FileVersion));
    }
}

2.3.2 崩溃问题解决方案

public class CrashPreventionManager
{
    // 内存管理优化
    public void OptimizeMemoryUsage()
    {
        // 强制垃圾回收
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
    }
    
    // 递归深度控制
    public ModelItemCollection GetItemsSafely(ModelItem root, int maxDepth = 10)
    {
        var result = new ModelItemCollection();
        GetItemsRecursive(root, result, 0, maxDepth);
        return result;
    }
    
    private void GetItemsRecursive(ModelItem item, ModelItemCollection result, 
        int currentDepth, int maxDepth)
    {
        if (currentDepth >= maxDepth) return;
        
        result.Add(item);
        foreach (ModelItem child in item.Children)
        {
            GetItemsRecursive(child, result, currentDepth + 1, maxDepth);
        }
    }
}

3. 阶段2功能增强第5-7周

3.1 高级动画功能实现

3.1.1 TimeLiner集成的4D动画

public class TimeLinedLogisticsAnimation
{
    private readonly Document _document;
    private readonly TimeLiner _timeLiner;
    
    public void CreateLogisticsSchedule(LogisticsSchedule schedule)
    {
        // 创建时间线任务
        foreach (var task in schedule.Tasks)
        {
            var timeLineTask = _timeLiner.Tasks.Add(task.Name);
            timeLineTask.StartDate = task.StartTime;
            timeLineTask.EndDate = task.EndTime;
            timeLineTask.Selection = task.ModelItems;
            
            // 关联动画
            if (task.HasAnimation)
            {
                var animation = CreatePathAnimation(task.Animation);
                timeLineTask.AttachedAnimations.Add(animation);
                
                // 设置动画触发
                timeLineTask.OnStart += () => animation.Play();
                timeLineTask.OnEnd += () => animation.Stop();
            }
        }
    }
}

3.1.2 交互式动画控制

public class InteractiveAnimationSystem
{
    private readonly Scripter _scripter;
    private readonly Dictionary<string, AnimationTrigger> _triggers;
    
    private void SetupEventHandlers()
    {
        _scripter.OnKeyPress += HandleKeyPress;
        _scripter.OnMouseClick += HandleMouseClick;
    }
    
    private void HandleKeyPress(KeyPressEventArgs e)
    {
        switch (e.Key)
        {
            case Keys.Space: ToggleAnimation("主要路径动画"); break;
            case Keys.R: RestartAnimation("主要路径动画"); break;
            case Keys.S: StopAllAnimations(); break;
        }
    }
}

3.2 碰撞检测系统升级

3.2.1 增强的碰撞检测器

public class EnhancedClashDetector2026
{
    public ClashTestResult RunLogisticsClashTest(
        ModelItemCollection pathItems,
        ModelItemCollection obstacleItems,
        ClashTestOptions options)
    {
        var clashTest = new ClashTest(_document);
        
        // 2026新功能设置优先级
        clashTest.Priority = options.Priority;
        clashTest.Description = "物流路径碰撞检测";
        
        // 配置选择集
        clashTest.SelectionA = CreateClashSelection(pathItems);
        clashTest.SelectionB = CreateClashSelection(obstacleItems);
        
        // 2026增强按属性分组
        clashTest.GroupBy = ClashGroupBy.Property;
        clashTest.GroupByProperty = "物流类型";
        
        clashTest.Run();
        
        return ProcessClashResults(clashTest.Results);
    }
}

3.3 导航地图输出功能

3.3.1 图片导出实现

public class NavigationMapExporter
{
    public async Task<bool> ExportImageAsync(string outputPath, ImageExportOptions options)
    {
        try
        {
            var doc = Application.ActiveDocument;
            var oState = ComApiBridge.State;
            
            // 获取图像导出插件选项
            var exportOptions = oState.GetIOPluginOptions("lcodpimage");
            
            // 配置导出参数
            ConfigureImageExportOptions(exportOptions, options);
            
            // 执行导出
            await Task.Run(() => oState.DriveIOPlugin("lcodpimage", outputPath, exportOptions));
            
            return File.Exists(outputPath);
        }
        catch (Exception ex)
        {
            _logger.LogError($"图片导出失败: {ex.Message}");
            return false;
        }
    }
    
    private void ConfigureImageExportOptions(ComApi.InwOaPropertyVec options, ImageExportOptions settings)
    {
        foreach (ComApi.InwOaProperty opt in options.Properties())
        {
            switch (opt.name)
            {
                case "export.image.format":
                    opt.value = settings.Format == ImageFormat.PNG ? "lcodpexpng" : "lcodpexjpeg";
                    break;
                case "export.image.width":
                    opt.value = settings.Width;
                    break;
                case "export.image.height":
                    opt.value = settings.Height;
                    break;
            }
        }
    }
}

3.3.2 视频导出实现(结合新动画系统)

public class VideoExporter
{
    public async Task<bool> ExportAnimationVideoAsync(
        string outputPath, 
        List<AnimationFrame> frames,
        VideoExportOptions options)
    {
        string tempDir = Path.Combine(Path.GetTempPath(), "NavisFrames", Guid.NewGuid().ToString());
        
        try
        {
            Directory.CreateDirectory(tempDir);
            
            // 逐帧捕获
            var framePaths = await CaptureFramesAsync(frames, tempDir);
            
            // 使用FFmpeg合成视频
            return await ComposeVideoAsync(framePaths, outputPath, options);
        }
        finally
        {
            // 清理临时文件
            if (Directory.Exists(tempDir))
            {
                Directory.Delete(tempDir, true);
            }
        }
    }
    
    private async Task<List<string>> CaptureFramesAsync(AnimationSet animationSet, string tempDir, int frameCount)
    {
        var framePaths = new List<string>();
        var duration = animationSet.Duration;
        
        for (int i = 0; i < frameCount; i++)
        {
            // 使用新动画系统的精确时间控制
            var timeRatio = (double)i / (frameCount - 1);
            var currentTime = TimeSpan.FromMilliseconds(duration.TotalMilliseconds * timeRatio);
            
            // 让动画系统更新到指定时间点
            animationSet.EvaluateAt(currentTime);
            
            // 捕获当前帧
            string framePath = Path.Combine(tempDir, $"frame_{i:D5}.png");
            await ExportCurrentFrameAsync(framePath);
            
            framePaths.Add(framePath);
            
            // 进度报告
            OnProgressChanged?.Invoke((i + 1.0) / frameCount);
        }
        
        return framePaths;
    }
    
    private async Task<bool> ComposeVideoAsync(List<string> framePaths, string outputPath, VideoExportOptions options)
    {
        var ffmpegArgs = BuildFFmpegArguments(framePaths, outputPath, options);
        
        using (var process = new Process())
        {
            process.StartInfo = new ProcessStartInfo
            {
                FileName = "ffmpeg",
                Arguments = ffmpegArgs,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                CreateNoWindow = true
            };
            
            process.Start();
            await process.WaitForExitAsync();
            
            return process.ExitCode == 0;
        }
    }
}

4. 阶段3UI现代化和新功能第8-10周

4.1 WPF界面迁移

4.1.1 主界面重构

<!-- 新的WPF主界面 -->
<UserControl x:Class="NavisworksTransport.UI.MainPanel2026">
    <Grid>
        <TabControl>
            <TabItem Header="物流属性">
                <local:LogisticsPropertyPanel />
            </TabItem>
            <TabItem Header="模型切分">
                <local:ModelSplitterPanel />
            </TabItem>
            <TabItem Header="路径规划">
                <local:PathPlanningPanel />
            </TabItem>
            <TabItem Header="导航地图">
                <local:NavigationMapPanel />
            </TabItem>
        </TabControl>
    </Grid>
</UserControl>

4.1.2 可停靠面板实现

[Plugin("NavisworksTransport.DockablePane2026", "YourDeveloperID")]
public class LogisticsDockablePane : DockPanePlugin
{
    public override Control CreateControlPane()
    {
        // 使用ElementHost托管WPF控件
        var elementHost = new ElementHost
        {
            Dock = DockStyle.Fill,
            Child = new MainPanel2026()
        };
        
        return elementHost;
    }
    
    public override void DestroyControlPane(Control pane)
    {
        if (pane is ElementHost elementHost)
        {
            elementHost.Child = null;
            elementHost.Dispose();
        }
    }
}

4.2 DELMIA集成准备

4.2.1 数据导出格式

public class DelmiaDataExporter
{
    public async Task<bool> ExportLogisticsDataAsync(string outputPath, LogisticsData data)
    {
        var exportData = new
        {
            Metadata = new
            {
                ExportTime = DateTime.UtcNow,
                NavisworksVersion = "2026",
                ProjectName = data.ProjectName
            },
            Paths = data.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 }),
                Properties = p.Properties
            }),
            Objects = data.Objects.Select(o => new
            {
                Id = o.Id,
                Name = o.Name,
                Category = o.Category,
                BoundingBox = o.BoundingBox,
                Transform = o.Transform,
                Properties = o.Properties
            })
        };
        
        var json = JsonSerializer.Serialize(exportData, new JsonSerializerOptions
        {
            WriteIndented = true,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });
        
        await File.WriteAllTextAsync(outputPath, json);
        return true;
    }
}

5. 测试和验证第11-12周

5.1 功能测试

  • 动画系统功能测试(新增重点)
    • 基础动画播放控制测试
    • 相机跟随动画测试
    • TimeLiner集成测试
    • 交互式动画控制测试
  • 物流属性管理功能测试
  • 模型分层拆分功能测试
  • 碰撞检测功能测试
  • 导航地图输出功能测试
  • UI界面交互测试

5.2 性能测试

  • 动画系统性能测试(新增重点)
    • 动画流畅度测试目标稳定60fps
    • CPU使用率对比测试目标降低60%
    • 内存使用稳定性测试
    • 长时间动画播放稳定性测试
  • 大型模型加载性能测试
  • 批量属性操作性能测试
  • 内存使用情况测试
  • 崩溃稳定性测试

5.3 兼容性测试

  • 不同版本NWD文件兼容性
  • 多种模型格式支持测试
  • Windows不同版本兼容性测试

6. 部署和发布第13周

6.1 打包和分发

  • 创建安装程序
  • 准备用户文档
  • 创建迁移指南

6.2 用户培训

  • 准备培训材料
  • 录制功能演示视频
  • 编写用户手册

7. 风险控制措施

7.1 技术风险

风险 概率 影响 应对措施
API兼容性问题 建立兼容性测试套件,准备降级方案
性能回归 持续性能监控,基准测试对比
动画系统迁移复杂度 渐进式迁移,保留手动变换作为备用
动画流畅度不达预期 充分的动画场景测试,性能调优
新功能缺陷 充分测试,分阶段发布

7.2 项目风险

风险 概率 影响 应对措施
时间延期 优先级管理,关键路径监控
资源不足 提前资源规划,外部支持
需求变更 变更控制流程,影响评估

8. 成功标准

8.1 技术指标

  • 代码复杂度降低 > 30%
  • 整体性能提升 > 20%
  • 动画系统性能提升 > 200%(新增关键指标)
  • 动画开发效率提升 > 400%(新增关键指标)
  • 崩溃率降低 > 90%
  • 新功能覆盖率 > 95%

8.2 业务指标

  • 用户满意度 > 90%
  • 功能完整性 > 98%
  • 文档完整性 > 95%
  • 培训效果 > 85%

9. 后续维护计划

9.1 短期维护3个月

  • 监控系统稳定性
  • 收集用户反馈
  • 修复发现的问题

9.2 长期维护1年

  • 功能增强和优化
  • 新版本API适配
  • 性能持续改进

这个实施计划确保了迁移过程的有序进行同时最大化了2026版本API的优势为项目的长期发展奠定了坚实基础。