将时标导出到TimeLiner任务
This commit is contained in:
parent
57751e85fa
commit
08b4ecc5d5
@ -2,7 +2,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Autodesk.Navisworks.Api;
|
||||
using Autodesk.Navisworks.Api.Timeliner;
|
||||
using NavisworksTransport.Core.Models;
|
||||
using NavisworksTransport.Core.Animation;
|
||||
using NavisworksTransport.Utils;
|
||||
|
||||
namespace NavisworksTransport.Core.Services
|
||||
@ -13,20 +15,28 @@ namespace NavisworksTransport.Core.Services
|
||||
public class TimeTagTimeLinerIntegration
|
||||
{
|
||||
private readonly TimeTagService _timeTagService;
|
||||
private readonly TimeLinerIntegrationManager _timeLinerManager;
|
||||
|
||||
public TimeTagTimeLinerIntegration(TimeTagService timeTagService)
|
||||
{
|
||||
_timeTagService = timeTagService ?? throw new ArgumentNullException(nameof(timeTagService));
|
||||
_timeLinerManager = new TimeLinerIntegrationManager();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TimeLiner 是否可用
|
||||
/// </summary>
|
||||
public bool IsTimeLinerAvailable => _timeLinerManager?.IsTimeLinerAvailable ?? false;
|
||||
|
||||
/// <summary>
|
||||
/// 将时标配置导入为TimeLiner仿真任务
|
||||
/// </summary>
|
||||
/// <param name="profile">时标配置</param>
|
||||
/// <param name="route">路径</param>
|
||||
/// <param name="movingObject">运输物体(可选)</param>
|
||||
/// <param name="taskName">任务名称</param>
|
||||
/// <returns>是否成功</returns>
|
||||
public bool ImportToTimeLiner(TimeTagProfile profile, PathRoute route, string taskName = null)
|
||||
public bool ImportToTimeLiner(TimeTagProfile profile, PathRoute route, ModelItem movingObject = null, string taskName = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -36,17 +46,44 @@ namespace NavisworksTransport.Core.Services
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsTimeLinerAvailable)
|
||||
{
|
||||
LogManager.Warning("TimeLiner 不可用,无法导入任务");
|
||||
return false;
|
||||
}
|
||||
|
||||
string name = taskName ?? $"{route.Name} - {profile.Name}";
|
||||
LogManager.Info($"开始导入TimeLiner: {name}");
|
||||
|
||||
// 创建仿真任务数据
|
||||
// 创建仿真数据
|
||||
var simulationData = CreateSimulationData(profile, route);
|
||||
|
||||
LogManager.Info($"TimeLiner数据已准备: {name}, 总时间 {profile.TotalTime:F1}s");
|
||||
|
||||
// 注意:实际的TimeLiner导入需要通过COM API实现
|
||||
// 这里返回成功表示数据已准备好
|
||||
return true;
|
||||
// 计算持续时间
|
||||
var duration = TimeSpan.FromSeconds(profile.TotalTime);
|
||||
|
||||
// 创建 TimeLiner 任务
|
||||
string taskId = null;
|
||||
if (movingObject != null)
|
||||
{
|
||||
// 如果有选中物体,创建完整任务
|
||||
taskId = _timeLinerManager.CreateTransportTask(name, simulationData.Waypoints.Select(w => w.Position).ToList(), duration, movingObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有选中物体,创建简单任务(仅信息展示)
|
||||
taskId = CreateSimpleTimelinerTask(name, profile, route, duration);
|
||||
}
|
||||
|
||||
if (taskId != null)
|
||||
{
|
||||
LogManager.Info($"✓ TimeLiner 任务创建成功: {name}, 任务ID: {taskId}");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogManager.Error("TimeLiner 任务创建失败");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -55,6 +92,35 @@ namespace NavisworksTransport.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建简单的 TimeLiner 任务(无物体关联,仅信息展示)
|
||||
/// </summary>
|
||||
private string CreateSimpleTimelinerTask(string taskName, TimeTagProfile profile, PathRoute route, TimeSpan duration)
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = Application.ActiveDocument;
|
||||
var timeliner = doc?.GetTimeliner();
|
||||
if (timeliner == null) return null;
|
||||
|
||||
var task = new TimelinerTask();
|
||||
task.DisplayName = $"运输任务:{taskName}";
|
||||
// Comments 属性是只读的,使用 DisplayName 包含更多信息
|
||||
task.DisplayName = $"运输任务:{taskName} ({profile.TotalTime:F1}s, {route.TotalLength:F1}m)";
|
||||
|
||||
// 添加到 TimeLiner
|
||||
timeliner.TaskAddCopy(task);
|
||||
|
||||
LogManager.Info($"✓ 简单 TimeLiner 任务创建成功: {taskName}");
|
||||
return Guid.NewGuid().ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"创建简单 TimeLiner 任务失败: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建仿真数据 - 用于动画系统
|
||||
/// </summary>
|
||||
@ -76,7 +142,6 @@ namespace NavisworksTransport.Core.Services
|
||||
var events = profile.Events.OrderBy(e => e.Distance).ToList();
|
||||
|
||||
// 生成仿真路径点
|
||||
double currentTime = 0;
|
||||
for (int i = 0; i < events.Count; i++)
|
||||
{
|
||||
var evt = events[i];
|
||||
@ -95,8 +160,6 @@ namespace NavisworksTransport.Core.Services
|
||||
ActionTime = evt.ActionTime
|
||||
});
|
||||
}
|
||||
|
||||
currentTime = evt.CumulativeTime + evt.WaitTime + evt.ActionTime;
|
||||
}
|
||||
|
||||
// 计算每段的实际速度
|
||||
@ -122,7 +185,6 @@ namespace NavisworksTransport.Core.Services
|
||||
|
||||
if (accumulated + segLength >= distance)
|
||||
{
|
||||
// 在此段内插值
|
||||
double t = (distance - accumulated) / segLength;
|
||||
return InterpolatePoint(p1, p2, t);
|
||||
}
|
||||
@ -130,13 +192,9 @@ namespace NavisworksTransport.Core.Services
|
||||
accumulated += segLength;
|
||||
}
|
||||
|
||||
// 返回最后一个点
|
||||
return route.Points[route.Points.Count - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算两点距离
|
||||
/// </summary>
|
||||
private double CalculateDistance(PathPoint p1, PathPoint p2)
|
||||
{
|
||||
double dx = p2.Position.X - p1.Position.X;
|
||||
@ -145,9 +203,6 @@ namespace NavisworksTransport.Core.Services
|
||||
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 线性插值两个路径点
|
||||
/// </summary>
|
||||
private PathPoint InterpolatePoint(PathPoint p1, PathPoint p2, double t)
|
||||
{
|
||||
return new PathPoint
|
||||
@ -161,9 +216,6 @@ namespace NavisworksTransport.Core.Services
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算每段的速度
|
||||
/// </summary>
|
||||
private void CalculateSegmentSpeeds(SimulationData data, TimeTagProfile profile)
|
||||
{
|
||||
if (data.Waypoints.Count < 2) return;
|
||||
@ -218,9 +270,6 @@ namespace NavisworksTransport.Core.Services
|
||||
return ExportSimulationDataToJson(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将仿真数据转换为JSON
|
||||
/// </summary>
|
||||
private string ExportSimulationDataToJson(SimulationData data)
|
||||
{
|
||||
var sb = new System.Text.StringBuilder();
|
||||
@ -256,9 +305,6 @@ namespace NavisworksTransport.Core.Services
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转义JSON字符串
|
||||
/// </summary>
|
||||
private string EscapeJson(string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str)) return "";
|
||||
|
||||
@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.Win32;
|
||||
using Autodesk.Navisworks.Api;
|
||||
using NavisworksTransport.Core.Models;
|
||||
using NavisworksTransport.Core.Services;
|
||||
|
||||
@ -17,6 +18,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
private readonly TimeTagService _timeTagService;
|
||||
private readonly TimeTagExporter _exporter;
|
||||
private readonly TimeTagTimeLinerIntegration _timeLinerIntegration;
|
||||
private PathRoute _currentRoute;
|
||||
private TimeTagProfile _currentProfile;
|
||||
private TimeTagEvent _selectedEvent;
|
||||
@ -206,6 +208,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
public ICommand DeleteProfileCommand { get; }
|
||||
public ICommand RefreshCommand { get; }
|
||||
public ICommand ExportCommand { get; }
|
||||
public ICommand ImportToTimeLinerCommand { get; }
|
||||
public ICommand InsertEventCommand { get; }
|
||||
public ICommand DeleteEventCommand { get; }
|
||||
|
||||
@ -215,6 +218,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
_timeTagService = timeTagService ?? throw new ArgumentNullException(nameof(timeTagService));
|
||||
_exporter = new TimeTagExporter();
|
||||
_timeLinerIntegration = new TimeTagTimeLinerIntegration(timeTagService);
|
||||
_currentRoute = route;
|
||||
|
||||
Profiles = new ObservableCollection<TimeTagProfile>();
|
||||
@ -224,6 +228,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
DeleteProfileCommand = new RelayCommand(() => DeleteProfile(), () => CurrentProfile != null);
|
||||
RefreshCommand = new RelayCommand(() => RefreshProfiles());
|
||||
ExportCommand = new RelayCommand(() => Export(), () => CurrentProfile != null);
|
||||
ImportToTimeLinerCommand = new RelayCommand(() => ImportToTimeLiner(), () => CurrentProfile != null);
|
||||
InsertEventCommand = new RelayCommand(() => InsertEvent(), () => CurrentProfile != null && _currentRoute != null);
|
||||
DeleteEventCommand = new RelayCommand(() => DeleteEvent(), () => SelectedEvent != null);
|
||||
|
||||
@ -518,6 +523,73 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入到 TimeLiner
|
||||
/// </summary>
|
||||
private void ImportToTimeLiner()
|
||||
{
|
||||
if (CurrentProfile == null || _currentRoute == null) return;
|
||||
|
||||
// 检查 TimeLiner 是否可用
|
||||
if (!_timeLinerIntegration.IsTimeLinerAvailable)
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
"TimeLiner 不可用。请确保 Navisworks TimeLiner 插件已加载。",
|
||||
"TimeLiner 不可用",
|
||||
System.Windows.MessageBoxButton.OK,
|
||||
System.Windows.MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取当前选中的模型元素(可选)
|
||||
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
|
||||
var selectedItems = doc?.CurrentSelection?.SelectedItems;
|
||||
ModelItem movingObject = null;
|
||||
if (selectedItems != null && selectedItems.Count > 0)
|
||||
{
|
||||
movingObject = selectedItems.First();
|
||||
}
|
||||
|
||||
var result = System.Windows.MessageBox.Show(
|
||||
movingObject != null
|
||||
? $"将时标配置 \"{CurrentProfile.Name}\" 导入到 TimeLiner 吗?\n\n已选中物体: {movingObject.DisplayName}\n总时间: {CurrentProfile.TotalTime:F1}秒\n事件数: {CurrentProfile.Events?.Count ?? 0}"
|
||||
: $"将时标配置 \"{CurrentProfile.Name}\" 导入到 TimeLiner 吗?\n\n未选中运输物体,将创建信息任务(无动画)。\n总时间: {CurrentProfile.TotalTime:F1}秒\n事件数: {CurrentProfile.Events?.Count ?? 0}",
|
||||
"导入到 TimeLiner",
|
||||
System.Windows.MessageBoxButton.YesNo,
|
||||
System.Windows.MessageBoxImage.Question);
|
||||
|
||||
if (result != System.Windows.MessageBoxResult.Yes) return;
|
||||
|
||||
try
|
||||
{
|
||||
bool success = _timeLinerIntegration.ImportToTimeLiner(CurrentProfile, _currentRoute, movingObject);
|
||||
|
||||
if (success)
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
"时标配置已成功导入到 TimeLiner!\n\n请在 Navisworks 的 TimeLiner 窗口中查看任务。",
|
||||
"导入成功",
|
||||
System.Windows.MessageBoxButton.OK,
|
||||
System.Windows.MessageBoxImage.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Windows.MessageBox.Show(
|
||||
"导入失败,请查看日志了解详情。",
|
||||
"导入失败",
|
||||
System.Windows.MessageBoxButton.OK,
|
||||
System.Windows.MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"导入 TimeLiner 失败: {ex.Message}");
|
||||
System.Windows.MessageBox.Show($"导入失败: {ex.Message}", "错误",
|
||||
System.Windows.MessageBoxButton.OK,
|
||||
System.Windows.MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
#region INotifyPropertyChanged
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
<Button Content="删除配置" Margin="5,0,0,0" Padding="15,3" Command="{Binding DeleteProfileCommand}"/>
|
||||
<Separator Margin="20,0" Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}"/>
|
||||
<Button Content="导出" Padding="15,3" Command="{Binding ExportCommand}"/>
|
||||
<Button Content="导入到TimeLiner" Padding="15,3" Margin="10,0,0,0" Command="{Binding ImportToTimeLinerCommand}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 主内容区 -->
|
||||
|
||||
Loading…
Reference in New Issue
Block a user