实现了部件动画

This commit is contained in:
tian 2025-06-21 17:38:48 +08:00
parent e626dc5777
commit 6e21a7dbf8
3 changed files with 57 additions and 94 deletions

View File

@ -2069,10 +2069,10 @@ namespace NavisworksTransport
/// <param name="parent">父容器</param>
private void CreateAnimationControls(GroupBox parent)
{
// 车辆选择部分
// 部件选择部分
Label vehicleInstructionLabel = new Label
{
Text = "请在选择树中选择车辆模型",
Text = "请在选择树中选择部件",
Location = new Point(20, 25),
Size = new Size(200, 20),
Font = new Font("微软雅黑", 8),
@ -2081,7 +2081,7 @@ namespace NavisworksTransport
Button getVehicleButton = new Button
{
Text = "获取选中车辆",
Text = "获取选中部件",
Location = new Point(230, 22),
Size = new Size(90, 27),
Font = new Font("微软雅黑", 8),
@ -2204,8 +2204,8 @@ namespace NavisworksTransport
ForeColor = System.Drawing.Color.Gray
};
// 存储选中的车辆
ModelItem selectedVehicle = null;
// 存储选中的部件
ModelItem selectedComponent = null;
// 车辆选择事件处理
getVehicleButton.Click += (sender, e) =>
@ -2217,20 +2217,20 @@ namespace NavisworksTransport
if (selectedItems.Count == 0)
{
MessageBox.Show("请先在选择树中选择一个车辆模型", "提示",
MessageBox.Show("请先在选择树中选择一个部件", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (selectedItems.Count > 1)
{
MessageBox.Show("请只选择一个车辆模型", "提示",
MessageBox.Show("请只选择一个部件", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
selectedVehicle = selectedItems.First;
vehicleStatusLabel.Text = $"状态: 已选择 {selectedVehicle.DisplayName}";
selectedComponent = selectedItems.First;
vehicleStatusLabel.Text = $"状态: 已选择 {selectedComponent.DisplayName}";
vehicleStatusLabel.ForeColor = System.Drawing.Color.Green;
// 检查是否可以启用生成动画按钮
@ -2239,7 +2239,7 @@ namespace NavisworksTransport
createAnimationButton.Enabled = true;
}
}, "获取选中车辆");
}, "获取选中部件");
};
// 路径选择事件处理
@ -2255,7 +2255,7 @@ namespace NavisworksTransport
pathInfoLabel.Text = $"点数: {selectedPath.Points?.Count ?? 0}";
// 检查是否可以启用生成动画按钮
if (selectedVehicle != null)
if (selectedComponent != null)
{
createAnimationButton.Enabled = true;
}
@ -2322,9 +2322,9 @@ namespace NavisworksTransport
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (selectedVehicle == null)
if (selectedComponent == null)
{
MessageBox.Show("请先选择车辆模型", "提示",
MessageBox.Show("请先选择部件模型", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
@ -2372,11 +2372,11 @@ namespace NavisworksTransport
double duration = (double)durationNumeric.Value;
// 使用简化的动画设置方法
bool success = _animationManager.SetupSimpleAnimation(selectedVehicle, pathPoints, duration);
bool success = _animationManager.SetupSimpleAnimation(selectedComponent, pathPoints, duration);
if (!success)
{
MessageBox.Show("动画生成失败,请检查车辆和路径设置", "错误",
MessageBox.Show("动画生成失败,请检查部件和路径设置", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
@ -2389,7 +2389,7 @@ namespace NavisworksTransport
resetAnimationButton.Enabled = true;
createAnimationButton.Enabled = false;
MessageBox.Show($"动画生成成功!\n车辆: {selectedVehicle.DisplayName}\n路径: {selectedPath.Name}\n路径点: {pathPoints.Count}个\n时长: {duration}秒",
MessageBox.Show($"动画生成成功!\n部件: {selectedComponent.DisplayName}\n路径: {selectedPath.Name}\n路径点: {pathPoints.Count}个\n时长: {duration}秒",
"生成成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}, "生成动画");
};

View File

@ -20,7 +20,8 @@ namespace NavisworksTransport
private double _animationDuration = 10.0; // 动画总时长(秒)
private DateTime _animationStartTime;
private Transform3D _originalTransform;
private Point3D _originalCenter; // 存储车辆的原始中心位置
private Point3D _originalCenter; // 存储部件的原始中心位置
private Point3D _currentPosition; // 存储部件的当前位置
// 动画完成事件
public event EventHandler AnimationCompleted;
@ -58,26 +59,6 @@ namespace NavisworksTransport
var originalBoundingBox = animatedObject.BoundingBox();
_originalCenter = originalBoundingBox.Center;
// 🔍 添加调试:检查车辆的变换矩阵
LogManager.Info($"=== 坐标系统调试信息 ===");
LogManager.Info($"车辆模型名称: {_animatedObject.DisplayName}");
LogManager.Info($"车辆变换矩阵: {_animatedObject.Transform}");
LogManager.Info($"车辆包围盒中心: ({_originalCenter.X:F2},{_originalCenter.Y:F2},{_originalCenter.Z:F2})");
// 检查顶级模型组(场馆和车辆)
var doc = NavisApplication.ActiveDocument;
var rootItems = doc.Models.RootItemDescendantsAndSelf.Where(m => m.Parent == null).ToList();
LogManager.Info($"文档中的顶级模型组数量: {rootItems.Count}");
foreach (var rootModel in rootItems)
{
var modelCenter = rootModel.HasGeometry ? rootModel.BoundingBox().Center : new Point3D(0, 0, 0);
LogManager.Info($" 顶级模型: {rootModel.DisplayName}");
LogManager.Info($" 变换矩阵: {rootModel.Transform}");
LogManager.Info($" 有几何体: {rootModel.HasGeometry}");
LogManager.Info($" 包围盒中心: ({modelCenter.X:F2},{modelCenter.Y:F2},{modelCenter.Z:F2})");
LogManager.Info($" 子项数量: {rootModel.Children.Count()}");
}
// 关键修复:将车辆立即移动到路径起点
// 这样动画就从路径起点开始,而不是从车辆当前位置开始
MoveVehicleToPathStart();
@ -115,7 +96,7 @@ namespace NavisworksTransport
var doc = NavisApplication.ActiveDocument;
var modelItems = new ModelItemCollection { _animatedObject };
// 计算从车辆原始中心到路径起点的偏移
// 计算从部件原始中心到路径起点的偏移
var startOffset = new Vector3D(
_pathPoints[0].X - _originalCenter.X,
_pathPoints[0].Y - _originalCenter.Y,
@ -126,11 +107,14 @@ namespace NavisworksTransport
var startTransform = Transform3D.CreateTranslation(startOffset);
doc.Models.OverridePermanentTransform(modelItems, startTransform, false);
LogManager.Info($"车辆已移动到路径起点,偏移: ({startOffset.X:F2},{startOffset.Y:F2},{startOffset.Z:F2})");
// 更新当前位置为路径起点
_currentPosition = _pathPoints[0];
LogManager.Info($"部件已移动到路径起点,偏移: ({startOffset.X:F2},{startOffset.Y:F2},{startOffset.Z:F2})");
}
catch (Exception ex)
{
LogManager.Error($"移动车辆到路径起点失败: {ex.Message}");
LogManager.Error($"移动部件到路径起点失败: {ex.Message}");
}
}
@ -211,6 +195,9 @@ namespace NavisworksTransport
var identityTransform = Transform3D.CreateTranslation(new Vector3D(0, 0, 0));
doc.Models.OverridePermanentTransform(modelItems, identityTransform, true);
// 重置当前位置为原始中心
_currentPosition = _originalCenter;
// 清除碰撞高亮
doc.Models.ResetAllTemporaryMaterials();
}
@ -353,58 +340,34 @@ namespace NavisworksTransport
var doc = NavisApplication.ActiveDocument;
var modelItems = new ModelItemCollection { _animatedObject };
// 关键修复:基于路径起点计算偏移,而不是基于车辆原始位置
// 因为车辆已经在SetupAnimation时移动到了路径起点
var offsetFromPathStart = new Vector3D(
newPosition.X - _pathPoints[0].X, // 相对于路径起点的偏移
newPosition.Y - _pathPoints[0].Y,
newPosition.Z - _pathPoints[0].Z
// 正确的增量变换:计算从当前位置到新位置的偏移
var incrementalOffset = new Vector3D(
newPosition.X - _currentPosition.X,
newPosition.Y - _currentPosition.Y,
newPosition.Z - _currentPosition.Z
);
// 总偏移 = 原始到起点的偏移 + 起点到当前位置的偏移
var totalOffset = new Vector3D(
(_pathPoints[0].X - _originalCenter.X) + offsetFromPathStart.X,
(_pathPoints[0].Y - _originalCenter.Y) + offsetFromPathStart.Y,
(_pathPoints[0].Z - _originalCenter.Z) + offsetFromPathStart.Z
);
// 创建增量变换
var incrementalTransform = Transform3D.CreateTranslation(incrementalOffset);
// 🔧 动态获取车辆的真实缩放系数
var vehicleScaleFactor = GetVehicleScaleFactor();
// 应用增量变换(不重置之前的变换)
doc.Models.OverridePermanentTransform(modelItems, incrementalTransform, false);
// 🚨 关键修复:如果车辆有缩放,需要将偏移量除以缩放系数
// 因为OverridePermanentTransform在世界坐标系中工作但缩放后的车辆会放大变换
Vector3D adjustedOffset;
if (vehicleScaleFactor > 1.0)
{
adjustedOffset = new Vector3D(
totalOffset.X / vehicleScaleFactor,
totalOffset.Y / vehicleScaleFactor,
totalOffset.Z / vehicleScaleFactor
);
LogManager.Debug($"车辆有缩放({vehicleScaleFactor:F2}),调整偏移量");
}
else
{
adjustedOffset = totalOffset;
LogManager.Debug($"车辆无缩放,直接使用原始偏移量");
}
LogManager.Debug($"部件位置更新:从({_currentPosition.X:F2},{_currentPosition.Y:F2},{_currentPosition.Z:F2})到({newPosition.X:F2},{newPosition.Y:F2},{newPosition.Z:F2}),增量偏移({incrementalOffset.X:F2},{incrementalOffset.Y:F2},{incrementalOffset.Z:F2})");
// 创建基于调整后偏移的变换
var transform = Transform3D.CreateTranslation(adjustedOffset);
// 应用变换
doc.Models.OverridePermanentTransform(modelItems, transform, false);
LogManager.Debug($"车辆位置更新:目标位置({newPosition.X:F2},{newPosition.Y:F2},{newPosition.Z:F2}),原始偏移({totalOffset.X:F2},{totalOffset.Y:F2},{totalOffset.Z:F2}),调整后偏移({adjustedOffset.X:F2},{adjustedOffset.Y:F2},{adjustedOffset.Z:F2})");
// 更新当前位置
_currentPosition = newPosition;
}
catch (Exception ex)
{
LogManager.Error($"更新车辆位置失败: {ex.Message}");
LogManager.Error($"更新部件位置失败: {ex.Message}");
}
}
/// <summary>
/// 从车辆变换矩阵中获取真实的缩放系数
/// 注意:此方法已废弃但保留,用于车辆模型的缩放处理。
/// 现在使用场馆部件进行动画,通常不需要复杂的缩放计算。
/// </summary>
private double GetVehicleScaleFactor()
{
@ -610,18 +573,18 @@ namespace NavisworksTransport
}
/// <summary>
/// 简化的动画设置方法,支持直接传入车辆和路径
/// 简化的动画设置方法,支持直接传入部件和路径
/// </summary>
/// <param name="vehicle">车辆模型</param>
/// <param name="component">部件模型</param>
/// <param name="pathPoints">路径点列表</param>
/// <param name="durationSeconds">动画持续时间(秒)</param>
public bool SetupSimpleAnimation(ModelItem vehicle, List<Point3D> pathPoints, double durationSeconds = 10.0)
public bool SetupSimpleAnimation(ModelItem component, List<Point3D> pathPoints, double durationSeconds = 10.0)
{
try
{
if (vehicle == null)
if (component == null)
{
LogManager.Error("车辆模型不能为空");
LogManager.Error("部件模型不能为空");
return false;
}
@ -632,9 +595,9 @@ namespace NavisworksTransport
}
// 使用现有的SetupAnimation方法
SetupAnimation(vehicle, pathPoints, durationSeconds);
SetupAnimation(component, pathPoints, durationSeconds);
LogManager.Info($"简化动画设置成功:车辆={vehicle.DisplayName}, 路径点数={pathPoints.Count}, 时长={durationSeconds}秒");
LogManager.Info($"简化动画设置成功:部件={component.DisplayName}, 路径点数={pathPoints.Count}, 时长={durationSeconds}秒");
return true;
}
catch (Exception ex)
@ -645,10 +608,10 @@ namespace NavisworksTransport
}
/// <summary>
/// 获取当前选中的车辆模型(简化版本)
/// 获取当前选中的部件模型(简化版本)
/// </summary>
/// <returns>选中的车辆模型如果没有选中或选中多个则返回null</returns>
public static ModelItem GetSelectedVehicle()
/// <returns>选中的部件模型如果没有选中或选中多个则返回null</returns>
public static ModelItem GetSelectedComponent()
{
try
{
@ -660,12 +623,12 @@ namespace NavisworksTransport
var item = selectedItems.First;
if (item.HasGeometry)
{
LogManager.Info($"已获取选中车辆: {item.DisplayName}");
LogManager.Info($"已获取选中部件: {item.DisplayName}");
return item;
}
else
{
LogManager.Warning("选中的项目没有几何体,可能不适合作为车辆");
LogManager.Warning("选中的项目没有几何体,可能不适合用于动画");
return null;
}
}
@ -676,13 +639,13 @@ namespace NavisworksTransport
}
else
{
LogManager.Info($"选中了{selectedItems.Count}个项目,请只选择一个车辆");
LogManager.Info($"选中了{selectedItems.Count}个项目,请只选择一个部件");
return null;
}
}
catch (Exception ex)
{
LogManager.Error($"获取选中车辆失败: {ex.Message}");
LogManager.Error($"获取选中部件失败: {ex.Message}");
return null;
}
}

View File

@ -105,7 +105,7 @@ namespace NavisworksTransport
// 绘制连接线段(作为圆柱体)
if (_circleMarkers.Count > 1)
{
graphics.Color(Color.FromByteRGB(255, 255, 0), 1.0); // 高亮黄色
graphics.Color(Color.FromByteRGB(0, 0, 0), 1.0); // 黑色连线
// 定义连线的物理半径例如20厘米
double lineRadiusInMeters = 0.2;